FFT实现需规避递归栈溢出与精度误差,优先选迭代位逆序+蝴蝶运算;OpenCV的dft()需显式加DFT_SCALE归一化;FFTW须用fftw_malloc对齐内存;非2幂长度必须补零对齐。

用 std::complex 和自写递归 FFT 容易崩栈、精度差
标准库不提供 FFT 实现,直接手写递归版 fft() 看似简洁,但实际会遇到两个硬伤:一是递归深度为 O(n),n=1e6 时栈直接溢出;二是复数乘法累积误差明显,尤其在多次逆变换后实部出现 1e-12 级杂项。真要自己实现,必须改成迭代位逆序重排 + 蝴蝶运算,且全程用 std::complex<double></double>,别用 float。
OpenCV 的 dft() 默认返回非归一化结果
调用 cv::dft() 做 FFT 很方便,但默认输出不除以 n,逆变换也不自动归一化。这意味着:cv::dft(x, X, cv::DFT_COMPLEX_OUTPUT) 后,cv::dft(X, x_back, cv::DFT_INVERSE | cv::DFT_SCALE) 才能得到原数组(cv::DFT_SCALE 就是除以 n)。漏掉这个标志,结果会放大 n 倍,调试时看到数值爆炸就该查这儿。
FFTW 在 C++ 里要手动管理内存对齐
FFTW 快、准、支持任意长度,但 C++ 接口不是开箱即用:fftw_complex* 指针必须由 fftw_malloc() 分配,不能用 new 或 std::vector 直接传指针。否则在 AVX 指令下大概率崩溃或结果错乱。典型写法是:
fftw_complex *in = fftw_alloc_complex(n); fftw_complex *out = fftw_alloc_complex(n); fftw_plan p = fftw_plan_dft_1d(n, in, out, FFTW_FORWARD, FFTW_ESTIMATE); // ... 使用后 fftw_destroy_plan(p); fftw_free(in); fftw_free(out);
另外,若输入长度不是 2/3/5/7 的乘积,FFTW 会降速——这时可提前调用 fftw_plan_with_nthreads() 并用 FFTW_PATIENT 生成优化过的 plan,但首次耗时会变长。
立即学习“C++免费学习笔记(深入)”;
输入长度不是 2 的幂时,std::vector 需补零对齐
多数 FFT 实现(包括 OpenCV 和朴素迭代版)要求长度为 2 的幂,否则行为未定义或报错。别指望自动截断或丢弃——得自己补零:x.resize(next_pow2(x.size()), {0.0, 0.0});,其中 next_pow2() 可用 1 << (32 - __builtin_clz(n-1))(GCC)或 std::bit_ceil(n)(C++20)。补零本身不影响频谱主瓣,但会插值式拉伸频率轴,做频域分析时要注意横坐标缩放。
真正麻烦的是实时流式 FFT:每次新来一批数据,既要滑动窗口又要补零重算,这时候固定长度 + 循环缓冲区比反复 resize std::vector 更靠谱。补零位置、重叠策略、窗函数选择——这些才是实际卡点,不是 FFT 函数本身。


















