用到的工具汇总
整体的思路和流程
- 用下载的 .dll 文件生成可供静态连接的 .lib 文件。这样可以直接添加到工程中,方便调用。
- 在 VS2010 中配置 FFTW 的包含路径、静态链接库路径和具体文件。
- 在所创建的工程中添加FFTW的 .dll 文件。
- 测试验证。
- 注意事项。
具体步骤
生成 .lib 文件
因为 FFTW 的 dll 在发布时不提供 lib,没有 lib 我们就不能静态的加载。所以我们首先要做的就是配合 .def 文件来生成 .lib 文件。
解压 fftw-3.3.4-dll32.zip 文件,并进入目录,首先阅读里面的 README-WINDOWS 文件,获取相关信息。
开始菜单,所有程序,VS2010,打开 Visual Studio 命令提示。
在命令提示窗口中,切换路径到上面刚刚解压好的目录下,输入下面的命令,生成 .lib 文件。
bash
lib /machine:x86 /def:libfftw3f-3.def
lib /machine:x86 /def:libfftw3-3.def
lib /machine:x86 /def:libfftw3l-3.def
这时可能会报错,lib 命令无法使用。这时有下面两种解决办法:
1. 进入VS2010的 \Common7\IDE 路径,复制下面三个文件到 \VC\bin 路径下。
- mspdb100.dll
- mspdbcore.dll
- mspdbsrv.exe
2. 把 \Common7\IDE\ 添加到环境变量中。
命令执行成功,会在解压目录下生成三个 .lib 文件。
- libfftw3-3.lib
- libfftw3f-3.lib
- libfftw3l-3.lib
配置FFTW的包含路径、静态链接库路径和具体文件
新建项目,依次打开属性,配置属性,VC++目录。
1. 配置包含路径:在包含目录选项栏中,添加刚才的解压目录。这是搜索包含文件时使用的路径。与 INCLUDE xx.h 对应。
2. 配置静态链接库路径:在库目录选项栏中,添加刚才的解压目录。这是搜索库文件时使用的路径。与环境变量 LIB 相对应。这里还有一个引用目录,它是搜索通过#Using引入的文件时使用的路径。与库路径是有区别的。
3. 配置具体文件:链接器,输入,附加依赖项,增加上面生成的三个 .lib 文件。
在工程中添加 .dll 文件
复制解压目录里的三个 .dll 文件到工程路径里。
测试验证
//test-fftw.c
#include "fftw3.h"
int main()
{
int N= 8;
int i, j;
fftw_complex *in, *out;
in = (fftw_complex*) fftw_malloc(sizeof(fftw_complex) * N);
out = (fftw_complex*) fftw_malloc(sizeof(fftw_complex) * N);
for( i=0; i < N; i++)
{
in[i][0] = 1.0;
in[i][1] = 0.0;
printf("%6.2f ",in[i][0]);
}
printf("\n");
fftw_plan p;
p=fftw_plan_dft_1d(N,in,out, FFTW_FORWARD, FFTW_ESTIMATE);
fftw_execute(p);
fftw_destroy_plan(p);
for(j = 0;j < N;j++)
{
printf("%6.2f ",out[j][0]);
}
printf("\n");
fftw_free(in);
fftw_free(out);
return 0;
}
运行成功之后会得到如下结果,说明配置成功!
注意事项
- 关于逆变换。FFTW 的逆变换默认没有除以系数,如果要得到正确结果,我们需要手动除以系数,这里需要注意一下。
- 关于 FFTW 提供的复数类型 fftw_complex 与 C++ 中的复数类型 complex。可以直接通过指针类型转换来互相读写数据。
官方文档有详细说明:
http://www.fftw.org/fftw3_doc/Complex-numbers.html#Complex-numbers - 更多 FFTW 的使用方法可以参考
下面的测试程序可以对前两个问题做一个总结和说明。
//test-fftw-ifft.cpp
#include <iostream>
#include <complex>
#include "fftw3.h"
#define ROW 4 //输入矩阵的行数
#define COL 8 //输入矩阵的列数
using namespace std;
int main()
{
cout << "********************************" << endl;
cout << "\nFFTW的傅里叶逆变换测试程序: " << endl;
complex<double> inputdata[ROW][COL];
for (int row = 0; row < ROW; row++)
{
for (int col =0; col < COL; col++)
{
inputdata[row][col] = complex<double>(1, 0);
}
}
cout << "\n4行8列的输入数据为: " << endl;
for (int row = 0; row < ROW; row++)
{
for (int col =0; col < COL; col++)
{
cout << inputdata[row][col] << '\t';
}
cout << endl;
}
cout << "\n对每一行做傅里叶逆变换..." << endl;
fftw_plan p;
int rank = 1; //1d transform.进行变换时,原始矩阵的维度。下一行的n[]紧接着用来确定每个维度的尺寸。
int n[] = {COL}; //1d transform of length. size number of each transform. n should be elementwise less than or equal to {i,o}nembed.
int howmany = ROW; //the number of transforms to compute
int istride, ostride;
istride = ostride = 1; //distance between two elements in the same row(1)/col(COL)。原始矩阵中,位于同一变换里的相邻元素的间隔
int *inembed = n; //前面的每个变换用到的矩阵,可以是某个更大矩阵的子矩阵。{io}nembed就是来描述这个大矩阵的。
int *onembed = n;
int idist = COL; //用来确定两个相邻变换起始位置之间的间隔
int odist = COL; //用来确定两个相邻变换起始位置之间的间隔
p = fftw_plan_many_dft(rank, n, howmany,
(fftw_complex*)(inputdata), //结果矩阵地址
inembed, istride, idist,
(fftw_complex*)(inputdata), //输入矩阵地址
onembed, ostride, odist, FFTW_BACKWARD, FFTW_ESTIMATE);
fftw_execute(p);
fftw_destroy_plan(p);
cout << "\n得到的结果为: " << endl;
for (int row = 0; row < ROW; row++)
{
for (int col =0; col < COL; col++)
{
cout << inputdata[row][col] << '\t';
}
cout << endl;
}
cout << "\n结果表明,FFTW提供的傅里叶逆变换并没有对结果除以系数。" << endl;
return 0;
}
运行测试程序,得到的结果如下图: