上述分别为FFT、IFFT公式。下面首先讨论FFT的算法实现。 本文采用输入逆序、输出顺序的FFT计算方法。实质上就是在时域对x(n)进行“奇偶分类”、在频域上对X(k)进行“前后分类”。 值得说明的是,这里的“奇”和“偶”是相对的概念,并不完全是通常我们所理解的“奇”和“偶”。下面将给出一个例子进行说明: ·图中,总共可以分为 “三级” ,每一级包含若干 “蝶形计算单元”。每一个蝶形单元的结构如下: 因此,进行FFT运算只需考虑三件事情。一、将输入序列倒序排列,也就是进行奇偶分类。二、实现最基本的蝶形计算单元。三、根据规律,划分出FFT运算的级数,并且确定出每一级中参与蝶形运算的数据分组。
说明:complex为自己定义的复数数据结构。再次强调,奇偶分类就是倒序排序。二者是一样的。
蝶形运算单元的实现。分析蝶形运算单元,两输入、两输出,因此蝶形运算单元需要注意的就是输入、输出采用同一片内存存储即可,也就是让输出数据覆盖输入数据,这样可以有效节约存储资源。 void butterfly(int x1_point, int x2_point, complex wn) //蝶形计算单元 { complex result1, result2, T; T = multiplication(x[x2_point], wn); result1 = add(x[x1_point], T); result2 = sub(x[x1_point], T); x[x1_point] = result1; x[x2_point] = result2; }说明:上面multiplication、add、sub方法均为自己定义,wn为旋转因子。
进行单级FFT运算。需要注意的就是总结规律。总结出两对偶结点的“结点跨距”、“分组间隔”、“分组数”……有了这些才能够编写将参与蝶形运算的数据分类配对。 void single_fft(int m) //进行单级的fft运算 { //首先进行分组 int point_distance = (int)pow(2, m - 1); //结点跨距 int group_distance = 2 * point_distance; //分组间隔 int group_count = N / group_distance; //分组数 int group_header = 0; int x1, x2; //参与计算两结点的标号 complex w; int i, j; //循环控制符 //分组 for (i = 0;i < group_count;i++) { //获取一组的标号范围 group_header = i * group_distance; //将每组分成两半,前一半均为x1,后一半均为x2 for (j = 0;j < group_distance / 2;j++) { w = w_builder(m, j); x1 = j + group_header; x2 = x1 + point_distance; butterfly(x1, x2, w); } } } 有了单级FFT运算以后,将每一级组合就可以实现FFT运算了。 complex* fft(int fft_point, int xn_length, complex* xn) //fft最终封装 { int i; //初始化 fft_init(fft_point, xn_length, xn); //输入倒序 reverse(); //fft运算 for (i = 1;i <= bits;i++) { single_fft(i); } return x; }从上面的等式可以看出,括号里面的内容实际上就是FFT运算。也就是说只需要对输入、输出序列进行一定的处理,就可以利用刚刚已经做好的FFT算法实现IFFT的运算!
本文也程序也考虑到了FFT自动补零问题的处理,大家可以参考完整代码(FFT、IFFT均验证正确)。FFT.zip