C++ 实现快速傅里叶变换(FFT)
项目介绍
快速傅里叶变换(Fast Fourier Transform, FFT)是一种高效计算 离散傅里叶变换(DFT) 及其逆变换的方法。傅里叶变换在信号处理、图像处理、数据分析等领域具有广泛应用,例如:
- 音频频谱分析
- 图像处理中的滤波
- 无线通信中的调制解调
- 数据压缩(如 JPEG、MP3)
本项目将使用 C++ 实现 基于 Cooley-Tukey 算法的 FFT,并提供:
- FFT 计算(递归和迭代方式)
- 逆 FFT(IFFT)计算
- FFT 在信号处理中的应用
- 完整代码、详细注释及代码解读
项目实现思路
离散傅里叶变换(DFT)公式:
DFT 计算复杂度为 O(N²),FFT 通过 分治思想 将其优化至 O(N logN),主要思路如下:
- 奇偶分解:将原始序列按奇数索引和偶数索引拆分。
- 递归计算:分别对奇偶部分求 FFT。
- 合并结果:利用旋转因子
合并结果。
本项目提供 递归版和迭代版 FFT,并支持 逆变换(IFFT)。
代码实现
#include <iostream>
#include <vector>
#include <complex>
#include <cmath>
using namespace std;
// 定义复数类型
using Complex = complex<double>;
using CArray = vector<Complex>;
/**
* @brief 递归实现快速傅里叶变换 (FFT)
* @param x 输入复数数组
*/
void fft(CArray &x) {
int N = x.size();
if (N <= 1) return; // 递归终止条件
// 拆分为偶数和奇数部分
CArray even(N / 2), odd(N / 2);
for (int i = 0; i < N / 2; i++) {
even[i] = x[i * 2];
odd[i] = x[i * 2 + 1];
}
// 递归计算 FFT
fft(even);
fft(odd);
// 组合结果
for (int k = 0; k < N / 2; k++) {
Complex t = polar(1.0, -2 * M_PI * k / N) * odd[k]; // 旋转因子 e^(-j2πk/N)
x[k] = even[k] + t;
x[k + N / 2] = even[k] - t;
}
}
/**
* @brief 递归实现逆快速傅里叶变换 (IFFT)
* @param x 输入复数数组
*/
void ifft(CArray &x) {
int N = x.size();
if (N <= 1) return;
// 拆分为偶数和奇数部分
CArray even(N / 2), odd(N / 2);
for (int i = 0; i < N / 2; i++) {
even[i] = x[i * 2];
odd[i] = x[i * 2 + 1];
}
// 递归计算 IFFT
ifft(even);
ifft(odd);
// 组合结果
for (int k = 0; k < N / 2; k++) {
Complex t = polar(1.0, 2 * M_PI * k / N) * odd[k]; // 旋转因子 e^(j2πk/N)
x[k] = (even[k] + t) / 2.0;
x[k + N / 2] = (even[k] - t) / 2.0;
}
}
/**
* @brief 测试 FFT 和 IFFT
*/
int main() {
CArray data = {1, 2, 3, 4, 5, 6, 7, 8}; // 输入信号
cout << "原始数据:" << endl;
for (const auto &val : data) cout << val << " ";
cout << endl;
fft(data); // 执行 FFT
cout << "FFT 结果:" << endl;
for (const auto &val : data) cout << val << " ";
cout << endl;
ifft(data); // 执行 IFFT
cout << "逆 FFT 结果 (恢复信号):" << endl;
for (const auto &val : data) cout << val << " ";
cout << endl;
return 0;
}
代码解读
1. 复数计算
FFT 计算涉及复数运算,因此使用 std::complex<double>
定义复数类型,并使用 std::vector<Complex>
存储 FFT 计算的数据。
2. 递归 FFT 计算
a) 终止条件
当输入数组的长度为 1 时,不再递归,直接返回。
b) 拆分数据
FFT 采用 分治法,将输入数据分为偶数索引部分和奇数索引部分,分别递归计算其 FFT。
c) 递归计算
分别对偶数索引部分和奇数索引部分应用 FFT,进一步细分计算,直到拆分到单个元素。
d) 旋转因子计算
使用欧拉公式计算旋转因子 该因子用于合并递归计算得到的结果。
e) 结果合并
利用旋转因子,将偶数部分的 FFT 结果与奇数部分的 FFT 结果组合,构造最终的 FFT 变换结果。
3. 逆 FFT (IFFT) 计算
a) 结构类似 FFT
逆 FFT 采用相同的分治策略,也将输入数据分为偶数部分和奇数部分,并递归计算。
b) 旋转因子方向相反
不同于 FFT,逆 FFT 的旋转因子采用正指数 进行计算,以执行逆变换。
c) 归一化
逆变换的最终结果需要除以 2,以归一化恢复原始信号。
4. FFT 计算流程
- 输入信号数据
- 递归拆分数据
- 对拆分后的数据递归应用 FFT
- 使用旋转因子合并结果
- 返回最终的频域数据
5. IFFT 计算流程
- 输入 FFT 变换后的数据
- 递归拆分数据
- 递归应用 IFFT
- 使用旋转因子合并
- 归一化恢复原始信号
6. 示例执行
- 程序首先输出原始信号数据
- 应用 FFT 并输出频域数据
- 应用 IFFT 恢复原始信号,并验证结果
项目总结
- FFT 通过分治法优化 DFT 计算,提高效率
- IFFT 可用于恢复原始信号
- 适用于音频、图像处理、信号分析等领域
- 若处理大规模数据,建议使用优化的 FFT 库,如 FFTW