信号处理算法(4):全球最快的傅里叶变换算法(FFTW)

2023-11-05

   本文大部分内容转载自博客【congwulong】 (https://blog.csdn.net/congwulong/article/details/7576012)

  FFTW(Fastest Fourier Transform in the West)是世界上最快的FFT, 实测计算长度为10000的double数组, 单次运行时间在2ms左右。为了详细了解FFTW以及为编程方便,特将用户手册看了一下,并结合手册制作了以下FFTW中文参考。其中大部分是原文重点内容的翻译,并加入了一些注解。

一、 简介

  先看一下使用FFTW编程的方法:

      #include <fftw3.h>
     ...
     {
         fftw_complex *in, *out;
         fftw_plan p;
         ...
         in = (fftw_complex*) fftw_malloc(sizeof(fftw_complex) * N);
         out = (fftw_complex*) fftw_malloc(sizeof(fftw_complex) * N);


         // 输入数据in赋值


         p = fftw_plan_dft_1d(N, in, out, FFTW_FORWARD, FFTW_ESTIMATE);
         fftw_execute(p); // 执行变换
         ...
         fftw_destroy_plan(p);
         fftw_free(in); 
         fftw_free(out);
     }

   大致是先用fftw_malloc分配输入输出内存,然后输入数据赋值,然后创建变换方案(fftw_plan),然后执行变换(fftw_execute),最后释放资源,还是比较简单的。

二、 一维复数据的DFT

  1. 数据类型

   fftw_complex默认由两个double组成,在内存中顺序排列,实部在 前,虚部在后,即typedef double fftw_complex[2]。FFTW文档指出如果有一个支持C99标准的C编译器(如gcc),可以在#include <fftw3.h>前加入#include <complex.h>,这样一来fftw_complex就被定义为本机复数类型,而且与上述typedef二进制兼容(指内存排列),经 测试不能用在Windows下。C++有一个复数模板类complex<T>,在头文件<complex>下定义。C++标准委 员会最近同意该类的存储方式与C99二进制兼容,即顺序存储,实部在前,虚部在后(见报告WG21/N1388),该解决方案在所有主流标准库实现中都能正确工作。所以实际上可以用complex <double> 来代替fftw_complex,比如有一个复数数组complex<double> *x,则可以将其类型转换后作为参数传递给fftw:reinterpret_cast<fftw_complex*>(x)。测试如下:开 两个数组fftw_complex x1[2]和complex<double> x2[2],然后赋相同值,在调试模式下可以看到它们的内存排列是相同的。complex<T>类数据赋值的方式不是很直接,必须采用无名对象方式x2[i] = complex <double>(1,2) 或成员函数方式x2[i].real(1);x2[i].imag(2);不能直接写x2[i].real=1;x2[i].imag=2。 fftw_complex赋值方式比较直接:x1[i][0]=1;x1[i][1]=2。最后,考虑到数据对齐(见后),最好使用 fftw_malloc分配内存,所以可以将其返回的指针转换为complex <double> *类型使用(比如赋值或读取等),变换时再将其转换为fftw_complex*。

  2. 函数接口

fftw_plan fftw_plan_dft_1d(int n, fftw_complex *in, fftw_complex *out, int sign, unsigned flags);

   n为数据个数,可以为任意正整数,但如果为一些小因子的乘积计算起来可以更有效,不过即使n为素数算法仍然能够达到O(nlogn)的复杂度。FFTW对N=2a 3b 5c 7d 11e 13f的变换处理得最好,其中e+f=0/1,其它幂指数可以为任意值。

   如果in和out指针相同为原位运算,否则为非原位运算。

   sign可以为正变换FFTW_FORWARD(-1),也可以为逆变换FFTW_BACKWORD(+1),实际上就是变换公式中指数项的符号。需注意FFTW的逆变换没有除以N,即数据正变换再反变换后是原始数据的N倍。

   flags参数一般情况下为FFTW_MEASURE 或 FFTW_ESTIMATE。FFTW_MEASURE表示FFTW会先计算一些FFT并测量所用的时间,以便为大小为n的变换寻找最优的计算方法。依据 机器配置和变换的大小(n),这个过程耗费约数秒(时钟clock精度)。FFTW_ESTIMATE则相反,它直接构造一个合理的但可能是次最优的方 案。总体来说,如果你的程序需要进行大量相同大小的FFT,并且初始化时间不重要,可以使用FFTW_MEASURE,否则应使用 FFTW_ESTIMATE。FFTW_MEASURE模式下in和out数组中的值会被覆盖,所以该方式应该在用户初始化输入数据in之前完成。

   不知道上述说法是不是这个意思:先用FFTW_MEASURE模式自动选最优方案,速度较慢;然后使用该模式变换数据就会较快。示例代码为:

  int length = 50000;
  fftw_complex* din  = (fftw_complex *)fftw_malloc(sizeof(double)*length * 2);
  fftw_complex* dout = (fftw_complex *)fftw_malloc(sizeof(double)*length * 2);


  fftw_plan p   = fftw_plan_dft_1d(length, din, din, FFTW_FORWARD, FFTW_MEASURE);
  fftw_execute(p); 


  // 输入数据din赋值
  // ...


  fftw_execute(p);


  // 读取变换结果
  // ...


  fftw_destroy_plan(p);
  fftw_free(din);
  fftw_free(dout);

   实验发现第一个fftw_execute耗费了数秒,而第二个fftw_execute则瞬间完成,说明上述猜想可能是对的。

   创建完方案(fftw_plan)后,就可以用fftw_execute对指定的 数据in/out做任意次变换。如果想变换一个相同大小(N相等)但数据不同的另外一个数组in,可以创建一个新方案,FFTW会自动重用上次方案的信 息。这一点其实是非常好的,比如你首先用FFTW_MEASURE模式创建了一个最优的变换方案,只要变换数据的大小不变,你可以用 fftw_plan_dft_1d创建新的方案以对新数据执行变换,同时新变换仍然是最优的。一个fftw_plan只能对固定的in/out进行变换, 但可以在变换后改变in的内容(大小不变)以用同一个方案执行新的变换。

三、 多维复数据的DFT

fftw_plan fftw_plan_dft_2d(int n0, int n1,
                                fftw_complex *in, fftw_complex *out,
                                int sign, unsigned flags);
fftw_plan fftw_plan_dft_3d(int n0, int n1, int n2,
                                fftw_complex *in, fftw_complex *out,
                                int sign, unsigned flags);
fftw_plan fftw_plan_dft(int rank, const int *n,
                             fftw_complex *in, fftw_complex *out,
                             int sign, unsigned flags);

   多维复数据的DFT同一维复数据的DFT用法类似,数组in/out为行优先方式 存储。fftw_plan_dft是一个通用的复DFT函数,可以执行一维、二维或多维复DFT。比如对于图像(2维数据),其变换为 fftw_plan_dft_2d(height,width,85),因为原始图像数据为height×width的矩阵,即第一维(n0)为行数 height。

四、 一维实数据的DFT

  函数接口

fftw_plan fftw_plan_dft_r2c_1d(int n, double *in, fftw_complex *out, unsigned flags);
fftw_plan fftw_plan_dft_c2r_1d(int n, fftw_complex *in, double *out, unsigned flags);

   r2c版本:实输入数据,复Hermitian输出,正变换。

   c2r版本:复Hermitian输入数据,实输出数据,逆变换。

   n:逻辑长度,不必为物理长度。由于实数据的DFT具有 Hermitian对称性,所以只需要计算n/2+1(向下取整)个输出就可以了。比如对于r2c,输入in有n个数据,输出out有floor(n /2)+1个数据。对于原位运算,in和out为同一数组(out须强制类型转换),所以其必须足够大以容纳所有数据,长度为2*(n/2+1),in数 组的前n个数据为输入数据,后面的数据用来保存输出。

   c2r逆变换在任何情况下(不管是否为原位运算)都破坏输入数组in,如果有必要可以通过在flags中加入FFTW_PRESERVE_INPUT来阻止,但这会损失一些性能,而其这个标志位目前在多维实DFT中已不被支持。

   比如对于n=4,in=[1 2 3 4],out=[10 -2+2i -2 -2-2i],out具有共轭对称性,out的实际内存为10 0 -2 2 -2 0,共3个复数数据。对于n=5,in=[1 2 3 4 5],out=[15 -2.5+3.44i -2.5+0.81i -2.5-0.81i -2.5-3.44i] ,out的实际内存为15 0 -2.5 3.44 -2.5 0.81,共3个复数数据。

   实数据DFT中,首个变换数据为直流分量,为实数;如果n为偶数,由 Nyquist采样定理,第n/2个变换数据也为实数;所以可以把这两个数据组合在一起,即将第n/2个变换数据作为第0个变换数据的虚部,这样一来输入 数组就和输出数组相等(n=n/2*2)。一些FFT的实现就是这么做的,但FFTW没有这么做,因为它并不能很好地推广到多维DFT中,而且存储空间的 节省也是非常小以至于可以忽略不计。

   一个一维c2r和r2c DFT的替代接口可以在r2r接口中找到,它利用了半复数输出类型(即实部和虚部分开放在不通的区域里),使输出数组具有和输入数组同样的长度和类型。该接口在多维变换中用处不大,但有时可能会有一些性能的提升。

五、 多维实数据的DFT

fftw_plan fftw_plan_dft_r2c_2d(int n0, int n1,
                                    double *in, fftw_complex *out,
                                    unsigned flags);
fftw_plan fftw_plan_dft_r2c_3d(int n0, int n1, int n2,
                                    double *in, fftw_complex *out,
                                    unsigned flags);
fftw_plan fftw_plan_dft_r2c(int rank, const int *n,
                                 double *in, fftw_complex *out,
                                 unsigned flags);

   这是r2c接口(正变换),c2r接口(逆变换)只是简单的将输入/输出类型交换一下。用法大致同1d情况一样,需要特别注意的是复数据的存放方式。对于n0×n1×n1×…×nd-1的实输入数组(行优先),经过r2c正变换后,输出为一个n0×n1×n1×…×(nd-1/2+1)的复数(fftw_complex)数组(行优先),其中除法向下取整。由于复数数据的总长度要大于实数据,所以如果需要进行原位运算则输入实数组必须扩展以能够容纳所有复数据,即实数组的最后一维必须包含2(floor(nd-1/2)+1)个double元素。比如对于一个2维实正DFT,输入数组为n0×n1大小,输出复数组大小为n0×floor(n1/2+1)(由对称性),其长度大于实输入数组。所以对于原位运算,输入数组要扩展到n0×2floor(n1/2+1)。如果n1为偶数,扩展为n0×(n1+2);如果n1为奇数,扩展为n0×(n1+1);这些扩展的内存不需要赋初值,它们只用来存放输出数据。

   比如对于3×3的实正DFT,in=[0 2 4;6 1 3;5 7 4],out=[32 0.5+0.86i 0.5-0.86i;-7+5.2i -1-1.73i -8.5-6.06i;-7-5.2i -8.5+6.06i -1+1.73i];out的实际内存为32,0,0.5,0.86,-7,5.2,-1,-1.73,-7,-5.19,-8.5,6.06;即为 3×2的复数组,换算成double类型为3×4,所以如果要进行原位运算,in数组大小必须为3×4,即最后一维(每行)扩展一个double元素。另 外,如果用这个out数组进行3×3的c2r逆变换,将得到实数据[0 18 36;54 9 27;45 63 36],即原始数据的9(n0×n1)倍,这是因为FFTW的逆变换没有归一化。

六、 更多实数据的DFT

   通过一个统一的r2r(real-to-real,实数-实数)接口,FFTW支持其它的一些变换类型,这些变换的输入和输出数组大小相同。这些r2r变换可以分为3个类型:DFT的实 数据输入,complex-Hermitian(指复Hermitian对称)以半复数格式的输出;DCT/DST(离散正余弦变换);DHT(离散 Hartley变换)。接口如下:

fftw_plan fftw_plan_r2r_1d(int n, double *in, double *out,
                                fftw_r2r_kind kind, unsigned flags);
fftw_plan fftw_plan_r2r_2d(int n0, int n1, double *in, double *out,
                                fftw_r2r_kind kind0, fftw_r2r_kind kind1, unsigned flags);
fftw_plan fftw_plan_r2r_3d(int n0, int n1, int n2,
                                double *in, double *out,
                                fftw_r2r_kind kind0,
                                fftw_r2r_kind kind1,
                                fftw_r2r_kind kind2,
                                unsigned flags);
fftw_plan fftw_plan_r2r(int rank, const int *n, double *in, double *out, const fftw_r2r_kind *kind, unsigned flags);

   这里n为数组的物理尺寸。对于多维变换,数组按行优先方式存储(与C++标准相同,与Fortran不同)。由于DFT是可分离变换,所以2维/3维/多维的变换是在每个维度上分别进行变换得到的,每个维度都可指定一个kind参数,指定该维的变换类型。

  1. 半复数格式DFT(HalfComplex-format)

   对于大小为n的1维DFT,输出格式如下:

   r0, r1, r2, ..., rn/2, i(n+1)/2-1, ..., i2, i1

   上述(n+1)/2向下取整。rk是第k个输出的实部,ik是 第k个输出的虚部。对于一个半复数格式的数组hc[n],第k个元素的实部为hc[k],虚部为[n-k];k==0或n/2(n为偶数)情况除外,这两 种情况下虚部为0,不存储。所以对于r2hc(real-half complex,正变换)变换,输入输出数组大小都为n,hc2r(half complex- real,逆变换)变换也是如此。除了数据格式的差异,r2hc和hc2r变换的结果与前述r2c和c2r的变换结果是相同的。

   对于多维比如2维变换,由可分离性,可以先对行 变换,再对列变换,FFTW_R2HC方式行变换的结果是半复数行,如果采用FFTW_R2HC方式进行列变换,需要进行一些数据处理,r2r变换不会自 动处理,需要手动进行,所以对于多维实数据变换,推荐使用普通的r2c/c2r接口。

  2. DCT/DST

   DCT可以认为是实偶对称数据DFT(REDFT,Real-Even DFT), DST可以认为是实奇对称数据DFT(RODFT,Real-Odd DFT)。REDFTab和RODFTab中的a,b为数据移位标志(1表示移位),这些构成了DCT和DST的I-IV类,比较常用的为DCT-II,FFTW支持所有这些类型的变换。

FFTW_REDFT00 (DCT-I): even around j=0 and even around j=n-1.
FFTW_REDFT10 (DCT-II, the DCT): even around j=-0.5 and even around j=n-0.5.
FFTW_REDFT01 (DCT-III, the IDCT): even around j=0 and odd around j=n.
FFTW_REDFT11 (DCT-IV): even around j=-0.5 and odd around j=n-0.5.
FFTW_RODFT00 (DST-I): odd around j=-1 and odd around j=n.
FFTW_RODFT10 (DST-II): odd around j=-0.5 and odd around j=n-0.5.
FFTW_RODFT01 (DST-III): odd around j=-1 and even around j=n-1.
FFTW_RODFT11 (DST-IV): odd around j=-0.5 and even around j=n-0.5.

   对称性只是逻辑意义上的,对物理输入数据没有任何限制。比如对于n=5的REDFT00 (DCT-I),输入数据为abcde,它对应n=8的abcdedcb的常规DFT;对于n=4的REDFT10 (DCT-II),输入数据为abcd,它对应n=8的abcddcba的常规DFT。

   所有这些变换都是可逆的。R*DFT00的逆变 换是R*DFT00,R*DFT10的逆变换是R*DFT01(即DCT和IDCT),R*DFT11的逆变换是R*DFT11。如同DFT一样,这些变 换的结果都没有归一化,所以正变换再逆变换后数据变为原始数据的N倍,N为逻辑DFT大小。比如对于REDFT00变换,N=2(n-1);对于 RODFT00,N=2n。

   注意n=1的REDFT00对应与N=0的DFT,所以它是未定义的(返回值为NULL的fftw_plan)。

   R*DFT01和R*DFT10要比R*DFT11稍微快一些,尤其对于奇数长度数据;而R*DFT00则要慢一些,尤其对于奇数长度数据。

   比如对于in=[1 2 3 4],n=4,N=2n=8。Matlab下dct变换的结果为[5 -2.2304 0 -0.15851];FFTW的结果为(FFTW_REDFT10)out=[20 -6.3086 0 -0.4483415],为matlab结果的√8(√N)倍;用out进行逆dct变换(FFTW_REDFT01)的结果为[8 16 24 32],为原始数据的8(N)倍。

   再比如对于in=[0 2 4;6 1 3;5 7 4]的二维DCT变换,n=3,N=2n=6。Matlab下dct2的变换结果为out_matlab=[10.667 0 0.4714;-4.0825 -2.5 1.4434;0.4714 -2.5981 -3.1667];FFTW的结果为(fftw_plan_r2r_2d(3, 3, in, out, FFTW_REDFT10, FFTW_REDFT10, FFTW_ESTIMATE)out_fftw=[128 0 4;-34.641 -15 8.66;4 -15.588 -19],这与Matlab的结果同样是有差别的。将Matlab的结果变换到FFTW结果的步骤为:

   1. 将out_matlab乘以√6×√6(即√N×√N);

   2. 再将上一步得到的out_matlab的第一行和第一列都乘以√2,因此第一个元素(即左上角的元素)要乘以2。

   第一个是归一化的原因,第二个是FFTW为了将DCT变换与实偶对称FFT相对应的结果。这些对于DCT变换的应用都影响不大。(见此

   最后对out_fftw进行IDCT变换 (fftw_plan_r2r_2d(3, 3, in, out, FFTW_REDFT01, FFTW_REDFT01, FFTW_ESTIMATE),将得到[0 72 144;216 36 108;180 252 144];它是原始数据in的36(N×N,N=6)倍。

  3. 其它

   fftw_malloc考虑了数据对齐,以便使 用SIMD指令加速,所以最好不要用C函数malloc替代,而且不要将fftw_malloc、fftw_free和malloc、free、 delete等混用。尽量使用fftw_malloc分配数组,而不是下面的固定数组,因为固定数组是在栈上分配的,而栈空间较小;还因为这种方式没有考 虑数据对齐,不便应用SIMD指令。

  fftw_complex data[N0][N1][N2];
  fftw_plan plan;
...
  plan = fftw_plan_dft_3d(N0, N1, N2, &data[0][0][0], &data[0][0][0], FFTW_FORWARD, FFTW_ESTIMATE);
...

   对于多维数组也尽量使用fftw_malloc(n0*n1*n285*sizeof(double)),不要使用C的malloc。

  fftw_complex *a_good_array;
  a_good_array = (fftw_complex*) fftw_malloc(5*12*27* sizeof(fftw_complex));


  fftw_complex ***a_bad_array;  /* another way to make a 5x12x27 array */ 
  a_bad_array = (fftw_complex ***) malloc(5 * sizeof(fftw_complex **));

七、 函数参考

  1. 复数DFT

fftw_plan fftw_plan_dft_1d(int n,
                                fftw_complex *in, fftw_complex *out,
                                int sign, unsigned flags);
fftw_plan fftw_plan_dft_2d(int n0, int n1,
                                fftw_complex *in, fftw_complex *out,
                                int sign, unsigned flags);
fftw_plan fftw_plan_dft_3d(int n0, int n1, int n2,
                                fftw_complex *in, fftw_complex *out,
                                int sign, unsigned flags);
fftw_plan fftw_plan_dft(int rank, const int *n,
                             fftw_complex *in, fftw_complex *out,
                             int sign, unsigned flags);

  2. 实数DFT

fftw_plan fftw_plan_dft_r2c_1d(int n,
                                    double *in, fftw_complex *out,
                                    unsigned flags);
fftw_plan fftw_plan_dft_r2c_2d(int n0, int n1,
                                    double *in, fftw_complex *out,
                                    unsigned flags);
fftw_plan fftw_plan_dft_r2c_3d(int n0, int n1, int n2,
                                    double *in, fftw_complex *out,
                                    unsigned flags);
fftw_plan fftw_plan_dft_r2c(int rank, const int *n,
                                 double *in, fftw_complex *out,
                                 unsigned flags);

  3. 实数-实数变换

fftw_plan fftw_plan_r2r_1d(int n, double *in, double *out,
                                fftw_r2r_kind kind, unsigned flags);
fftw_plan fftw_plan_r2r_2d(int n0, int n1, double *in, double *out,
                                fftw_r2r_kind kind0, fftw_r2r_kind kind1, unsigned flags);
fftw_plan fftw_plan_r2r_3d(int n0, int n1, int n2,
                                double *in, double *out,
                                fftw_r2r_kind kind0,
                                fftw_r2r_kind kind1,
                                fftw_r2r_kind kind2,
                                unsigned flags);
fftw_plan fftw_plan_r2r(int rank, const int *n, double *in, double *out, const fftw_r2r_kind *kind, unsigned flags);

  4. 实数-实数变换类型

   对于大小为n的下列变换,对应的逻辑DFT大小为N,N用来进行归一化。FFTW的变换没有归一化,正变换后再逆变换为原数据的N倍(不是n倍),对于多维变换,为N的乘积(N0*N1*N285)。下表列出了变换类型及其对应的逻辑大小N及逆变换:

FFTW_R2HC computes a real-input DFT with output in halfcomplex format, i.e. real and imaginary parts for a transform of size n stored as:r0, r1, r2, ..., rn/2, i(n+1)/2-1, ..., i2, i1 (Logical N=n, inverse is FFTW_HC2R.)
FFTW_HC2R computes the reverse of FFTW_R2HC, above. (Logical N=n, inverse is FFTW_R2HC.)
FFTW_DHT computes a discrete Hartley transform. (Logical N=n, inverse is FFTW_DHT.)
FFTW_REDFT00 computes an REDFT00 transform, i.e. a DCT-I. (Logical N=2*(n-1), inverse is FFTW_REDFT00.)
FFTW_REDFT10 computes an REDFT10 transform, i.e. a DCT-II (sometimes called the DCT). (Logical N=2*n, inverse is FFTW_REDFT01.)
FFTW_REDFT01 computes an REDFT01 transform, i.e. a DCT-III (sometimes called the IDCT, being the inverse of DCT-II). (Logical N=2*n, inverse is FFTW_REDFT=10.)
FFTW_REDFT11 computes an REDFT11 transform, i.e. a DCT-IV. (Logical N=2*n, inverse is FFTW_REDFT11.)
FFTW_RODFT00 computes an RODFT00 transform, i.e. a DST-I. (Logical N=2*(n+1), inverse is FFTW_RODFT00.)
FFTW_RODFT10 computes an RODFT10 transform, i.e. a DST-II. (Logical N=2*n, inverse is FFTW_RODFT01.)
FFTW_RODFT01 computes an RODFT01 transform, i.e. a DST-III. (Logical N=2*n, inverse is FFTW_RODFT=10.)
FFTW_RODFT11 computes an RODFT11 transform, i.e. a DST-IV. (Logical N=2*n, inverse is FFTW_RODFT11.)

八、 其它

  1. 数据类型

   FFTW有三个版本的数据类型:double、float和long double,使用方法如下:

  • 链接对应的库(比如libfftw3-3、libfftw3f-3、或ibfftw3l-3)
  • 包含同样的头文件fftw3.h
  • 将所有以小写"fftw_"开头的名字替换为"fftwf_"(float版本)或"fftwl_"(long double版本)。比如将fftw_complex替换为fftwf_complex,将fftw_execute替换为fftwf_execute等。
  • 所有以大写"FFTW_"开头的名字不变
  • 将函数参数中的double替换为float或long double

   最后,虽然long double是C99的标准,但你的编译器可能根本不支持该类型,或它并不能提供比double更高的精度。

  2. 用同一个fftw_plan执行多个数据的变换

   前面说过可以利用同一个fftw_plan通过对输入数据赋不同值来实现不同的变换,实际上还可以利用同一个fftw_plan实现对不同输入输出数据的变换,也就是说可以有多个输入输出数据数组,各自进行变换,互不影响。当然这要满足一定的条件:

  • 输入/输出数据大小相等。
  • 变换类型、是否原位运算不变。
  • 对split数组(指实虚部分开),实部和虚部的分割方式与方案创建时相同。
  • 数组的对齐方式相同。如果都是用fftw_malloc分配的则此项条件满足,除非使用 FFTW_UNALIGNED标志。

   如果想对新数组,比如大小相等的一批数组执行变换,可以使用以下接口:

     void fftw_execute_dft(
          const fftw_plan p,
          fftw_complex *in, fftw_complex *out);
     
     void fftw_execute_split_dft(
          const fftw_plan p,
          double *ri, double *ii, double *ro, double *io);
     
     void fftw_execute_dft_r2c(
          const fftw_plan p,
          double *in, fftw_complex *out);
     
     void fftw_execute_split_dft_r2c(
          const fftw_plan p,
          double *in, double *ro, double *io);
     
     void fftw_execute_dft_c2r(
          const fftw_plan p,
          fftw_complex *in, double *out);
     
     void fftw_execute_split_dft_c2r(
          const fftw_plan p,
          double *ri, double *ii, double *out);
     
     void fftw_execute_r2r(
          const fftw_plan p,
          double *in, double *out);

   这些函数的执行不会修改原始plan,并且可以和fftw_execute混合使用。

  3. 多线程FFTW

   FFTW可以多线程执行,但是多线程存在线程同步问题,这可能会降低性能。所以除非问题规模非常大,一般并不能从多线程中获益。

  4. FFTW变换公式

在这里插入图片描述


本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

信号处理算法(4):全球最快的傅里叶变换算法(FFTW) 的相关文章

  • 照片马赛克算法。如何在给定基本图像和瓷砖列表的情况下创建马赛克照片?

    Hy 我要做的是创建一个程序 使用 C 或 C 它将 24 位 像素位图和图像集合作为输入 我必须创建一个马赛克图像 类似于使用库的输入图像给定的图像 创建与输入类似的马赛克照片 到目前为止 我可以访问输入的图像像素及其颜色 但我有点卡住了
  • 需要解释搜索最小大和的算法

    我正在解决 Codility 问题作为练习 但无法回答其中一个问题 我在互联网上找到了答案 但我不明白这个算法是如何工作的 有人可以引导我逐步完成它吗 这是问题 You are given integers K M and a non em
  • O(1) 算法确定节点是否是多路树中另一个节点的后代?

    想象一下下面的树 A B C D E F 我正在寻找一种方法来查询 F 是否是 A 的后代 注意 F 不需要是directA 的后代 在这种特殊情况下这是正确的 只需要针对更大的潜在后代节点池测试有限数量的潜在父节点 当测试一个节点是否是潜
  • 将名称字符串编码为唯一的数字

    我有一大堆名字 数以百万计 他们每个人都有一个名字 一个可选的中间名和一个姓氏 我需要将这些名称编码为唯一代表这些名称的数字 编码应该是一对一的 即一个名称只能与一个数字相关联 一个数字只能与一个名称相关联 对此进行编码的明智方法是什么 我
  • 依赖解析算法

    我正在编写一个包管理器 为此我希望依赖项解析尽可能强大 每个包都有一个版本列表 每个版本包含以下信息 具有可比性的 ID 依赖关系 软件包列表以及每个软件包的一组可接受的版本 冲突 软件包列表以及每个软件包的一组与该版本一起导致问题的版本
  • pytesseract 无法从图像中识别复杂的数学公式

    我在用pytesseractpython 中的模块 pytesseract从图像中识别文本 但它不适用于包含复杂数学公式 例如根 推导 积分数学问题或方程 的图像 代码2 py Import modules from PIL import
  • 如何衡量字符串的复杂度?

    我有一些长字符串 1 000 000 个字符 每个字符串仅包含定义字母表中的符号 例如 A 1 2 3 示例字符串 string S1 1111111111 meta complexity 0 string S2 1111222333 me
  • 2D形状识别与解析算法

    我正在寻找一种算法 用于从给定的一组 x y 点检测简单形状 如矩形 三角形 正方形和圆形 我还在寻找一种方法 一旦检测到 将路径转换为更干净的形状 我已经查遍了互联网 但没有找到任何 简单 的方法 几乎所有这些对于我的简单实现来说都是高级
  • 如何检测图像是否像素化

    之前有人在 SO 上提出过这样的问题 在Python中检测像素化图像 https stackoverflow com questions 12942365 detecting a pixelated image in python还有关于q
  • 机器人探索算法

    我正在尝试为机器人设计一种算法 试图找到位于未知位置的旗帜 该旗帜位于一个包含障碍物的世界中 机器人的任务是夺取旗帜并将其带到他的基地 代表他的起始位置 机器人在每一步只能看到有限的邻域 他事先不知道世界是什么样子 但他有无限的内存来存储已
  • 关于逻辑/算法的想法以及如何防止线程写入 Sql Server 中的竞争

    我有以下逻辑 public void InQueueTable DataTable Table int incomingRows Table Rows Count if incomingRows gt RowsThreshold async
  • 为什么Python中pop()的大O与pop(0)不同[重复]

    这个问题在这里已经有答案了 他们不应该都是O 1 因为从 Python 列表中的任何位置弹出一个元素涉及销毁该列表并在新的内存位置创建一个元素 蟒蛇的list实现使用动态调整大小的 Carray在引擎盖下 删除元素usually要求您移动后
  • 整数除法性质

    下面的整数算术性质成立吗 m n l m n l 起初我以为我知道答案 不成立 但现在不确定 它适用于所有数字还是仅适用于某些条件 即n gt l 该问题涉及计算机算术 即q n m q m n 忽略溢出 Case1 assume m kn
  • 查找重叠事件/时间的算法

    在处理自定义日历时 我不知道如何找到与任何其他时间段重叠的时间段 时段从 0 点至 720 点 上午 9 点至晚上 9 点 每个像素代表一分钟 var events id 1 start 0 end 40 an event from 9 0
  • 将数字 n 拆分为 k 个不同数字的总和

    我有一个数字 n 我必须将它分成 k 个数字 使得所有 k 个数字都是不同的 k 个数字的总和等于 n 并且 k 最大 例如 如果 n 为 9 则答案应为 1 2 6 如果 n 为 15 则答案应为 1 2 3 4 5 这就是我尝试过的 v
  • 带有元数据的 scipy kdtree

    我目前正在寻找一种方法来构建几个 kd 树以快速查询一些 n 维数据 但是 我对 scipy KD 树算法有一些问题 我的数据包括id gt data somedata coordinate x y 我希望能够基于坐标和 k 最近邻居的 i
  • 最低共同祖先算法

    所以我一直在研究实现最低共同祖先算法 我研究了许多不同的算法 主要是 Trajan 解决方案的变体或 RMQ 的变体 我正在使用非二叉树 我的树经常会在查询之间发生变化 因此预处理不一定值得 树的节点数不应超过 50 75 个 我想知道的是
  • java中的Anagram算法

    我想做字谜算法但是 这段代码不起作用 我的错在哪里 例如 des 和 sed 是字谜 但输出不是字谜 同时我必须使用字符串方法 不是数组 public static boolean isAnagram String s1 String s2
  • 算法 - 树中所有节点的最大距离

    所以 找到树中两个节点之间的最长路径相当容易 但我想要的是找到从节点出发的最长路径x到树中的另一个节点 对于所有x 这个问题也可以用以下方式表达 计算从给定的树中可以生成的所有有根树的高度 One way of course is to j
  • 查找数组中的重叠数据

    我们正在编写一个 C 应用程序 它将有助于删除不必要的数据重复器 只有在以下情况下才可以移除中继器 all它接收到的数据被其他中继器接收 我们第一步需要做的事情解释如下 例如 我有 int 数组的集合 A 1 2 3 4 5 b 2 4 6

随机推荐

  • JavaScript实现WebService的http的Post请求

    javascript 这个脚本实现Webservice调用 function AjaxFunc var url http localhost MyService Service asmx var method DollarConvertTo
  • 使用Jmeter做压力测试,参数化

    1 首先在工作台下添加一个线程组 测试计划右键 添加 线程 用户 线程组 根据需求填写线程组信息 根据测试数据量填写 线程数也就是并发数 下面的调度时间代表规定的时间内完成并发 2 添加HTTP请求 在线程组下右键 添加 取样器 HTTP请
  • 微信小程序image组件的mode总结+介绍(包含heightFix)

    2 10 3版本后 微信小程序的图片即image组件新增了heightFix属性 mode 总共具有14种属性 满足各种情况的放置需要 14种属性可以分为两大类 一种是完全保留的缩放属性 一种是裁剪属性 原图 缩放属性 scaleToFil
  • 常见的List接口的实现类

    常见的List接口的实现类 ArrayList 数组实现 查询快 增删慢 轻量级 线程不安全 LinkedList 双向链表实现 增删快 查询慢 线程不安全 Vector 数组实现 重量级 线程安全 使用少 ArrayList实现类 pub
  • cesium-添加点线面可以动可编辑

    使用 const drawEntities new CesiumEntityDraw viewer drawEntities startDraw 需要绘制的类型 CesiumEntityDraw ts文件 import Cesium fro
  • RabbitMQ编程模型

    Hello World 在本教程的这一部分中 我们将用 Java 编写两个程序 发送单个消息的生产者和接收消息并将其打印出来的消费者 我们将忽略 Java API 中的一些细节 专注于这个非常简单的事情 以便开始 这是一个 Hello Wo
  • vue3的element-plus的el-dialog的样式加上scoped发现:deep()不再生效解决方案

    想要将 弹框 el dialog header el dialog body 的padding值设为0 但是 el dialog 用了 append to body 属性情况下 官网解释 Dialog 自身是否插入至 body 元素上 嵌套
  • C语言入门教程之三天入门C语言(第二天结构体与指针使用)

    三天学习C语言 第二步 一 C语言中的几种集合的表达形式 数组类型 数组扩展 结构体的表示 联合体的表示 二 sizeof 的使用 三 指针的使用 指针变量 未完待续 指针与数组 一 C语言中的几种集合的表达形式 在数学中一般一组数据的集合
  • 前端面试100道

    幕布链接 完整版 面试终极 幕布 目录 1 弹性布局的认识 2 Var和let有什么区别 3 和 的区别 4 Js事件 5 Vue计算属性 6 Vue采用指令 7 Html中的浮动怎么使用 8 箭头函数 9 Js的this指向 10 Cal
  • css兼容浏览器的各种背景渐变

    需要兼容各浏览要注意的是 必须加上浏览器的私有前缀 否则一般都是不生效的 浏览器的私有前缀主要是解决不同浏览器的兼容性问题 webkit 谷歌浏览器 安卓 moz 火狐浏览器 o opera浏览器 ms ie浏览器 首先来个简单的也最常见的
  • 父组件更新,子组件未更新

    囧 问题 项目中 渲染的数据为对象数组arr obj obj obj 业务需要要给某个对象obj增加一个属性key arr forEach obj gt obj key 囧 但是当在父组件中修改这个属性后 子组件并没有随着更新 原因 没有通
  • 软件测试笔试题含答案

    目录 一 填空 1 系统测试使用 C 技术 主要测试被测应用的高级互操作性需求 而无需考虑被测试应用的内部结构 2 单元测试主要的测试技术不包括 B 3 A 的目的是对最终软件系统进行全面的测试 确保最终软件系统满足产品需求并且遵循系统设计
  • ReactNative中使用WebSocket

    首先说说发布订阅这种设计模式 这种模式我给它起了个别名叫遥控炸弹 很多朋友理解不了这种模式 那 举个例子 张三是个法外狂徒 它要去复仇 他想去炸掉仇家的房子 他来到仇家所在的小区 拿出自己准备的炸弹 监听 丢进仇家的屋里 页面 等他走出小区
  • Hadoop3.x集成HBase

    HBase作为Hadoop家族中实现高并发的利器 我们来看看怎么进行集成 1 下载并上传到服务器 目前使用2 3 5版本 wget https mirrors bfsu edu cn apache hbase 2 3 5 hbase 2 3
  • 软件工程—软件测试

    前言 软件测试是为了发现错误而执行程序的过程 是对需求分析 设计和编码3个阶段进行的最终复审 下面介绍了软件测试的原则 方法过程等 测试用例的设计 测试的步骤还有软件的调试技术 一 软件测试 软件测试的目的 1 测试是程序的执行过程 目的在
  • QT Creator 自定义控件的方法和步骤

    QT版本 QT 6 2 3 QT Creator6 0 2 Community 是MSVC编写 要注意看哦 编写自定义控件的时候也要用 1 打开QT Creator 点击 文件 gt 新建文件或项目 gt 其他项目 gt QT4设计师自定义
  • 微信小程序在wxml中使用函数

    方法一 在wxml中直接添加模块 就可以在wxml中直接引用 举个例子
  • VS2022 安装 .NET Framework 4.0 和 .NET Framework 4.5 的方法

    前言 2022年5月27日 刚刚把VS2019升级到了VS2022 安装时已经不提供 NET Framework 4 0和 NET Framework 4 5的目标框架了 打开VS也提示不支持目标框架 解决方法 1 下载 NET Frame
  • tcp的半连接与完全连接队列

    队列及参数 server端的半连接队列 syn队列 在三次握手协议中 服务器维护一个半连接队列 该队列为每个客户端的SYN包开设一个条目 服务端在接收到SYN包的时候 就已经创建了request sock结构 存储在半连接队列中 该条目表明
  • 信号处理算法(4):全球最快的傅里叶变换算法(FFTW)

    本文大部分内容转载自博客 congwulong https blog csdn net congwulong article details 7576012 FFTW Fastest Fourier Transform in the Wes