相信網(wǎng)上現(xiàn)在有很多關(guān)于FFT的教程,我曾經(jīng)也參閱了很多網(wǎng)上的教程,感覺都不怎么通俗易懂。在基本上的研究FFT,并且通過編程的形式實現(xiàn)之后。我決定寫一篇通俗易懂的關(guān)于FFT的講解。因此我在接下來的敘述中盡量非常通俗細致的講解。 本人最早知道傅里葉變換的時候是沉迷于音樂的頻譜跳動無法自拔,當時就很想做一個音樂頻譜顯示器。搜閱了很多資料之后,才了解到傅里葉變換,和FFT。當然這都是以前的事情了,經(jīng)過了系統(tǒng)的學習+2個星期的研究,自制了一個FFT的算法,不敢說速度上的優(yōu)勢,但是個人認為是一種通俗易懂的實現(xiàn)方法。經(jīng)過實際的VC++模擬實驗、和STM32跑的也很成功。 首先,要會FFT,就必須要對DFT有所了解,因為兩者之間本質(zhì)上是一樣的。在此之前,先列出離散傅里葉變換對(DFT): 其中: 但是FFT之所以稱之為快速傅里葉變換,就利用了以下的幾個性質(zhì)(重中之重!) 周期性: 對稱性: 可約性: 先把這仨公式放到這,接下來會用到。 根據(jù)這幾個特性,就可以將一個長的DFT運算分解為若干短序列的DFT運算的組合,從而減少運算量。在這里,為了方便理解,我就用了一個按時間抽取的快速傅里葉變換(DIT-FFT)的方法。 首先,將一個序列x(n)一分為二 對于 將x(n)按照奇偶分組 x(2r)=x1(r) x(2r+1)=x2(r) r=0,1,…..(N/2)-1 那么將DFT也分為兩組來預算 這個時候,我們上邊提的三個性質(zhì)中的可約性就起到作用了: 回顧一下: 那么這個式子就可以化為: 則X1(k)和X2(k)都是長度為N/2的序列 x1(k)和x2(k)的N/2點的離散傅里葉變換 其中: K=0,1,2…N/2-1 至此,一個N點的DFT就被分解為2個N/2的DFT。但是X1(k),和X2(k)只有N/2個點,也就是說式子(1-1)只是DFT前半部分。要求DFT的后半部分可以利用其對稱性求出后半部分為: (式1-2) 那么式(1-1)和(1-2)就可以專用一個蝶形信號流圖符號來表示。如圖: 以N=8為例,可以用下圖表示: 通過這樣的分解,每一個N/2點DFT只需(N^2)/4次復數(shù)相乘計算,明顯的節(jié)省了運算量。 以此類推,繼續(xù)將已經(jīng)得出的X1(k)和X2(k)按照奇偶分解,還是和上邊一樣的方法。那么就得出了百度上都可以找到的一大推的這個圖片了。 (笑) 對于這張圖片我想強調(diào)的一點就是第二階蝶形運算的時候,WN0之后不應該是WN1嗎,為什么是W2N了,這個問題之前困擾了我一段時間,但是不要忘了,前者的 W0N的展開是W0N/2 因為此時N已經(jīng)按照奇偶分開了,所以是N/2 而W2N/2也就是 W2N是根據(jù)可約性得出的,在這里不能混淆.。 對于運算效率就不用多提了 以上就是FFT算法的理論內(nèi)容了,接下來就是用C語言對這個算法的實現(xiàn)了,對于FFT算法C語言的實現(xiàn),網(wǎng)上的方法層出不窮,介于本人比較懶(懶得看別人的程序),再加上自給自足豐衣足食的原則,我自己也寫了一個個人認為比較通俗易懂的程序,并且為了幫助讀者理解,我特意盡量減少了庫函數(shù)的使用,一些基本的函數(shù)都是自己寫的(難免有很多BUG),但是作為FFT算法已經(jīng)夠用了,目前這個程序只能處理2^N的數(shù)據(jù),理論上來講如果不夠2^N的話可以在后面數(shù)列補0這種操作為了簡約我也就沒有實現(xiàn),但是主要的功能是具備的,下面是代碼:
這個程序中input這個數(shù)組是輸入信號,在這里只模擬抽樣了8次,輸出的數(shù)據(jù)也是input,如果想看其它序列的話,可以改變FFT_LENGTH的值以及 input里的內(nèi)容,程序輸出的是實部和虛部的模,如果單純想看實部或者虛部的幅度的話,請自行修改程序~ (本文摘自21ic論壇,感謝原作者辛苦分享) |
|
來自: 西北望msm66g9f > 《培訓》