7static size_t lmmc_reverse_base4(
size_t value,
unsigned digits) {
11 for (i = 0; i < digits; ++i) {
12 reversed = (reversed << 2) | (value & (
size_t)3);
21 if (out_nfft == NULL || n == 0) {
26 if (nfft > ((
size_t)-1) / (
size_t)4) {
37static void fft_radix4_butterfly(
39 double angle,
int inverse)
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;
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];
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];
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];
70static void fft_radix4_stage(
72 size_t group,
int inverse)
74 const size_t quarter = group / 4;
75 const double step = (inverse ? 2.0 : -2.0) *
LMMC_PI / (
double)group;
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);
90 if (!lmmc_is_power_of_four(n, &digits)) {
94 for (i = 0; i < n; ++i) {
95 const size_t r = lmmc_reverse_base4(i, digits);
97 lmmc_swap(&real[i], &real[r]);
98 lmmc_swap(&imag[i], &imag[r]);
101 for (len = 4; len <= n; len *= 4) {
102 fft_radix4_stage(real, imag, n, len, inverse);
103 if (len == n) {
break; }
106 const double scale = 1.0 / (double)n;
107 for (i = 0; i < n; ++i) {
120 if (real == NULL || imag == NULL) {
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)) {
133 return lmmc_fft_radix4_core(real, imag, n, inverse ? 1 : 0);
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_status_t
LMMC 库统一返回的状态码.
@ LMMC_STATUS_INVALID_ARGUMENT