热门问题
时间线
聊天
视角
库利-图基快速傅里叶变换算法
来自维基百科,自由的百科全书
Remove ads
库利-图基快速傅里叶变换算法(英语:Cooley–Tukey FFT algorithm)[1]是最常见的快速傅里叶变换算法。这一方法以分治法为策略递归地将长度为N = N1N2的DFT分解为长度分别为N1和N2的两个较短序列的DFT,以及与旋转因子的复数乘法。这种方法以及FFT的基本思路在1965年詹姆斯·库利和约翰·图基合作发表《An algorithm for the machine calculation of complex Fourier series》之后开始为人所知。但后来发现,实际上这两位作者只是重新发明了高斯在1805年就已经提出的算法(此算法在历史上数次以各种形式被再次提出)。
库利-图基算法最有名的应用,是将序列长为N的DFT分割为两个长为N/2的子序列的DFT,因此这一应用只适用于序列长度为2的幂的DFT计算,即基2-FFT。实际上,如同高斯和库利与图基都指出的那样,库利-图基算法也可以用于序列长度N为任意因数分解形式的DFT,即混合基FFT,而且还可以应用于其他诸如分裂基FFT等变种。尽管库利-图基算法的基本思路是采用递归的方法进行计算,大多数传统的算法实现都将显示的递归算法改写为非递归的形式。另外,因为库利-图基算法是将DFT分解为较小长度的多个DFT,因此它可以同任一种其他的DFT算法联合使用。
Remove ads
复杂度
快速傅立叶变换的复杂度为,分析可见下方架构图部分,级数为而每一级的复杂度为,故复杂度为
Remove ads
蝶形结
在FFT演算法中,使用到的蝶形结可以分为Cooley-Tukey和Gentleman-Sande两种,而他们进行的运算互为对方的逆运算,同时对应了DFT和IDFT当中会使用到的运算单元。


在Cooley-Tukey蝶形结当中,上下两列的输出分别为:
而在Gentleman–Sande蝶形结当中,上下两列的输出分别为:
可以注意到在进行完一次Cooley-Tukey蝶形结和Gentleman–Sande蝶形结的运算之后,原先输入的(a, b)会变成(2a, 2b),而这项常数倍的差异可以在所有的蝶形结运算结束后再处理,不需要直接改变这两项蝶形结运算单元的常数。
以下是这两种蝶形运算应用在快速傅立叶转换中性质的比较。
Remove ads
- 组成:一个加法器、一个减法器、和一个乘法器。
- 输入顺序:以位元反转顺序(bit-reversed order)输入资料。
- 输出顺序:产生以正常顺序(normal order)输出的结果,对应到分时快速傅立叶转换(Decimation-in-Time FFT)。
- 使用时机:由于输入非按照正常顺序,输入端资料流控制较DIF-FFT更为复杂。
- 组成:一个加法器、一个减法器、和一个乘法器。
- 输入顺序:以正常顺序(normal order)输入资料。
- 输出顺序:产生以位元反转顺序(bit-reversed order)输出的结果,对应到分频快速傅立叶转换(Decimation-in-Frequency FFT)。
- 使用时机:由于输入会按照正常顺序,输入端资料流控制较DIT-FFT更为简单。
而Utsav Banerjee等人在2019年发表的〈An Energy-Efficient Configurable Lattice Cryptography Processor for the Quantum-Secure Internet of Things〉[2]提出了一个整合式蝶形运算单元的架构,同时包含了Cooley-Tukey蝶形结和Gentleman–Sande蝶形结的运算,以满足在硬体实作上同时兼顾两者的需求。
Remove ads
- 组成:两个加法器、两个减法器、一个乘法器、和四个数据多工器(MUX)。
- 原理:借由数据多工器(MUX)使得每次只有其中一个加法器和一个减法器的输出会被使用,以此呈现原先Cooley-Tukey蝶形结和Gentleman–Sande蝶形结中的运算,在Cooley-Tukey蝶形结中会跳过前半部分的加法器和减法器,使得乘法器放置在有效的加法器和减法器之前,而Gentleman–Sande蝶形结则正好相反,跳过后半部分的加法器和减法器,使得乘法器放置在有效的加法器和减法器之后。而至于是要呈现哪一个运算单元的特性就可以根据当下输入输出等情况做选择,借此弥补硬体实作上和软体设计相比缺乏弹性的问题,同时避免硬体资源的浪费。
- 优点:
- 节省资源:通过整合 Cooley-Tukey 和 Gentleman–Sande 的蝶形结构,减少硬体面积。
- 提升效能:避免处理位元反转(bit reversal)等复杂操作,提升运算效率。
- 高度弹性:支援两种变换类型以适用于多种不同应用情境。
- 缺点:
Remove ads
时域/频域抽取法
在FFT演算法中,针对输入做不同方式的分组会造成输出顺序上的不同。如果我们使用时域抽取(Decimation-in-time),那么输入的顺序将会是位元反转排列(bit-reversed order),输出将会依序排列。但若我们采取的是频域抽取(Decimation-in-frequency),那么输出与输出顺序的情况将会完全相反,变为依序排列的输入与位元反转排列的输出。
我们可以将DFT公式中的项目在时域上重新分组,这样就叫做时域抽取(Decimation-in-time),在这里将会被代换为旋转因子(twiddle factor)。
在这边我们要注意的是,我们所替换的G[k]与H[k]具有周期性:
还注意到系数具有对称性:
上述的推导可以划成下面的图:
划红框处所示的点DFT架构如下图所示:
划红框处所示的点DFT架构如下图所示:
下图是一个8点DIT FFT的完整架构图。
Remove ads
我们可以将DFT公式中的项目在频域上重新分组,这样就叫做频域抽取(Decimation-in-frequency)。
首先先观察在频域上偶数项的部分:
再观察在频域上奇数项的部分:
上述的推导可以画成下面的图:
更进一步的拆解-point DFT的架构
下图为8点FFT下-point DFT的架构
总结上述架构,完整的8点DIF FFT架构图为
Remove ads
单一基底
利用库利-图基演算法进行离散傅立叶拆解时,能够依需求而以2, 4, 8…等2的幂次方为单位进行拆解,不同的拆解方法会产生不同层数快速傅里叶变换的架构,基底越大则层数越少,复数乘法器也越少,但是每级的蝴蝶形架构则会越复杂,因此常见的架构为2基底、4基底与8基底这三种设计。
2基底-快速傅立叶演算法(Radix-2 FFT)是最广为人知的一种库利-图基快速傅立叶演算法分支。此方法不断地将N点的FFT拆解成两个'N/2'点的FFT,利用旋转因子的对称性借此来降低DFT的计算复杂度,达到加速的功效。
而其实前述有关时域抽取或是频域抽取的方法介绍,即为2基底的快速傅立叶转换法。以下展示其他种2基底快速傅立叶演算法的连线方法,此种不规则的连线方法可以让输出与输入都为循序排列,但是连线的复杂度却大大的增加。
Remove ads
4基底快速傅立叶变换演算法则是承接2基底的概念,在此里用时域抽取的技巧,将原本的DFT公式拆解为四个一组的形式:
在这里再利用的特性来进行与2基数FFT类似的化减方法,以降低演算法复杂度。
Remove ads
在库利-图基算法里,使用的基底(radix)越大,复数的乘法与记忆体的存取就越少,所带来的好处不言而喻。但是随之而来的就是实数的乘法与实数的加法也会增加,尤其计算单元的设计也就越复杂,对于可应用FFT之点数限制也就越严格。在表中我们可以看到在不同基底下所需的计算成本。
在DFT的公式中,我们重新定义x=[x(0),x(1),…,x(N-1)]T, X=[X(0),X(1),…,X(N-1)]T,则DFT可重写为X=FN‧x。FN是一个N×N的DFT矩阵,其元素定义为[FN]ij=WNij(i,j ∈ [0,N-1]),当N=8时,我们可以得到以下的F8矩阵并且进一步将其拆解。
在拆解成三个矩阵相乘之后,我们可以将复数运算的数量从56个降至24个复数的加法。底下是8基底的SFG。要注意的是所有的输出与输入都是复数的形式,而输出与输入的排序也并非规律排列,此种排列方式是为了要达到接线的最佳化。
混合基底
在2/8基底的演算法中,我们可以看到我们对于偶数项的输出会使用2基底的分解法,对于奇数项的输出采用8基底的分解法。这个做法充分利用了2基底与4基底拥有最少乘法数与加法数的特性。当使用了2基底的分解法后,偶数项的输出如下所示。
奇数项的输出则交由8基底分解来处理,如下四式所述。
以上式子就是2/8基底的FFT快速演算法。在架构图上可化为L型的蝴蝶运算架构,如下图所示。
而下图表示的是一个64点的FFT使用2/8基底的架构图。虽然2/8基底的演算法缩减了的乘法量,但是这种演算法最大的缺点是跟其他固定基底或是混合基底比较起来,他的架构较为不规则。所以在硬体上比4基底或是2基底更难实现。
为了改进Radix 2/8在架构上的不规则性,我们在这里做了一些修改,如下图4.。此修改可让架构更加规则,且所使用的加法器与乘法器数量更加减少,如下表所示。
在这里我们最小的运算单元称为PE(Process Element),PE内部包含了2/8基底、2/4基底、2基底的运算,简化过的信号处理流程与蝴蝶型架构图可见下图
基底的选择越大会造成蝴蝶形架构更加复杂,控制电路也会复杂化。因此Shousheng He和Mats Torkelson在1996提出了一个2^2基底的FFT演算法,利用旋转因子的特性:。而–j的乘法基本上只需要将被乘数的实部虚部对调,然后将虚部加上负号即可,这样的负数乘法被定义为'简单乘法',因此可以用很简单的硬体架构来实现。利用上面的特性,22基底FFT能用串接的方式将旋转因子以4为单位对DFT公式进行拆解,将蝴蝶形架构层数降到log4N,大幅减少复数乘法器的用量,而同时却维持了2基底蝴蝶形架构的简单性,在效能上获得改进。22基底DIF FFT演算法的拆解方法如下列公式所述:
N点DFT公式:
利用线性映射将n与k映射到三个维度上面
然后套用Common Factor Algorithm(CFA)
而蝴蝶型架构会变成以下形式
利用旋转因子的特性,可以观察出
再将此公式带入原式中可以得到
如上述公式所示,原本的DFT公式会被拆解成多个,而又可分为BF2I与BF2II两个阶层,分别会对应到之后所介绍的两种硬体架构。
一个16点的DFT公式经过一次上面所述之拆解之后可得下面的FFT架构
可以看出上图的架构保留了2基底的简单架构,然而复数乘法却降到每两级才出现一次,也就是次。而BF2I以及BF2II所对应的硬体架构下图:
其中BF2II硬体单元中左下角的交叉电路就是用来处理-j的乘法。
一个256点的FFT架构可以由下面的硬体来实现:
其中图下方的为一7位元宽的计数器,而此架构的控制电路相当单纯,只要将计数器的各个位元分别接上BF2I与BF2II单元即可。
下表将2基底、4基底与22基底演算法做一比较,可以发现22基底演算法所需要的乘法气数量为2基底的一半,加法弃用量是4基底的一半,并维持一样的记忆体用量和控制电路的简单性。
如上所述,22演算法是将旋转因子视为一个简单乘法,进而由公式以及硬体上的化简获得硬体需求上的改进。而借由相同的概念,Shousheng He和Mats Torkelson进一步将旋转因子的乘法化简成一个简单乘法,而化简的方法将会在下面讲解。
在2基数FFT演算法中的基本概念是利用旋转因子的对称性,4基数演算法则是利用 的特性。但是我们会发现在这些旋转因子的对称特性中─
─并没有被利用到。主要是因为的乘法运算会让整个FFT变得复杂,但是如果借由近似的方法,我们便可以将此一运算化简为12个加法。
我们可以从上式注意到,可以被近似为五个加法的结果,所以就可以被简化为只有六个加法,再算入实部与虚部的计算,总共只需12个加法器就可以运用到此一简化特性。
经由与22基底类似的推导,并用串接的方式将旋转因子以8为单位对DFT公式进行拆解,23基底FFT演算法进一步将复数乘法器的用量缩减到log8N,并同时维持硬体架构的简单性。 推导的方法与22基底相当类似。借由这样的方法,23基底能将乘法器的用量缩减到2基底的1/3,并同时维持一样的记忆体用量以及控制电路的简单性。
一般性分解[4]
除了常在应用中见到与相关基底的拆解法,对于更加一般性的点离散傅立叶变换问题, 我们也有办法在理论上进行拆解,将问题化为数个与点离散傅立叶变换问题,并可对计算量进行估计。
为了避免之后的符号混淆,我们先将置换为,也就是说接著要将点离散傅立叶变换, 想办法拆解为数个与点离散傅立叶变换问题。
接著定义要拆分的问题,要拆分的问题为点离散傅立叶变换,将转换至:
直观地说,这个点离散傅立叶变换,将由作为参数的函数,转换成由作为参数的函数, 并且都有个可能的数值。
待定义好要拆分的问题,便可以开始讨论如何进行拆分,基本概念是将有个可能的数值的, 分别化为个使用两个参数进行描述的函数,并借此将原问题化为二维度离散傅立叶变换, 便可使用数个较小的离散傅立叶变换问题描述整个过程。
而一种很直觉的转换方式,便是透过将分别除以, 以商数与馀数来做为参数描述的值:
其中作为将除以的商数,与作为除以的馀数的相同, 具有个可能数值,同理与有个可能数值。
将上述的参数代换及带入原式,可以得到:
将右式的指数部分乘开并分项化简可以得到:
最后透过与,可以得到:
观察上式,并加上括号辅助厘清运算顺序我们可以得到:
最内层的运算可以视为将双参数函数中的一个参数,透过离散傅立叶变换取代为由描述, 得到一个新函数(这步因为对每个不同,都需要做一次将取代为的转换, 共需要个点离散傅立叶变换):
下一层的运算则可视为单纯的乘法,将与相乘,得到 (这步需要的计算量视的特殊性而会有变化):
最后的运算可以视为将函数中,透过离散傅立叶变换取代为由描述, 得到一个新函数(这步因为对每个不同,都需要做一次将取代为的转换, 共需要个点离散傅立叶变换):
就成功仅使用与点离散傅立叶变换,描述了原先的点离散傅立叶变换。
而在这样的分解下,我们使用了个点离散傅立叶变换与个点离散傅立叶变换与一些额外的乘法, 并且这些额外使用的复数乘法, 在电脑的运算架构中,如果是的倍数则不需要使用乘法, 如果是的倍数则仅需两个实数乘法, 其他则需三个实数乘法,所以总运算量可以如下方式表示:
其中是傅立叶所需乘法数,是傅立叶所需乘法数, 是需三个实数乘法组合个数,是需两个实数乘法组合个数。
而常见以为基底的分解则是为了使离散傅立叶变换所需乘法数为零,这样就仅需考虑上面提到的额外乘法,可以提高效率也有较简单的结构。
在互质的情况下,仍是采取和上面相近的思路来将问题进行拆分,首先,为了避免之后的符号混淆,我们同样将置换为。
接著同样定义要拆分的问题:
接著就是和上面的算法有最大差异的部分,在将化为个使用两个参数进行描述的函数时, 最直觉的作法便是使用商数和馀数,但在互质的情况下,可以有一些其他更具技巧性的选择。
当互质,对所有我们可以找到唯一且不重复的一组使得:
其中,代表取馀数的意思,是一个整数。
例如假设,则对应到的就是, 有。
并且对所有的组合(有组),都对应到一个特定不重复的。
同理我们可以把表示为的双参数函数:
将上述的参数代换及带入原式,可以得到:
接著透过一次的展开化简及应用可得:
再将带入并再透过一次的展开化简及应用可得:
观察上式,并加上括号辅助厘清运算顺序我们可以得到:
内层的运算可以视为将双参数函数中的一个参数, 透过离散傅立叶变换取代为由一个与有关的变数描述, 得到一个新函数(这步因为对每个不同,都需要做一次将取代为的转换, 共需要个点离散傅立叶变换):
外层的运算可以视为将函数中的参数, 透过离散傅立叶变换取代为由一个与有关的变数描述, 得到一个新函数(这步因为对每个不同,都需要做一次将取代为的转换, 共需要个点离散傅立叶变换):
最后透过与在不同时的点点数值对应关系, 就成功仅使用与点离散傅立叶变换,描述了原先的点离散傅立叶变换。
而这个方法透过聪明的选取表达的方式,使得拆解的过程中完全不需要多馀的乘法运算, 总运算量可以简单表示为:
其中是傅立叶所需乘法数,是傅立叶所需乘法数。
虽然这个方法可以较上面的方法节省运算量, 但这个方法也牵涉较为复杂的与转换,较为不直觉且不易理解, 也会遇到许多需要取馀数的运算,可能会需要较大的空间建表进行查表法。
最后关于实际上要如何求得与的转换关系, 可以先透过辗转相除法取得一对特定的使得:
然后我们可以知道对于任意整数有:
然后就可以得到:
满足:
参考资料
Wikiwand - on
Seamless Wikipedia browsing. On steroids.
Remove ads