为了回答我自己的问题,我对分裂基FFT(SR-FFT)做了一些研究,发现了Anthony Blake的一篇有趣的论文等等. 标题:“南方最快的傅立叶变换”
https://www.cs.waikato.ac.nz/~ihw/papers/13-AMB-IHW-MJC-FastFourier.pdf。本文概述了用SR-FFT加速FFT的方法,并参考了Blake博士论文https://www.cs.waikato.ac.nz/~ihw/PhD_theses/Anthony_Blake.pdf。这包含了附录B清单25中SR-FFT的C代码,如下所示:typedef complex float data_t;
#define W(N,k) (cexp(-2.0f * M_PI * I * (float)k / (float)N))
data_t *LUT1;
data_t *LUT3;
void splitfft(data_t *in, data_t *out, int log2stride, int stride, int N) {
if(N == 1) {
out[0] = in[0];
}else if(N == 2) {
out[0] = in[0] + in[stride];
out[N/2] = in[0] - in[stride];
}else{
splitfft(in, out, log2stride+1, stride << 1, N >> 1);
splitfft(in+stride, out+N/2, log2stride+2, stride << 2, N >> 2);
splitfft(in+3*stride, out+3*N/4, log2stride+2, stride << 2, N >> 2);
{
data_t Uk = out[0];
data_t Zk = out[0+N/2];
data_t Uk2 = out[0+N/4];
data_t Zdk = out[0+3*N/4];
out[0] = Uk + (Zk + Zdk);
out[0+N/2] = Uk - (Zk + Zdk);
out[0+N/4] = Uk2 - I*(Zk - Zdk);
out[0+3*N/4] = Uk2 + I*(Zk - Zdk);
}
int k;
for(k=1;k
data_t Uk = out[k];
data_t Zk = out[k+N/2];
data_t Uk2 = out[k+N/4];
data_t Zdk = out[k+3*N/4];
data_t w1 = LUT1[k<
data_t w3 = LUT3[k<
out[k] = Uk + (w1*Zk + w3*Zdk);
out[k+N/2] = Uk - (w1*Zk + w3*Zdk);
out[k+N/4] = Uk2 - I*(w1*Zk - w3*Zdk);
out[k+3*N/4] = Uk2 + I*(w1*Zk - w3*Zdk);
}
}
}
void fft_init(int N) {
LUT1 = malloc(N/4 * sizeof(data_t));
LUT3 = malloc(N/4 * sizeof(data_t));
int i;
for(i=0;i
for(i=0;i
}
经过一些努力,我能够将其转换为Python并使其正常工作。然后我在Python中做了一些改进,以加快它的速度:(1)开始时的N==1和N==2的情况被N==4和N==8替换,以便将递归调用的数量减少75%,循环的数量减少大约8%。(2) 正如我在上面的文章中所述,循环中连续的旋转因子是通过乘法生成的。(3) 这样就可以使用字典来存储预先计算的旋转因子,从而将其数量从N/4减少到log2(N)-2,并加快生成速度。(4) 通过对N==4和N==8情况下生成的术语进行适当的排序,以及使用Python中创建新对象的列表切片,可以重用输入数组来消除out数组。(5) 为了简化Python实现,删除了stride&log2stride这两个变量。更好的SR-FFT算法和Python代码优化相结合,比我原来的文章中的FFT速度提高了1.66倍。这是生成的Python代码:
^{pr2}$
在主代码中,这是通过以下方式调用的:N = len(X)
fft_init(N)
F = fft_cp(X, N)
和以前一样,两个实际的数据输入可以合并和分离,以执行一个调用的2-fft。在
这个答案几乎达到了我的目标,速度比我原来的帖子快2倍。我会很高兴得到一个更好的答案,得到改善超过2倍的门槛。在