简单回顾
快速傅里叶变换,其实是离散傅里叶变换的一种改进算法
我们先来回忆一下离散傅里叶变换(DFT):
Ff[m]–––––––=∑n=0N−1f[n]––––ω[m]–––––−n(1)
其中ω[m]–––––=e2πimN
对应的矩阵形式为:
⎡⎣⎢⎢⎢⎢⎢⎢Ff[0]––––––Ff[1]––––––⋮Ff[N−1]–––––––––––⎤⎦⎥⎥⎥⎥⎥⎥=⎡⎣⎢⎢⎢⎢⎢11⋮11ω––−1⋅1⋮ω––−(N−1)⋅1⋯⋯⋱⋯1ω––−1⋅(N−1)⋮ω––−(N−1)2⎤⎦⎥⎥⎥⎥⎥⎡⎣⎢⎢⎢⎢⎢⎢f[0]––––f[1]––––⋮f[N−1]–––––––––⎤⎦⎥⎥⎥⎥⎥⎥
不难发现,如果要对N个采样点进行DFT,则时间复杂度为o(N2)
接下来,我们将讲解时间复杂度为o(NlogN)的FFT算法
为了书写方便,我们记
ω––[p,q]=e2πiqp(2)
这样,ω[m]–––––就可以改写为
ω[m]–––––=e2πimN=ω––[N,m]
同时,不难发现,
ω––[N,n+m]=e2πin+mN=e2πinNe2πimN=ω––[N,n]ω––[N,m]
ω––[N2,−nm]=e−2πinmN2=e−2πi2nmN=ω––[N,−2nm]
FFT推导
FFT的核心思想就是:将DFT的N×N矩阵该写为对几个N2×N2的矩阵的操作,并用这种方式进行递归,最后得到FFT
首先,我们将(1)式拆分为奇数、偶数两部分,即
Ff[m]–––––––=∑n=0N−1f[n]––––ω[m]–––––−n=(f[0]––––ω[m]–––––−0+f[2]––––ω[m]–––––−2+⋯+f[N−2]–––––––––ω[m]–––––−(N−2))+(f[1]––––ω[m]–––––−1+f[3]––––ω[m]–––––−3+⋯+f[N−1]–––––––––ω[m]–––––−(N−1))=∑n=0N2−1f[2n]–––––ω[m]–––––−2n+∑n=0N2−1f[2n+1]–––––––––ω[m]–––––−(2n+1)
利用(2)式,可将上式改写为
Ff[m]–––––––=∑n=0N2−1f[2n]–––––ω––[N,−2nm]+∑n=0N2−1f[2n+1]–––––––––ω––[N,−(2n+1)m]=∑n=0N2−1f[2n]–––––ω––[N,−2nm]+∑n=0N2−1f[2n+1]–––––––––ω––[N,−2nm]ω––[N,−m]=∑n=0N2−1f[2n]–––––ω––[N2,−nm]+ω––[N,−m]∑n=0N2−1f[2n+1]–––––––––ω––[N2,−nm](3)
注意我们要使用递归来计算的话,必须把式子写成矩阵形式,那么(3)式就可以写为:
F–––Nf[m]–––––=FN2feven[m]––––––––––––+ω––[N,−m]FN2fodd[m]–––––––––––(4)
我们仔细看看从(3)式的求和形式到(4)的矩阵矩阵形式,(3)式完全是没有问题的,但是(4)式却有问题:
(4)式中的F–––N2是N2×N2的矩阵,那么与之相乘的矩阵必然有N2行,也就是说m≤N2−1。换句话说,(4)式计算出的其实是F–––N的前半部分。
那么对于m∈[N2,N−1]的情况,应该如何写出相应的矩阵形式呢?我们将(3)式左边的系数写成m+N2,这样一来,m的取值依然是[0,N2−1]。于是就有:
Ff[m+N2]–––––––––––––=∑n=0N2−1f[2n]–––––ω––[N2,−n(m+N2)]+ω––[N,−(m+N2)]∑n=0N2−1f[2n+1]–––––––––ω––[N2,−n(m+N2)]=∑n=0N2−1f[2n]–––––ω––[N2,−nm]ω––[N2,−nN2]+ω––[N,−m]ω––[N,−N2]∑n=0N2−1f[2n+1]–––––––––ω––[N2,−nm]ω––[N2,−nN2](5)
注意到,
ω––[N2,−nN2]=e−2πin=1
ω––[N,−N2]=e−πi=−1
带入(5)式,有:
Ff[m+N2]–––––––––––––=∑n=0N2−1f[2n]–––––ω––[N2,−nm]−ω––[N,−m]∑n=0N2−1f[2n+1]–––––––––ω––[N2,−nm]
写成矩阵的形式,即
F–––Nf[m+N2]––––––––––=FN2feven[m]––––––––––––−ω––[N,−m]FN2fodd[m]–––––––––––(6)
结合(4),(6)两式,我们可以得到FFT的矩阵递归式:
F–––Nf[m]–––––=FN2feven[m]––––––––––––+ω––[N,−m]FN2fodd[m]–––––––––––
F–––Nf[m+N2]––––––––––=FN2feven[m]––––––––––––−ω––[N,−m]FN2fodd[m]–––––––––––
其中m∈[0,N2−1],第一个等式为前N2项,第二个等式为后N2项
这个式子很明确地告诉我们:
FFT实际上就是将DFT的矩阵,通过一定的方式进行拆分,从而降低时间复杂度的一种算法
FFT的时间复杂度
有了递归式,我们就可以来算时间复杂度。
方便起见,我们将矩阵写成[n×m],其中n,m分别表示行列数。并设N=2k
-
那么前N2项就可以写成
[N2×N2]+CN[N2×N2]
其中CN为一常数,该式花费的时间为o([N2×N2])+1+o([N2×N2]),其中1就是常数相乘的操作
对于后N2项,由于对应的矩阵、常数都是相同的,因此只需要额外进行1次操作即可
-
我们把n×n的矩阵记为[n],并把m个不同的常数相乘记为Cm,则如下图
![15. 快速傅里叶变换(FFT)原理 [学习笔记] 15. 快速傅里叶变换(FFT)原理 [学习笔记]](/default/index/img?u=aHR0cHM6Ly9waWFuc2hlbi5jb20vaW1hZ2VzLzg4MS9lOWI3NTVlN2JjYzYxYTQ5ODkyZjQ3MDI1NjMxNjVmMS5wbmc=)
注意图中1+2⋯+2k−1是前文提到的后N2项的计算量,需要进行累加计算。到最后一项时,它的累积值为2n−1
不难发现,递归至最后一项时,总计算次数应为(图中最后一行以及虚线框内):
0⋅(0k)+1⋅(1k)+⋯+k⋅(kk)+(2k)+(2k−1)+(2k)(7)
简单解释一下上式
- 前面的各项排列组合表示的是各个常数Cx所需的计算时间,如系数Ck只在最后一个一阶矩阵前出现,计算量为k⋅(kk)=k次,又如系数C1必然会出现(1k)次,因此计算量为1⋅(1k)=k;
- 第一个2n表示的是所有1阶矩阵的计算时间总和;
-
2n−1表示的是后N2项的计算量;
- 第二个2n表示的是计算所有+(加号)花费的时间
(7)式不容易计算,但是我们可以直观地估计一下,对于前面的阶乘项,最多用时为k次,最少为1次,那么不严格地估计一下,我们取平均k+12次,这样共需要计算N次(有N个[1]),因此时间复杂度应为:
o((Nk2)+3N−1)=o(12Nlog2N+3N−1)=o(Nlog2N)
因此,FFT的时间复杂度就是
o(NlgN)