离散傅里叶变换学习-从一维到海洋模拟(二)

2 阅读2分钟

一维快速傅里叶变换(FFT)

  在一维DFT的基础上,推导一维快速傅里叶变换的方法。要利用ejk2πNne^{-jk\frac{2\pi}{N}n}的性质,将其记为WNknW_N^{kn}主要有以下性质:

  • 周期性:WNa+N=WNaW_N^{a+N}=W_N^{a}

  • 对称性:WNa+N2=WNaW_N^{a+\frac{N}{2}}=W_N^{a}

  • 缩放性:WN2=WN21W_N^{2}=W_{\frac{N}{2}}^{1}

  证明方法就是按旋转因子定义,直接拆开就行,就是代数变换。以上性质意味着值相同的就不用了再多计算一遍了,这就能简化DFT的计算过程。

  FFT的递推公式就是基于上述性质对DFT进行变换得到的。

  首先,把输入的时域信号x[n] , n = 0 , 1 , . . . ,N−1根据索引分为奇偶两部分

feven[m]=x[2m]fodd[m]=x[2m+1]m=0,1,2,3,...,N21 f_{even}[m] = x[2m]\\ f_{odd}[m] = x[2m+1]\\ m = 0,1,2,3,...,\frac{N}{2}-1

  对DFT公式进行化简:

X[k]=n=0N1x[n]WNkn,k=0,1,2,3,...N1=evenx[n]WNkn+oddx[n]WNkn X[k] = \sum_{n=0}^{N-1}x[n]W_N^{kn},k=0,1,2,3,...N-1\\ =\sum_{even}x[n]W_N^{kn}+\sum_{odd}x[n]W_N^{kn}\\

  根据旋转因子的缩放性,可以进一步换算:

X[k]=m=0N21xeven[2m]WN2mk+m=0N21xodd[2m+1]WN(2m+1)k=m=0N21feven[m]WN2mk+WNkm=0N21fodd[m]WN2mk X[k]=\sum_{m=0}^{\frac{N}{2}-1}x_{even}[2m]W_N^{2mk}+\sum_{m=0}^{\frac{N}{2}-1}x_{odd}[2m+1]W_N^{(2m+1)k}\\ =\sum_{m=0}^{\frac{N}{2}-1}f_{even}[m]W_{\frac{N}{2}}^{mk}+W_N^{k}\sum_{m=0}^{\frac{N}{2}-1}f_{odd}[m]W_{\frac{N}{2}}^{mk}

  进一步得到递推公式:

X[k]=Feven[k]+WNkFodd[k] X[k]=F_{even}[k]+W_N^kF_{odd}[k]

  其中,Feven[k]F_{even}[k]为偶数项的DFT结果,Fodd[k]F_{odd}[k]为奇数项DFT的结果。WNkW_N^{k}ej2πNke^{-j\frac{2\pi}{N}k},是一个复数。有了递推公式就可以递归地实现该算法。然而递归是非常慢的操作,观察公式可以发现。要计算X[k]X[k],只需要将输入序列分为偶数项和奇数项,计算偶数项的DFT,可以继续划分,直到最后只剩两项时,计算两个数的DFT。然后向上层传递。   假设有输入序列有8个数。x[0],x[1],x[2]....x[7],划分层次如下:

Layer4=(x[0],x[1],x[2],x[3],x[4],x[5],x[6],x[7])Layer3=(x[0],x[2],x[4],x[6])+W8k(x[1],x[3],x[5],x[7])Layer2=(x[0],x[4])+W4k(x[2],x[6]),(x[1],x[5])+W4k(x[3],x[7])Layer1=(x[0])+W2k(x[4]),(x[2])+W2k(x[6]),(x[1])+W2k(x[5]),(x[3])+W2k(x[7]) Layer_4=(x[0],x[1],x[2],x[3],x[4],x[5],x[6],x[7])\\ Layer_3=(x[0],x[2],x[4],x[6])+W_8^k(x[1],x[3],x[5],x[7])\\ Layer_2=(x[0],x[4])+W_4^k(x[2],x[6]),(x[1],x[5])+W_4^k(x[3],x[7])\\ Layer_1=(x[0])+W_2^k(x[4]),(x[2])+W_2^k(x[6]),(x[1])+W_2^k(x[5]),(x[3])+W_2^k(x[7])

  最底下的数就是输入序列,按这个方式组合计算即可获得更高层次的结果,所有只需要自底向上层层按公式计算即可。在这里,不要被上面的(0,4),(2,6),(1,5),(3,7)的组合放置的顺序误导了,这里的遍历顺序仍然是0,1,2,3。具体的可以参考后面给出的代码实现。这里想要重点提一点的是,上面的x[n]x[n]虽然输入是一个实数,但其实在代码实现中,可以转成复数计算,这样一来,整个傅里叶变换过程和逆变换过程,都是在复数空间中计算的,计算结果也是复数,这样去看公式,就更统一和好理解。   更进一步地,分析快速傅里叶逆变换(IFFT),这里直接上公式,就不进行推导了,经过了前面的洗礼,推导的过程应该是很简单的。

x[n]=1Nk=0N1X[k]WNkn x[n]=\frac{1}{N}\sum_{k=0}^{N-1}X[k]W_N^{-kn}

  由此可见,IFFT的公式除了左边的1N\frac{1}{N}之外,还是一个复数乘积的求和公式。但是WNknW_N^{-kn}与FFT的相比,反过来了,X[k]X[k]就是FFT计算得到的序列。而快速计算的推导方法和FFT相同,就不再赘述。下面实现的代码仓库。
  FFT和IFFT代码实现的仓库地址

二维快速傅里叶变换(FFT)

  二维FFT是在一维FFT基础上实现,实现过程为:

  1. 对二维输入数据的每一行进行FFT,变换结果仍然按行存入二维数组中。结果是一行复数序列。

  2. 在1的结果基础上,对每一列进行FFT,得到二维FFT结果。

  这里仍然拿之前二维DFT的示例程序进行修改。得到的结果与DFT的结果一致。

  对于二维快速傅里叶逆变换,上面两点结论改改依然成立:

  1. 对二维FFT的每一行进行IFFT,结果是一行复数序列,变换结果仍然按行存入二维数组中。
  2. 在1的结果基础上,对每一列进行IFFT,得到二维IFFT结果。

image-20240511003723116.png

二维FFT及IFFT代码仓库地址