FFT算法的实现(1)

本文章参考:http://tieba.baidu.com/p/2513502552
那一天,作者终于想起了他CSDN的密码,填坑完毕:)

不想看理论想直接看代码的同学,请到我的第二篇博客拉到最底。点击传送门传送

由于需要在Arduino上进行声音处理,需要用到FFT变换,查找了相关库过后发现FFT的库比较少,而且版本比较老了,挑编译器,也因为种种个人原因,索性自己来实现一个FFT变换。
FFT(快速傅里叶变换)变换本质就是DFT(离散傅里叶变换),但是对DFT进行了优化,减少了计算量并能够比较方便地用程序实现。这里是在Arduino平台上实现了一个基2的FFT算法,大致需要如下预备知识:

  • 傅里叶变换的概念
  • 复数的概念
  • 欧拉公式

因为是用程序实现数学算法,要完全理解程序,肯定是会涉及到公式推导,但是这里的推导很简单,大概需要高中的数学知识即可。首先上DFT的公式,下面将由这个公式一步步推出FFT的算法。


X[k]=n=0N1x[n]ei2πkNn X [ k ] = ∑ n = 0 N − 1 x [ n ] e − i 2 π k N n


学过傅里叶变换的话应该比较熟悉这个公式,它其实就是针对离散的采样点 x[n] x [ n ] 的傅里叶变换,其意义还是将信号从时域转换到频域。那么这里的 X[k] X [ k ] 表示的就是频域信号了,下标k表示信号的频率, X[k] X [ k ] 的值就是该频率信号的幅值。这里可以看到,当k固定的时候,对应于频率为k的信号幅值是与 x[n] x [ n ] 有关的一个级数的和,因此每一个频域的点实际上包含了所有时域点的信息。

有两点需要注意,一是因为 x[n] x [ n ] 的长度为 N N ,因此 DFT 后的频域信号 X[k] X [ k ] 的长度也是 N N ;二是为了进行FFT变换,N 的取值一般是2的整数次幂。


将下标n分解为奇偶两部分,然后分别求和

X[k]=r=0N21x[2r]ei2πkN2r+r=0N21x[2r+1]ei2πkN(2r+1) X [ k ] = ∑ r = 0 N 2 − 1 x [ 2 r ] e − i 2 π k N 2 r + ∑ r = 0 N 2 − 1 x [ 2 r + 1 ] e − i 2 π k N ( 2 r + 1 )


这里进行一次代换,用 x0[n] x 0 [ n ] 表示 x[n] x [ n ] 中的偶数项,用 x1[n] x 1 [ n ] 表示 x[n] x [ n ] 中的奇数项

X[k]=n=0N21x0[n]ei2πkN/2n+n=0N21x1[n]ei2πkN/2ni2πkN X [ k ] = ∑ n = 0 N 2 − 1 x 0 [ n ] e − i 2 π k N / 2 n + ∑ n = 0 N 2 − 1 x 1 [ n ] e − i 2 π k N / 2 n − i 2 π k N


第二项求和中, ei2πNk e − i 2 π N k n n 无关,因此可以单独提出

X[k]=n=0N21x0[n]ei2πkN/2nx0[n]DFT+ei2πNkn=0N21x1[n]ei2πkN/2nx1[n]DFT X [ k ] = ∑ n = 0 N 2 − 1 x 0 [ n ] e − i 2 π k N / 2 n ⏟ 对 x 0 [ n ] 进 行 D F T + e − i 2 π N k ∑ n = 0 N 2 − 1 x 1 [ n ] e − i 2 π k N / 2 n ⏟ 对 x 1 [ n ] 进 行 D F T


X[k]=DFT(x0)+ei2πNkDFT(x1) X [ k ] = D F T ( x 0 ) + e − i 2 π N k D F T ( x 1 )


利用欧拉公式,将: ei2πNk=cos2πkNisin2πkN e − i 2 π N k = cos ⁡ 2 π k N − i sin ⁡ 2 π k N 代入:

X[k]=DFT(x0)+(cos2πkNisin2πkN)DFT(x1) X [ k ] = D F T ( x 0 ) + ( cos ⁡ 2 π k N − i sin ⁡ 2 π k N ) D F T ( x 1 )


设: X0[k]=DFT(x0)X1[k]=DFT(x1) X 0 [ k ] = D F T ( x 0 ) , X 1 [ k ] = D F T ( x 1 )

X[k]=X0[k]+(cos2πkNisin2πkN)X1[k] X [ k ] = X 0 [ k ] + ( cos ⁡ 2 π k N − i sin ⁡ 2 π k N ) X 1 [ k ]


因为这里 x0[n] x 0 [ n ] x1[n] x 1 [ n ] 分别是 x[n] x [ n ] 的偶数项和奇数项,因此它们的长度都是 N2 N 2 ,所以 X0[k] X 0 [ k ] X1[k] X 1 [ k ] 的长度也是 N2 N 2 ,而 X[k] X [ k ] X0[k] X 0 [ k ] X1[k] X 1 [ k ] 的线性组合,因此其长度也是 N2 N 2

前面已经提到,原式的变换中 X[k] X [ k ] 的长度为 N N ,经过一轮变换之后其长度变为了 N2 ,那岂不是意味着丢失了一半的频率信息吗?这肯定是不允许的,下面就利用 DFT D F T 的对称性找回这一半丢失的信息。

在此之前先引入旋转因子的概念:


旋转因子表示为:

WN=ei2πN=cos2πNisin2πN W N = e − i 2 π N = cos ⁡ 2 π N − i sin ⁡ 2 π N


旋转因子的对称性:

Wk+N2N=ei2πN(k+N2)=ei2πNeiπ=ei2πN=WkN W N k + N 2 = e − i 2 π N ( k + N 2 ) = e − i 2 π N ∗ e − i π = − e − i 2 π N = − W N k


使用旋转因子表达将更简洁:

X[k]=X0[k]+WkNX1[k] X [ k ] = X 0 [ k ] + W N k X 1 [ k ]


上面已经说到, X0[k] X 0 [ k ] X1[k] X 1 [ k ] 的长度为 N2 N 2 ,那么超出 N2 N 2 的部分会出现什么情况呢?事实上超出的部分将会呈周期性变化,即: X0[k+N2]=X0[k] X 0 [ k + N 2 ] = X 0 [ k ] ,这一点将 k+N2 k + N 2 代入 X0[k] X 0 [ k ] 的表达式即可证明,这里就省去了。知道这一点后,我们用在上式中用 k+N2 k + N 2 代替 k k



X[k+N2]=X0[k+N2]+Wk+N2NX1[k+N2]=X0[k]WkNX1[k] X [ k + N 2 ] = X 0 [ k + N 2 ] + W N k + N 2 X 1 [ k + N 2 ] = X 0 [ k ] − W N k X 1 [ k ]


至此已经得出了整个频域上的表达式:



X[k]=X0[k]+WkNX1[k] X [ k ] = X 0 [ k ] + W N k X 1 [ k ]

X[k+N2]=X0[k]WkNX1[k] X [ k + N 2 ] = X 0 [ k ] − W N k X 1 [ k ]


写了这么多公式,还没有讲到FFT,其实算到这里,已经完成了FFT的关键部分了。

下一篇中将完成算法的具体实现。

  • 3
    点赞
  • 39
    收藏
    觉得还不错? 一键收藏
  • 2
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值