java fft 频谱算法_快速傅里叶变换(FFT)算法原理及代码解析
FFT與DFT關(guān)系:
快速傅里葉變換(Fast Fourier Transform)是離散傅里葉(DFT)變換的一種快速算法,簡(jiǎn)稱FFT,通過FFT可以將一個(gè)信號(hào)從時(shí)域變換到頻域;FFT(快速傅里葉變換)其本質(zhì)就是DFT,只不過可以快速的計(jì)算出DFT結(jié)果,它只是傅立葉變換算法實(shí)現(xiàn)過程的一種改進(jìn)。
要弄懂FFT,必須先弄懂DFT,DFT(DiscreteFourier Transform) 離散傅里葉變換的縮寫,咱們先來簡(jiǎn)單討論一下DFT。DFT(FFT)的作用:可以將信號(hào)從時(shí)域變換到頻域,而且時(shí)域和頻域都是離散的,通俗的說,可以求出一個(gè)信號(hào)由哪些正弦波疊加而成,求出的結(jié)果就是這些正弦波的幅度和相位。
DFT的公式:
其中X(k)表示DFT變換后的數(shù)據(jù),x(n)為采樣的模擬信號(hào),公式中的x(n)可以為復(fù)信號(hào),實(shí)際當(dāng)中x(n)都是實(shí)信號(hào),即虛部為0,此時(shí)公式可以展開為:
那么,對(duì)于一個(gè) 的序列進(jìn)行不斷分解,就可以得出如下所謂的蝶形圖:
FFT處理蝶形運(yùn)算
蝶形運(yùn)算的規(guī)律:同一級(jí)中所有蝶形的輸入點(diǎn)在同一豎直線上,意味著我們可以按級(jí)來運(yùn)算,對(duì)于M級(jí)的蝶形,編個(gè)M次循環(huán)就好了;所有數(shù)據(jù)點(diǎn)在運(yùn)算后不會(huì)竄位,即計(jì)算后可以將結(jié)果存入原來的地址空間。
每級(jí)N/2個(gè)蝶都需要用到系數(shù)WN,這里稱它為旋轉(zhuǎn)因子。我們來觀察旋轉(zhuǎn)因子WN的規(guī)律。以8點(diǎn)的蝶形圖為例:
可見,第L級(jí)的旋轉(zhuǎn)因子為:
可以看到,每個(gè)蝶的兩個(gè)輸入點(diǎn)下標(biāo)跨度是不一樣的。比如第一級(jí)中是相鄰兩個(gè)數(shù)據(jù)作蝶運(yùn)算,第二級(jí)中是兩個(gè)輸入點(diǎn)隔開一個(gè)點(diǎn),而第三級(jí)隔開三個(gè)點(diǎn)。不難找到規(guī)律:第L級(jí)中,第二個(gè)輸入點(diǎn)的坐標(biāo)是第一個(gè)點(diǎn)的坐標(biāo)+space,space=Math.Pow(2, L)=num。
FFT的算法是寫一個(gè)三重循環(huán):第一重循環(huán)對(duì)每一級(jí)運(yùn)算(每級(jí)含num=Math.Pow(2, L)個(gè)蝶形);
第二重對(duì)每一個(gè)旋轉(zhuǎn)因子對(duì)應(yīng)的蝶運(yùn)算, 那么有幾個(gè)蝶呢?很簡(jiǎn)單,每級(jí)都應(yīng)該有N/2個(gè)蝶,而每個(gè)因子對(duì)應(yīng)N/2 / num個(gè)蝶;
第三重循環(huán)對(duì)每個(gè)蝶進(jìn)行計(jì)算,需要注意的一是循環(huán)下標(biāo)起始點(diǎn)的位置,二是每次計(jì)算需要申明臨時(shí)變量來保存輸入數(shù)據(jù)點(diǎn)。
實(shí)現(xiàn)代碼:
FFT算法的原理是通過許多小的更加容易進(jìn)行的變換去實(shí)現(xiàn)大規(guī)模的變換,降低了運(yùn)算要求,提高了與運(yùn)算速度。FFT不是DFT的近似運(yùn)算,它們完全是等效的。
傅里葉變換的C語言編程
對(duì)于快速傅里葉變換FFT,第一個(gè)要解決的問題就是碼位倒序。假設(shè)一個(gè)N點(diǎn)的輸入序列,那么它的序號(hào)二進(jìn)制數(shù)位數(shù)就是t=log2N。碼位倒序要解決兩個(gè)問題:將t位二進(jìn)制數(shù)倒序;
將倒序后的兩個(gè)存儲(chǔ)單元進(jìn)行交換。如果輸入序列的自然順序號(hào)i用二進(jìn)制數(shù)表示,例如若最大序號(hào)為15,即用4位就可表示n3n2n1n0,則其倒序后j對(duì)應(yīng)的二進(jìn)制數(shù)就是n0n1n2n3。
代碼如下:
復(fù)數(shù)類型定義及其運(yùn)算
#define N 64 //64點(diǎn)
#define log2N 6 //log2N=6
/*復(fù)數(shù)類型*/
typedef struct
{
float real;
float img;
}complex;
complex xdata x[N]; //輸入序列
/*復(fù)數(shù)加法*/
complex add(complex a,complex b)
{
complex c;
c.real=a.real+b.real;
c.img=a.img+b.img;
return c;
}
/*復(fù)數(shù)減法*/
complex sub(complex a,complex b)
{
complex c;
c.real=a.real-b.real;
c.img=a.img-b.img;
return c;
}
/*復(fù)數(shù)乘法*/
complex mul(complex a,complex b)
{
complex c;
c.real=a.real*b.real - a.img*b.img;
c.img=a.real*b.img + a.img*b.real;
return c;
}
/***碼位倒序函數(shù)***/
void Reverse(void)
{
unsigned int i,j,k;
unsigned int t;
complex temp;//臨時(shí)交換變量
for(i=0;i
{
k=i;//當(dāng)前第i個(gè)序號(hào)
j=0;//存儲(chǔ)倒序后的序號(hào),先初始化為0
for(t=0;t
{
j<>
j|=(k&1);//j左移一位然后加上k的最低位
k>>=1;//k右移一位,次低位變?yōu)樽畹臀?/p>
}
if(j>i)//如果倒序后大于原序數(shù),就將兩個(gè)存儲(chǔ)單元進(jìn)行交換(判斷j>i是為了防止重復(fù)交換)
{
temp=x;
x=x[j];
x[j]=temp;
}
}
}
總結(jié):
FFT是離散傅立葉變換的快速算法,可以將一個(gè)信號(hào)變換到頻域。有些信號(hào)在時(shí)域上是很難看出什么特征的,但是如果變換到頻域之后,就很容易看出特征了。這就是很多信號(hào)分析采用FFT變換的原因。另外,FFT可以將一個(gè)信號(hào)的頻譜提取出來,這在頻譜分析方面也是經(jīng)常用的。
總結(jié)
以上是生活随笔為你收集整理的java fft 频谱算法_快速傅里叶变换(FFT)算法原理及代码解析的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: c java 异常_javac -ve
- 下一篇: oracle 创建临时表报权限不足,OR