傅里叶变换应该是上大二的时候《信号与系统》课上学过,上研后在《数字信号处理》课上又学了一遍。当初一直在想傅里叶变换到底有什么用呢?什么时候能用上呢?时间如梭,没想到毕业四年后,一个小项目要用到傅里叶变换,喜大普奔啊,当初晦涩的概念、眼晕的公式,终于没白学。是的,其实任何知识都不是白学的,即使工作中一直用不到傅里叶变换,至少思维得到了锻炼,都是有益的。在应用傅里叶变换过程中,可以按照公式自己编程实现,也可以使用已有的开源傅里叶变换函数库。经过查阅资料,本人选用fftw函数库来进行傅里叶变换,因为fftw官网上提到说该函数库性能非常出众,甚至可以和同类型的商业软件相竞争。fftw官网地址为:http://www.fftw.org/。
一、fftw下载
由于本人是在windows平台开发,于是到下面链接:http://www.fftw.org/install/windows.html下载已编译版本。如下图所示,该图信息量很大,既有32/64两个版本的下载链接,同时还有生成lib文件命令。即32位系统命令为:
lib /def:libfftw3-3.def,而64位系统为: lib /machine:x64 /def:libfftw3-3.def。
下载解压后,会发现只有dll和头文件,在没有lib文件时,使用fftw库时会比较繁琐。于是在应用fftw编程前还是动手先生成lib文件。方法很简单,首先打开VS命令提示工具。本人使用的开发工具为VS2005,如下图所示:
打开后,cd到已下载的fftw文件目录,然后执行前面提到的lib生成命令,如下图所示:
命令执行完毕后,即可在当前目录内看到新生成的lib文件,我这边分别生成了double、float、long double三个版本,实际使用时可根据项目需要,选择相应精度的版本。生成的lib库文件如下图所示:
二、简单编程实例
有了头文件、lib/dll文件,那就什么都有了。新建一个工程,马上用起来吧。下面为一个非常简单的编程实例,主要完成实数傅里叶变换,输入为正弦曲线,输出为傅里叶变换的幅度谱。
#include "stdafx.h" #include <stdio.h> #include <stdlib.h> #include <math.h> #include "include/fftw3.h" #pragma comment(lib, "libfftw3-3.lib") // double版本 // #pragma comment(lib, "libfftw3f-3.lib")// float版本 // #pragma comment(lib, "libfftw3l-3.lib")// long double版本 #define PI 3.1415926 int main() { int len = 8; double *in = NULL; // 如果要使用float版本,需先引用float版本的lib库,然后在fftw后面加上f后缀即可. fftw_complex *out = NULL;// fftwf_complex --> 即为float版本 fftw_plan p; in = (double *)fftw_malloc(sizeof(double) * len); out = (fftw_complex *)fftw_malloc(sizeof(fftw_complex) * len); double dx = 1.0 / len; // 输入纯实数 for (int i = 0; i < len; i++) { in[i] = sin(2*PI * dx*i) + sin(4*PI * dx*i); printf("%.2f ", in[i]); } printf("\n\n"); // 傅里叶变换 p = fftw_plan_dft_r2c_1d(len, in, out, FFTW_ESTIMATE); fftw_execute(p); // 输出幅度谱 for (int i = 0; i < len; i++) { float len = sqrt(out[i][0]*out[i][0] + out[i][1]*out[i][1]); printf("%.2f ", len); } printf("\n"); // 释放资源 fftw_destroy_plan(p); fftw_free(in); fftw_free(out); system("pause"); return 0; }运行结果如下图所示,从结果来看,在频率为1及2两个位置有幅度输出,这与输入的频率为1及2的两个叠加正弦波吻合,结果正确。