关于《算法的乐趣》傅立叶变换一章的补充

一些热心读者反馈在介绍快速傅立叶变换(FFT)部分的描述和代码不一致,比如某位读者反馈前面正文介绍的是DIT-FFT,但是给出的代码实现确是DIF-FFT,让人困惑,本文准备补充一下相关的内容。

DIT-FFT和DIF-FFT,一个是按时间抽取计算(Decimation-In-Time),一个是按频率抽取计算(Decimation-In-Frequency),是两种等价的FFT算法,本章内容主要集中在离散傅立叶变换算法的使用实例,比如频谱和均衡器,因此并没有具体描述这二者的差异,只是在242页中间一段文字中做了说明,原文如下:

“FFT算法对这个位置关系的处理有两种方式,一种是如图15-4所示,在开始蝶形运算之前就对原始数据按照码位关系进行排序,则计算后可直接得到与原始序列一致的输出。这种方式又称为原位运算方式。另一种方式是直接进行蝶形运算,然后按照码位关系对运算后的输出结果重新排序。”

这段文字其实存一个错误,在此需要更正一下,实际上无论是DIT-FFT还是DIF-FFT,都可以实现为原位运算方式。

DIT-FFT和DIF-FFT的主要差异就是蝶形运算的方式,有的资料说属否需要对输入数据倒序重排也是DIT-FFT和DIF-FFT的差异,这一点是仁者见仁,智者见智了,许多高效的算法都可以通过巧妙的循环控制避免这个重排操作,因此这应该不算是DIT和DIF的主要差异。蝶形运算的差异主要体现在参与蝶形运算的两个点的数据与旋转因子的乘法是在减法之前还是在减法之后,这句话理解起来有点困难,可以通过蝶形运算关系图来理解。书中的图15-3是DIT-FFT的蝶形运算关系图,可以看出 X2(n) 先与旋转因子进行了乘法计算,然后又 X1(n) 分别与乘法计算的结果做加法和减法得到下一级的 X1(n) X2(n) ,因为之前已经进行过倒序重排操作,因此参与计算前的 X2(n) 实际上就是X(n+ N/2),原位计算后得到对应结果就是下一级的 X1(n) X2(n) 。本文在此给出DIF-FFT的蝶形运算关系图,如图(1)所示, X1(n) X2(n) 先做减法,然后将减法的结果与旋转因子相乘得到下一级的 X2(n)
关于《算法的乐趣》傅立叶变换一章的补充_第1张图片
图(1) DIF蝶形运算示意图

根据以上分析,本文补充一个DIT_FFT的算法实现,大家可以对比一下书中给出的DIF_FFT算法,可以看到蝶形运算部分的明显区别。

void DIT_FFT(FFT_HANDLE *hfft, COMPLEX *TD2FD)
{
    int power = NumberOfBits(hfft->count); //power为蝶形运算级数

    //重新排序
    ResortSequence(TD2FD, hfft->count, power);

    for(int k = 0; k < power; k++)  //第k级蝶形运算
    {
        int butterfly = 1 << (k + 1);
        int wtp = 1 << (power - k - 1);
        for(int j = 0; j < (1 << k); j++)  //蝶形运算分组
        {
            for(int i = j; i < hfft->count; i += butterfly)
            {
                int b = i + butterfly / 2;
                COMPLEX t = TD2FD[b]*hfft->wt[j * wtp];
                TD2FD[b] = TD2FD[i] - t; 
                TD2FD[i] = TD2FD[i] + t; 
            }
        }
    }
}

你可能感兴趣的:(代码,算法,fft,变换)