30static int fft_is_power_of_two(
size_t n) {
31 return (n > 0) && ((n & (n - 1)) == 0);
38static size_t fft_next_power_of_two(
size_t n) {
40 if (n == 0) {
return 1; }
42 if (p > SIZE_MAX / 2) {
return 0; }
56 for (i = 1; i < n; ++i) {
65 tmp = real[i]; real[i] = real[j]; real[j] = tmp;
66 tmp = imag[i]; imag[i] = imag[j]; imag[j] = tmp;
81 fft_bit_reverse(real, imag, n);
83 angle_sign = inverse ? 1.0 : -1.0;
85 for (len = 2; len <= n; len <<= 1) {
86 double angle = angle_sign * 2.0 *
LMMC_PI / (double)len;
87 double wlen_r = cos(angle);
88 double wlen_i = sin(angle);
90 for (i = 0; i < n; i += len) {
91 double w_r = 1.0, w_i = 0.0;
92 size_t half = len >> 1;
94 for (j = 0; j < half; ++j) {
96 size_t v_idx = i + j + half;
99 double t_r = w_r * real[v_idx] - w_i * imag[v_idx];
100 double t_i = w_r * imag[v_idx] + w_i * real[v_idx];
103 real[v_idx] = real[u_idx] - t_r;
104 imag[v_idx] = imag[u_idx] - t_i;
105 real[u_idx] = real[u_idx] + t_r;
106 imag[u_idx] = imag[u_idx] + t_i;
110 double new_w_r = w_r * wlen_r - w_i * wlen_i;
111 double new_w_i = w_r * wlen_i + w_i * wlen_r;
117 if (len == n) {
break; }
121 double scale = 1.0 / (double)n;
122 for (i = 0; i < n; ++i) {
131static void fft_chirp_input(
136 for (k = 0; k < n; ++k) {
137 const double kd = (double)k;
138 const double phase = sign *
LMMC_PI * kd * kd / (double)n;
139 const double c = cos(phase);
140 const double s = sin(phase);
141 a_r[k] = real[k] * c - imag[k] * s;
142 a_i[k] = imag[k] * c + real[k] * s;
146static void fft_chirp_kernel(
148 size_t n,
size_t m,
double sign)
151 for (k = 0; k < n; ++k) {
152 const double kd = (double)k;
153 const double phase = -sign *
LMMC_PI * kd * kd / (double)n;
157 for (k = 1; k < n; ++k) {
163static void fft_pointwise_product(
168 for (k = 0; k < n; ++k) {
169 const double tr = a_r[k] * b_r[k] - a_i[k] * b_i[k];
170 const double ti = a_r[k] * b_i[k] + a_i[k] * b_r[k];
188 size_t convolution_length;
200 if (!lmmc_safe_mul_size(2, n, &convolution_length)) {
203 --convolution_length;
204 m = fft_next_power_of_two(convolution_length);
213 if (a_r == NULL || a_i == NULL || b_r == NULL || b_i == NULL) {
227 sign = inverse ? 1.0 : -1.0;
229 fft_chirp_input(real, imag, a_r, a_i, n, sign);
230 fft_chirp_kernel(b_r, b_i, n, m, sign);
233 st = fft_radix2(a_r, a_i, m, 0);
236 st = fft_radix2(b_r, b_i, m, 0);
240 fft_pointwise_product(a_r, a_i, b_r, b_i, m);
243 st = fft_radix2(a_r, a_i, m, 1);
247 fft_chirp_input(a_r, a_i, real, imag, n, sign);
251 double scale = 1.0 / (double)n;
252 for (k = 0; k < n; ++k) {
270 if (real == NULL || imag == NULL || n == 0 ||
271 !lmmc_storage_envelope_checked(
272 real, 1, n, n,
sizeof(
lmmc_real_t), &real_envelope) ||
273 !lmmc_storage_envelope_checked(
274 imag, 1, n, n,
sizeof(
lmmc_real_t), &imag_envelope) ||
275 lmmc_storage_envelopes_overlap(&real_envelope, &imag_envelope)) {
284 if (lmmc_is_power_of_four(n, NULL)) {
286 }
else if (fft_is_power_of_two(n)) {
287 return fft_radix2(real, imag, n, inverse ? 1 : 0);
289 return fft_bluestein(real, imag, n, inverse ? 1 : 0);
301static int fft_padding_overlaps(
308 if (lmmc_storage_envelopes_overlap(real_out, imag_out)) {
311 if (lmmc_storage_envelopes_overlap(real_out, real_in) ||
312 lmmc_storage_envelopes_overlap(real_out, imag_in)) {
315 if (lmmc_storage_envelopes_overlap(imag_out, real_in) ||
316 lmmc_storage_envelopes_overlap(imag_out, imag_in)) {
319 if (lmmc_storage_envelopes_overlap(nfft, real_in) ||
320 lmmc_storage_envelopes_overlap(nfft, imag_in)) {
323 return lmmc_storage_envelopes_overlap(nfft, real_out) ||
324 lmmc_storage_envelopes_overlap(nfft, imag_out);
339 if (real_in == NULL || imag_in == NULL || n == 0) {
342 if (real_out == NULL || imag_out == NULL || out_nfft == NULL) {
350 if (!lmmc_storage_envelope_checked(
351 real_in, 1, n, n,
sizeof(
lmmc_real_t), &real_in_envelope) ||
352 !lmmc_storage_envelope_checked(
353 imag_in, 1, n, n,
sizeof(
lmmc_real_t), &imag_in_envelope) ||
354 !lmmc_storage_envelope_checked(
355 real_out, 1, nfft, nfft,
sizeof(
lmmc_real_t), &real_out_envelope) ||
356 !lmmc_storage_envelope_checked(
357 imag_out, 1, nfft, nfft,
sizeof(
lmmc_real_t), &imag_out_envelope) ||
358 !lmmc_storage_envelope_checked(
359 out_nfft, 1, 1, 1,
sizeof(
size_t), &nfft_envelope)) {
362 if (fft_padding_overlaps(&real_in_envelope, &imag_in_envelope,
363 &real_out_envelope, &imag_out_envelope,
369 memcpy(real_out, real_in, n *
sizeof(
lmmc_real_t));
370 memcpy(imag_out, imag_in, n *
sizeof(
lmmc_real_t));
374 memset(real_out + n, 0, (nfft - n) *
sizeof(
lmmc_real_t));
375 memset(imag_out + n, 0, (nfft - n) *
sizeof(
lmmc_real_t));
LMMC binary real type and arithmetic spelling.
double lmmc_real_t
Public and internal LMMC real type.
lmmc_status_t lmmc_fft_radix4_pad_into(const lmmc_real_t *real_in, const lmmc_real_t *imag_in, size_t n, lmmc_real_t *real_out, lmmc_real_t *imag_out, size_t *out_nfft)
将长度 n 的输入零填充至不小于它的最小 4 的幂。
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_inverse(lmmc_real_t *real, lmmc_real_t *imag, size_t n)
等价于 lmmc_fft(real, imag, n, 1) .
lmmc_status_t lmmc_fft_forward(lmmc_real_t *real, lmmc_real_t *imag, size_t n)
等价于 lmmc_fft(real, imag, n, 0) .
lmmc_status_t lmmc_fft_radix4_next_size(size_t n, size_t *out_nfft)
计算不小于 n 的最小 4 的幂,用于 FFT 长度对齐。
lmmc_status_t lmmc_fft(lmmc_real_t *real, lmmc_real_t *imag, size_t n, int inverse)
计算任意长度 N 点 DFT(正变换或逆变换).
void * lmmc_memory_alloc_array(size_t count, size_t element_size)
void lmmc_memory_free(void *pointer)
Private recoverable allocator for persistent LMMC ownership.
lmmc_status_t
LMMC 库统一返回的状态码.
@ LMMC_STATUS_ALLOCATION_FAILED
@ LMMC_STATUS_INVALID_ARGUMENT