LMMC
Lamina Mathematic core
载入中...
搜索中...
未找到
fft_radix4.c
浏览该文件的文档.
1#include <math.h>
2#include "internal.h"
3#include "lmmc/fft.h"
5
6
7static size_t lmmc_reverse_base4(size_t value, unsigned digits) {
8 size_t reversed = 0;
9 unsigned i = 0;
10
11 for (i = 0; i < digits; ++i) {
12 reversed = (reversed << 2) | (value & (size_t)3);
13 value >>= 2;
14 }
15 return reversed;
16}
17
18lmmc_status_t lmmc_fft_radix4_next_size(size_t n, size_t* out_nfft) {
19 size_t nfft = 1;
20
21 if (out_nfft == NULL || n == 0) {
23 }
24
25 while (nfft < n) {
26 if (nfft > ((size_t)-1) / (size_t)4) {
28 }
29 nfft *= (size_t)4;
30 }
31
32 *out_nfft = nfft;
33 return LMMC_STATUS_OK;
34}
35
37static void fft_radix4_butterfly(
38 lmmc_real_t* real, lmmc_real_t* imag, size_t quarter,
39 double angle, int inverse)
40{
41 lmmc_real_t ar[4], ai[4];
42 size_t k;
43 ar[0] = real[0];
44 ai[0] = imag[0];
45 for (k = 1; k < 4; ++k) {
46 const double phase = angle * (double)k;
47 const double c = cos(phase);
48 const double s = sin(phase);
49 ar[k] = real[k * quarter] * c - imag[k * quarter] * s;
50 ai[k] = real[k * quarter] * s + imag[k * quarter] * c;
51 }
52
53 real[0] = ((ar[0] + ar[1]) + ar[2]) + ar[3];
54 imag[0] = ((ai[0] + ai[1]) + ai[2]) + ai[3];
55 real[2 * quarter] = ((ar[0] - ar[1]) + ar[2]) - ar[3];
56 imag[2 * quarter] = ((ai[0] - ai[1]) + ai[2]) - ai[3];
57 if (!inverse) {
58 real[quarter] = ((ar[0] + ai[1]) - ar[2]) - ai[3];
59 imag[quarter] = ((ai[0] - ar[1]) - ai[2]) + ar[3];
60 real[3 * quarter] = ((ar[0] - ai[1]) - ar[2]) + ai[3];
61 imag[3 * quarter] = ((ai[0] + ar[1]) - ai[2]) - ar[3];
62 } else {
63 real[quarter] = ((ar[0] - ai[1]) - ar[2]) + ai[3];
64 imag[quarter] = ((ai[0] + ar[1]) - ai[2]) - ar[3];
65 real[3 * quarter] = ((ar[0] + ai[1]) - ar[2]) - ai[3];
66 imag[3 * quarter] = ((ai[0] - ar[1]) - ai[2]) + ar[3];
67 }
68}
69
70static void fft_radix4_stage(
71 lmmc_real_t* real, lmmc_real_t* imag, size_t n,
72 size_t group, int inverse)
73{
74 const size_t quarter = group / 4;
75 const double step = (inverse ? 2.0 : -2.0) * LMMC_PI / (double)group;
76 size_t i, j;
77 for (i = 0; i < n; i += group) {
78 for (j = 0; j < quarter; ++j) {
79 fft_radix4_butterfly(real + i + j, imag + i + j,
80 quarter, step * (double)j, inverse);
81 }
82 }
83}
84
85static lmmc_status_t lmmc_fft_radix4_core(
86 lmmc_real_t* real, lmmc_real_t* imag, size_t n, int inverse)
87{
88 unsigned digits = 0;
89 size_t i, len;
90 if (!lmmc_is_power_of_four(n, &digits)) {
92 }
93 if (n <= 1) { return LMMC_STATUS_OK; }
94 for (i = 0; i < n; ++i) {
95 const size_t r = lmmc_reverse_base4(i, digits);
96 if (r > i) {
97 lmmc_swap(&real[i], &real[r]);
98 lmmc_swap(&imag[i], &imag[r]);
99 }
100 }
101 for (len = 4; len <= n; len *= 4) {
102 fft_radix4_stage(real, imag, n, len, inverse);
103 if (len == n) { break; }
104 }
105 if (inverse) {
106 const double scale = 1.0 / (double)n;
107 for (i = 0; i < n; ++i) {
108 real[i] *= scale;
109 imag[i] *= scale;
110 }
111 }
112 return LMMC_STATUS_OK;
113}
114
115lmmc_status_t lmmc_fft_radix4(lmmc_real_t* real, lmmc_real_t* imag, size_t n, int inverse) {
116 unsigned digits = 0;
117 lmmc_storage_envelope_t real_envelope;
118 lmmc_storage_envelope_t imag_envelope;
119
120 if (real == NULL || imag == NULL) {
122 }
123
124 if (!lmmc_is_power_of_four(n, &digits) ||
125 !lmmc_storage_envelope_checked(
126 real, 1, n, n, sizeof(lmmc_real_t), &real_envelope) ||
127 !lmmc_storage_envelope_checked(
128 imag, 1, n, n, sizeof(lmmc_real_t), &imag_envelope) ||
129 lmmc_storage_envelopes_overlap(&real_envelope, &imag_envelope)) {
131 }
132
133 return lmmc_fft_radix4_core(real, imag, n, inverse ? 1 : 0);
134}
135
137 return lmmc_fft_radix4(real, imag, n, 0);
138}
139
141 return lmmc_fft_radix4(real, imag, n, 1);
142}
double lmmc_real_t
Public and internal LMMC real type.
lmmc_status_t lmmc_fft_radix4(lmmc_real_t *real, lmmc_real_t *imag, size_t n, int inverse)
对长度为 4 的幂的复数序列执行就地 radix-4 FFT。
lmmc_status_t lmmc_fft_radix4_inverse(lmmc_real_t *real, lmmc_real_t *imag, size_t n)
等价于 lmmc_fft_radix4(real, imag, n, 1) .
lmmc_status_t lmmc_fft_radix4_next_size(size_t n, size_t *out_nfft)
计算不小于 n 的最小 4 的幂,用于 FFT 长度对齐。
lmmc_status_t lmmc_fft_radix4_forward(lmmc_real_t *real, lmmc_real_t *imag, size_t n)
等价于 lmmc_fft_radix4(real, imag, n, 0) .
LMMC 内部使用的公共工具(仅源文件可见).
#define LMMC_PI
常量.
lmmc_status_t
LMMC 库统一返回的状态码.
@ LMMC_STATUS_OK
@ LMMC_STATUS_INVALID_ARGUMENT