FFT为什么这么快?

离散傅里叶变换(DFT)是为了能让计算机处理经过采集的离散信号提出的,DFT的推导以及代码实现在下面的两篇文章中也已经介绍了:

  1. DFT推导
  2. DFT代码实现

个人认为,DFT是数字信号处理领域最重要的数学思想,而快速傅里叶变换(FFT)是该领域最重要的算法。FFT不是一种新的变换,他是DFT的快速实现。正是因为FFT的提出,才让傅里叶变换算法能够在工程界大显身手。

1. 离散傅里叶变换的矩阵表达

DFT变换的公式为:
X p = ∑ n = 0 N − 1 x n e   − j 2 π N n p , p ∈ { 0 , 1 , … , N − 1 } X_{p}=\sum_{n=0}^{N-1} x_{n} \mathrm{e}^{\:-j \frac{2 \pi}{N} n p}, \quad p \in\{0,1, \ldots, N-1\} \\ Xp=n=0N1xnejN2πnp,p{0,1,,N1}
为了更清楚地计算DFT的算法复杂度,我们将其表示为矩阵表达:
[ X 0 X 1 ⋯ X N − 1 ] = [ W N 0 W N 0 W N 0 ⋯ W N 0 W N 0 W N 1 W N 2 ⋯ W N N − 1 ⋮ ⋮ ⋮ ⋯ ⋮ W N 0 W N N − 1 W N 2 ( N − 1 ) ⋯ W N ( N − 1 ) 2 ] [ x 0 x 1 ⋮ x N − 1 ] \begin{bmatrix} X_0 \\ X_1 \\\cdots \\X_{N-1} \end{bmatrix} =\begin{bmatrix} W_N^0 & W_N^0 & W_N^0 & \cdots & W_N^0\\ W_N^0 & W_N^1 & W_N^2 & \cdots & W_N^{N-1}\\ \vdots & \vdots & \vdots & \cdots &\vdots\\ W_N^0 & W_N^{N-1} & W_N^{2(N-1)} & \cdots & W_N^{(N-1)^2} \end{bmatrix} \begin{bmatrix} x_0 \\ x_1 \\\vdots \\x_{N-1} \end{bmatrix} X0X1XN1 = WN0WN0WN0WN0WN1WNN1WN0WN2WN2(N1)WN0WNN1WN(N1)2 x0x1xN1
式中:

W N = e   − j 2 π N W_N=e^{\:-j\frac{2\pi}{N}} WN=ejN2π

2. DFT复杂度计算

因为 N ∗ N N*N NN 的变换矩阵中的每一个元素可以离线计算并存储,这样上述计算过程仅涉及 N 2 N^2 N2 次复数乘法运算和 N ( N − 1 ) N(N-1) N(N1) 次复数加法运算。

因为变换矩阵的第一行和第一列都是 1 1 1 ,这样就节约了 2 N − 1 2N - 1 2N1 次的复数乘法运算,所以实际上,上述计算过程只需要进行 N 2 − ( 2 N − 1 ) N^2-(2N-1) N2(2N1) 次复数乘法运算,即共需要 ( N − 1 ) 2 (N-1)^2 (N1)2 次复数乘法运算和 N ( N − 1 ) N(N-1) N(N1) 次复数加法运算。

因为 1 1 1 次复数乘法运算相当于 4 4 4 次实数乘法运算和 2 2 2 次实数加法运算, 1 1 1 次复数加法运算相当于 2 2 2 次实数加法运算,所以:

一共需要进行 4 ( N − 1 ) 2 4(N-1)^2 4(N1)2 次实数乘法运算和 2 ( N − 1 ) 2 + 2 N ( N − 1 ) = 4 ( N − 0.5 ) ( N − 1 ) 2(N-1)^2+2N(N-1)=4(N-0.5)(N-1) 2(N1)2+2N(N1)=4(N0.5)(N1) 次实数加法运算。

所以离散傅里叶变换算法复杂度是 O ( n 2 ) O(n^2) O(n2) ,如果要处理的数据点数过多,就会需要大量的计算时间,这会给工程应用带来很大的限制。

3. FFT算法

Cooley和Tukey在1965年宣布,他们“第一次”发现了FFT算法。而实际上,他们发现的FFT算法的核心原理,早在150多年前(1806年),就被高斯记在了自己的小本本上。那么这个算法究竟用了什么奇技淫巧呢,本文将一探究竟。

DFT变换的基础公式为:
X p = ∑ n = 0 N − 1 x n e   − j 2 π N n p , p ∈ { 0 , 1 , … , N − 1 } X_{p}=\sum_{n=0}^{N-1} x_{n} \mathrm{e}^{\:-j \frac{2 \pi}{N} n p}, \quad p \in\{0,1, \ldots, N-1\} \\ Xp=n=0N1xnejN2πnp,p{0,1,,N1}
假设 N N N 2 2 2 的正整数次幂,则把上述公式等号右边分成两部分,分别是 n n n 为奇数时的有限项级数求和以及 n n n 为偶数时的有限项级数求和:
X p = ∑ n = 0 N 2 − 1 x 2 n e − j 2 π N ( 2 n ) p + ∑ n = 0 N 2 − 1 x 2 n + 1 e − j 2 π N ( 2 n + 1 ) p = ∑ n = 0 N 2 − 1 x 2 n e − j 2 π ( N / 2 ) n p + e − j 2 π N p ∑ n = 0 N 2 − 1 x 2 n + 1 e − j 2 π ( N / 2 ) n p = A p + W N p B p \begin{aligned} X_{p}&=\sum_{n=0}^{\frac{N}{2}-1} x_{2 n} \mathrm{e}^{-j \frac{2 \pi}{N}(2 n) p}+\sum_{n=0}^{\frac{N}{2}-1} x_{2 n+1} \mathrm{e}^{-j \frac{2 \pi}{N}(2 n+1) p}\\ &=\sum_{n=0}^{\frac{N}{2}-1} x_{2 n} e^{-j \frac{2 \pi}{(N / 2)} n p}+e^{-j \frac{2 \pi}{N} p} \sum_{n=0}^{\frac{N}{2}-1} x_{2 n+1} e^{-j \frac{2 \pi}{(N / 2)} n p}\\ &= A_p + W_N^pB_p \end{aligned} Xp=n=02N1x2nejN2π(2n)p+n=02N1x2n+1ejN2π(2n+1)p=n=02N1x2nej(N/2)2πnp+ejN2πpn=02N1x2n+1ej(N/2)2πnp=Ap+WNpBp

其中:
A p = ∑ n = 0 N 2 − 1 x 2 n e − j 2 π ( N / 2 ) n p B p = ∑ n = 0 N 2 − 1 x 2 n + 1 e − j 2 π ( N / 2 ) n p W N p = e − j 2 π N p \begin{aligned} A_p&=\sum_{n=0}^{\frac{N}{2}-1} x_{2 n} e^{-j \frac{2 \pi}{(N / 2)} n p}\\ B_p&=\sum_{n=0}^{\frac{N}{2}-1} x_{2 n+1} e^{-j \frac{2 \pi}{(N / 2)} n p}\\ W_N^p&= e^{-j \frac{2 \pi}{N} p} \end{aligned} ApBpWNp=n=02N1x2nej(N/2)2πnp=n=02N1x2n+1ej(N/2)2πnp=ejN2πp
注意看,这里 A p A_p Ap 是序列 { x 2 n } = { x 0 , x 2 , … x N − 4 , x N − 2 } \left\{x_{2 n}\right\}=\left\{x_{0}, x_{2}, \ldots x_{N-4}, x_{N-2}\right\} {x2n}={x0,x2,xN4,xN2} 的 DFT 变换结果,而 B p B_p Bp 是序列 { x 2 n + 1 } = { x 1 , x 3 , … x N − 3 , x N − 1 } \left\{x_{2 n+1}\right\}=\left\{x_{1}, x_{3}, \ldots x_{N-3}, x_{N-1}\right\} {x2n+1}={x1,x3,xN3,xN1} 的 DFT 结果。因为 W N p W_N^p WNp 可以事先计算并存储,所以如果先计算出 A p A_p Ap B p B_p Bp ,再进行 O ( n ) O(n) O(n) 次乘法和加法运算,岂不是就可以算出 X p X_p Xp ? 那么运算量岂不是减少了将近一半?那如果再把 A p A_p Ap B p B_p Bp 分别分成左右两部分(假设 N N N 2 2 2 的正整数次方),以同样的方式进行计算,如此穷尽下去…等下?先打住、有点过于乐观了…

因为 X p X_p Xp 中, p p p 的取值范围是 p ∈ { 0 , 1 , … , N − 1 } p \in\{0,1, \ldots, N-1\} p{0,1,,N1} , 而 A p A_p Ap B p B_p Bp 中, p p p 的取值范围却是 p ∈ { 0 , 1 , … , N / 2 − 1 } p \in\{0,1, \ldots, N/2-1\} p{0,1,,N/21} ,所以在完成 A p A_p Ap B p B_p Bp 的计算后,我们就只能算出当 p ∈ { 0 , 1 , … , N / 2 − 1 } p \in\{0,1, \ldots, N/2-1\} p{0,1,,N/21} 时的 X p X_p Xp ,也就是说傅里叶变换只完成了前一半。那运算量减少将近一半的说法不是笑话吗?还真不是,继续往下看。

因为:
X p = ∑ n = 0 N 2 − 1 x 2 n e − j 2 π ( N / 2 ) n p + e − j 2 π N p ∑ n = 0 N 2 − 1 x 2 n + 1 e − j 2 π ( N / 2 ) n p X_{p}=\sum_{n=0}^{\frac{N}{2}-1} x_{2 n} e^{-j \frac{2 \pi}{(N / 2)} n p}+e^{-j \frac{2 \pi}{N} p} \sum_{n=0}^{\frac{N}{2}-1} x_{2 n+1} e^{-j \frac{2 \pi}{(N / 2)} n p} Xp=n=02N1x2nej(N/2)2πnp+ejN2πpn=02N1x2n+1ej(N/2)2πnp
所以:
X p + N / 2 = ∑ n = 0 N 2 − 1 x 2 n e − j 2 π ( N / 2 ) n ( p + N / 2 ) + e − j 2 π N ( p + N / 2 ) ∑ n = 0 N 2 − 1 x 2 n + 1 e − j 2 π ( N / 2 ) n ( p + N / 2 ) X_{p+N/2}=\sum_{n=0}^{\frac{N}{2}-1} x_{2 n} e^{-j \frac{2 \pi}{(N / 2)} n(p+N/2)}+e^{-j \frac{2 \pi}{N} (p+N/2)} \sum_{n=0}^{\frac{N}{2}-1} x_{2 n+1} e^{-j \frac{2 \pi}{(N / 2)} n (p+N/2)} Xp+N/2=n=02N1x2nej(N/2)2πn(p+N/2)+ejN2π(p+N/2)n=02N1x2n+1ej(N/2)2πn(p+N/2)
对等号右边的部分表达进行化简,有:
e − j 2 π ( N / 2 ) n ( p + N / 2 ) = e − j 2 π ( N / 2 ) n p e − j 2 π N ( p + N / 2 ) = − e − j 2 π N p \begin{aligned} e^{-j \frac{2 \pi}{(N / 2)} n(p+N / 2)}&=e^{-j \frac{2 \pi}{(N / 2)} n p}\\ e^{-j \frac{2 \pi}{N} (p+N/2)} &= -e^{-j \frac{2 \pi}{N}p} \end{aligned} ej(N/2)2πn(p+N/2)ejN2π(p+N/2)=ej(N/2)2πnp=ejN2πp
将化简结果带入上式,有:
X p + N / 2 = ∑ n = 0 N 2 − 1 x 2 n e − j 2 π ( N / 2 ) n p − e − j 2 π N p ∑ n = 0 N 2 − 1 x 2 n + 1 e − j 2 π ( N / 2 ) n p = A p − W N p B p \begin{aligned} X_{p+N/2}&=\sum_{n=0}^{\frac{N}{2}-1} x_{2 n} e^{-j \frac{2 \pi}{(N / 2)} n p}-e^{-j \frac{2 \pi}{N}p} \sum_{n=0}^{\frac{N}{2}-1} x_{2 n+1} e^{-j \frac{2 \pi}{(N / 2)} n p}\\ &=A_p - W_N^pB_p \end{aligned} Xp+N/2=n=02N1x2nej(N/2)2πnpejN2πpn=02N1x2n+1ej(N/2)2πnp=ApWNpBp

所以有:
{ A p + W N p B p = X p A p − W N p B p = X p + N / 2 \begin{cases} A_p + W_N^pB_p = X_p\\ A_p - W_N^pB_p =X_{p+N/2} \end{cases} {Ap+WNpBp=XpApWNpBp=Xp+N/2
这样,如果先计算出 A p A_p Ap B p B_p Bp ,再进行 O ( n ) O(n) O(n) 次乘法和加法运算,就可以算出当 p ∈ { 0 , 1 , … , N − 1 } p \in\{0,1, \ldots, N-1\} p{0,1,,N1} 时的所有 X p X_p Xp ,这就是著名的蝶形运算,基本运算单元如下图所示(图中的 W p W^p Wp 和本文的 W N p W_N^p WNp 是一样的 ):

蝶形运算图

N N N 是一个比较大的数时,进行一次这样的处理就能节约将近一半的计算量,下图给出了当 N = 8 N=8 N=8 时候的第一步的蝶形运算过程:

N=8时的初步运算

A p A_p Ap 是序列 { x 2 n } = { x 0 , x 2 , … x N − 4 , x N − 2 } \left\{x_{2 n}\right\}=\left\{x_{0}, x_{2}, \ldots x_{N-4}, x_{N-2}\right\} {x2n}={x0,x2,xN4,xN2} 的 DFT 变换结果, B p B_p Bp 是序列 { x 2 n + 1 } = { x 1 , x 3 , … x N − 3 , x N − 1 } \left\{x_{2 n+1}\right\}=\left\{x_{1}, x_{3}, \ldots x_{N-3}, x_{N-1}\right\} {x2n+1}={x1,x3,xN3,xN1} 的 DFT 变换结果。那么如果再分别对 A p A_p Ap B p B_p Bp 采用上面的方法进行计算,当序列长度较大时,则又能节约将近一半的计算量!即 A p A_p Ap B p B_p Bp 采用下面的公式计算:
A p = α p + W N / 2 p β p A p + N / 2 = α p − W N / 2 p β p B p = α p ′ + W N / 2 p β p ′ B p + N / 2 = α p ′ − W N / 2 p β p ′ \begin{aligned} A_{p}=\alpha_{p}+W_{N / 2}^{p} \beta_{p} \quad A_{p+N / 2}=\alpha_{p}-W_{N / 2}^{p} \beta_{p}\\ B_{p}=\alpha_{p}^{\prime}+W_{N / 2}^p \beta_{p}^{\prime} \quad B_{p+N / 2}=\alpha_{p}^{\prime}-W_{N / 2}^p \beta_{p}^{\prime} \end{aligned} Ap=αp+WN/2pβpAp+N/2=αpWN/2pβpBp=αp+WN/2pβpBp+N/2=αpWN/2pβp
式中:
W N / 2 p = e − j 2 π N / 2 p = W N 2 p W_{N/2}^p = e^{-j \frac{2 \pi}{N/2} p}=W_{N}^{2p} WN/2p=ejN/22πp=WN2p
下图给出了当 N = 8 N=8 N=8 时候的进一步的蝶形运算过程:

N=8时的进一步运算

如果递归式地进行这样的处理,就能把算法复杂度从 O ( n 2 ) O(n^2) O(n2) 降到 O ( n log ⁡ n ) O(n\log n) O(nlogn) .

本文首发于微信公众号:“振动信号研究所”

  • 2
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值