FFT算法的实现_1

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

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


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

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

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


X [ k ] = n = 0 N 1 x [ n ] e i 2 π k N n


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

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


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

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 )


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

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


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

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 ] = D F T ( x 0 ) + e i 2 π N k D F T ( x 1 )


利用欧拉公式,将: e i 2 π N k = cos 2 π k N i sin 2 π k N 代入:

X [ k ] = D F T ( x 0 ) + ( cos 2 π k N i sin 2 π k N ) D F T ( x 1 )


设: X 0 [ k ] = D F T ( x 0 ) X 1 [ k ] = D F T ( x 1 )

X [ k ] = X 0 [ k ] + ( cos 2 π k N i sin 2 π k N ) X 1 [ k ]


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

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

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


旋转因子表示为:

W N = e i 2 π N = cos 2 π N i sin 2 π N


旋转因子的对称性:

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 ] = X 0 [ k ] + W N k X 1 [ k ]


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

X [ k + N 2 ] = X 0 [ k ] W N k X 1 [ k ]


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

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

猜你喜欢

转载自blog.csdn.net/egean/article/details/53039248