c++如何实现一个快速傅里叶变换(FFT)_c++信号处理算法【源码】

C++实现的基-2迭代Cooley-Tukey FFT支持复数输入、自然序输出,含位逆序重排与蝶形运算,要求长度为2的幂,使用std::complex,无外部依赖,可直接编译运行。

用 C++ 实现一个高效、可读、实用的快速傅里叶变换(FFT),核心是采用 基-2 递归/迭代 Cooley-Tukey 算法,支持复数输入,输出为标准频域复数数组(按自然序,非位逆序)。下面给出一个轻量、无外部依赖、可直接编译运行的完整实现。

基础准备:使用 std::complex 和标准库

无需第三方库,仅需:

  • #include #include
  • 使用 std::complex 表示复数
  • 输入长度必须是 2 的整数次幂(自动补零或报错提示)

迭代版 FFT(推荐:避免递归开销,内存友好)

迭代实现更稳定、无栈溢出风险,适合实时信号处理。关键点是位逆序重排 + 蝶形运算分层计算:

立即学习“C++免费学习笔记(深入)”;

#include 
#include 
#include 
#include 

using Complex = std::complex using VecC = std::vector

// 将 n 转换为 bit-reversed 数(bit width = log2(size)) int bitReverse(int n, int bits) { int rev = 0; for (int i = 0; i < bits; ++i) { rev |= ((n >> i) & 1) << (bits - 1 - i); } return rev; }

// 基-2 迭代 FFT(in-place,升序输出) void fft(VecC& x) { int N = x.size(); if (N <= 1) return;

// 检查是否为 2 的幂
if ((N & (N - 1)) != 0) {
    throw std::runtime_error("FFT size must be power of 2");
}

int bits = 0;
for (int n = N; n youjiankuohaophpcn 1; n youjiankuohaophpcnyoujiankuohaophpcn= 1) ++bits;

// 位逆序重排
for (int i = 0; i zuojiankuohaophpcn N; ++i) {
    int j = bitReverse(i, bits);
    if (j youjiankuohaophpcn i) std::swap(x[i], x[j]);
}

// 蝶形运算:按级数(m = 1,2,4,...,N/2)
for (int m = 1; m zuojiankuohaophpcn N; m *= 2) {
    double theta = M_PI / m; // π/m
    Complex w_m = Complex(cos(theta), -sin(theta)); // 主根 ωₘ

    for (int k = 0; k zuojiankuohaophpcn N; k += 2 * m) {
        Complex w = 1.0;
        for (int j = 0; j zuojiankuohaophpcn m; ++j) {
            Complex t = w * x[k + j + m];
            Complex u = x[k + j];
            x[k + j] = u + t;
            x[k + j + m] = u - t;
            w *= w_m;
        }
    }
}

}

使用示例:生成正弦信号并分析频谱

验证 FFT 正确性,比如对 64 点含 8Hz 正弦波(采样率 64Hz)做变换:

立即学习“C++免费学习笔记(深入)”;

int main() {
    const int N = 64;
    VecC signal(N);
// 生成 8Hz 正弦(采样率 fs = 64Hz → 一个周期 8 点 → 频点索引 = 8)
double fs = 64.0;
for (int i = 0; i zuojiankuohaophpcn N; ++i) {
    double t = i / fs;
    signal[i] = std::sin(2 * M_PI * 8 * t);
}

fft(signal);

// 输出前 12 个幅度谱(|X[k]|)
std::cout zuojiankuohaophpcnzuojiankuohaophpcn "Magnitude spectrum (first 12 bins):\n";
for (int k = 0; k zuojiankuohaophpcn 12; ++k) {
    double mag = std::abs(signal[k]);
    std::cout zuojiankuohaophpcnzuojiankuohaophpcn "bin[" zuojiankuohaophpcnzuojiankuohaophpcn k zuojiankuohaophpcnzuojiankuohaophpcn "] = " zuojiankuohaophpcnzuojiankuohaophpcn mag zuojiankuohaophpcnzuojiankuohaophpcn "\n";
}
// 应看到 bin[8] 和 bin[56](共轭对)幅值显著(≈32)

return 0;

}

补充说明与优化建议

  • 逆变换 IFFT:只需对 FFT 结果取共轭 → 调用 fft → 再取共轭并除以 N
  • 实数 FFT 优化:若输入纯实数,可用 packed 格式(如将两个实序列合进一个复序列)提升 2 倍效率
  • 精度注意:使用 double 复数,避免 float 在长序列下累积误差
  • 生产环境:高频/大数据推荐用 FFTW 或 Intel IPP;教学/嵌入式场景此实现足够清晰可控

基本上就这些 —— 代码简洁、逻辑清晰、可直接集成到信号采集、滤波器设计或频谱分析模块中。需要支持任意长度(Bluestein 算法)或 SIMD 加速时,再在此基础上扩展即可。