开发环境:
系统:Windows 10
QT版本:5.10
编译器:mingw32
1.下载fftw
http://www.fftw.org/install/windows.html,根据自已编译器版本下载32位或64位
2.生成lib库
使用visual studio里面的lib.exe工具(已管理员权限运行CMD),进入fftw-3.3.5-dll32目录,运行:
lib /def:libfftw3-3.def
lib /def:libfftw3f-3.def
lib /def:libfftw3l-3.def
会生成对应的lib和exp文件,如果需要.a库文件,把.lib直接重命名为.a即可
3.qt工程设置
在pro文件中添加lib和头文件
将libfftw3-3.dll,libfftw3f-3.dll和libfftw3l-3.dll拷贝到工程的build目录下
4.测试
读一个48K,16bit,单声道的pcm文件,然后通过fft变换后显示振幅谱和相位谱。
/**
* @brief MainWindow::show_amplitude_waveform 显示频域的幅度
* @param file_path 数据文件
* @param polt_1 显示振幅
* @param polt_2 显示相位
* @return
*/
int MainWindow::show_amplitude_waveform(char * file_path, QCustomPlot *polt_1, QCustomPlot *polt_2)
{
double val_max = 0;
size_t result;
char *buf;
short *in_buf;
FILE *fp1=fopen(file_path, "rb"); //打开读权限
fseek(fp1,0,SEEK_END); //文件指针从0挪到尾部
long filesize;
filesize=ftell(fp1); //ftell求文件指针相对于0的便宜字节数,就求出了文件字节数
int N = filesize/2; //计算数据个数
if(fp1==NULL) //判断文件是否打开
{
QMessageBox::critical(NULL, "错误", "\"" + QString(QLatin1String(file_path)) + "\"" + "文件打开失败!", QMessageBox::Yes, QMessageBox::Yes);
return -1;
}
rewind(fp1); //还原指针位置
buf=(char *)malloc(filesize); //开辟空间给缓存数组
if(buf==NULL)
{
QMessageBox::critical(NULL, "错误", "\"" + QString(QLatin1String(file_path)) + "\"" + "内存分配失败!", QMessageBox::Yes, QMessageBox::Yes);
return -1;
}
result =fread(buf, 1, filesize, fp1);//每次读一个字节到buf,同时求读的次数
if(result != filesize) //判断读的次数和文件大小是否一致
{
QMessageBox::critical(NULL, "错误", "\"" + QString(QLatin1String(file_path)) + "\"" + "文件读取失败!", QMessageBox::Yes, QMessageBox::Yes);
return -1;
}
in_buf = (short *)buf; //强转为short,因为采样深度是16bit
//为fft输入计算分配空间
double * in = (double*)fftw_malloc(sizeof(double) * N);
for(int i=0; i<N; i++)
{
in[i] = in_buf[i]; //将pcm文件中的数据复制到fft的输入
}
//为fft输出算分配空间
fftw_complex * out = (fftw_complex*)fftw_malloc(sizeof(fftw_complex) * N);
//进行fft变换,fftw_plan_dft_c2r_1d函数进行反变换
fftw_plan p = FFTW3_H::fftw_plan_dft_r2c_1d(N, in, out, FFTW_ESTIMATE);
fftw_execute(p);
double dx3 = (double)SAMPLE_RATE / N;
polt_1->xAxis->setRange(0, SAMPLE_RATE/2, Qt::AlignLeft);
//根据FFT计算的复数计算振幅谱
for( int i=0; i<N/2; i++ )
{
double val = sqrt(out[i][0] * out[i][0] + out[i][1] * out[i][1]);
val = val / (N / 2);
polt_1->graph(0)->addData( dx3 * i, val );
if( val > val_max )
{
val_max = val;
}
double db = log(val);
//qDebug("frequency = %f, amplitude = %f, db = %f", dx3 * i, val / (N / 2), db);
}
polt_1->yAxis->setRange(val_max*0.6, val_max*1.2, Qt::AlignBottom);
polt_1->replot();
polt_2->xAxis->setRange(0, SAMPLE_RATE/2, Qt::AlignLeft);
polt_2->yAxis->setRange(0, 10, Qt::AlignBaseline);
//根据FFT计算的复数计算相位谱
for( int i=0; i<N/2; i++ )
{
double val = atan2(out[i][1], out[i][0]);
polt_2->graph(0)->addData( dx3 * i, val );
}
polt_2->replot();
fclose(fp1); //关闭文件指针
fftw_destroy_plan(p);
free(buf); //释放buf
fftw_free(in);
fftw_free(out);
return 0;
}