古詩詞大全網 - 古詩大全 - 16點DFT的FFT算法

16點DFT的FFT算法

FFT(快速傅裏葉變換)是DFT的壹種特殊情況,就是當運算點的個數是2的整數次冪的時候進行的運算(不夠用0補齊)。

FFT計算原理及流程圖:

原理:FFT的計算要求點數必須為2的整數次冪,如果點數不夠用0補齊。例如計算{2,3,5,8,4}的16點FFT,需要補11個0後進行計算。FFT計算運用蝶形運算,在蝶形運算中變化規律由W(N, p)推導,其中N為FFT計算點數,J為下角標的值。

L = 1時,W(N, p) = W(N, J) = W(2^L, J),其中J = 0;

L = 2時,W(N, p) = W(N, J) = W(2^L, J),其中J = 0, 1;

L = 3時,W(N, p) = W(N, J) = W(2^L, J),其中J = 0, 1, 2, 3;

所以,W(N, p) = W(2^L, J),其中J = 0, 1, ..., 2^(L-1)-1

又因為2^L = 2^M*2^(L-M) = N*2^(L-M),這裏N為2的整數次冪,即N=2^M,

W(N, p) = W(2^L, J) = W(N*2^(L-M), J) = W(N, J*2^(M-L))

所以,p = J*2^(M-L),此處J = 0, 1, ..., 2^(L-1)-1,當J遍歷結束但計算點數不夠N時,J=J+2^L,後繼續遍歷,直到計算點數為N時不再循環。

流程圖:

實現代碼:

/*======================================================================?

*?方法名:fft?

*?方法功能:計算數組的FFT,運用蝶形運算?

*?

*?變量名稱:?

*yVector?-?原始數據?

*length-?原始數據長度?

*N?-?FFT計算點數?

*fftYreal-?FFT後的實部?

*fftYImg?-?FFT後的虛部?

*?

*?返回值:是否成功的標誌,若成功返回true,否則返回false?

*=====================================================================*/

+?(BOOL)fft:(floatfloat?*)yVector?andOriginalLength:(NSInteger)length?andFFTCount:(NSInteger)N?andFFTReal:(floatfloat?*)fftYReal?andFFTYImg:(floatfloat?*)fftYImg

{

//?確保計算時時2的整數冪點數計算

NSInteger?N1?=?[self?nextNumOfPow2:N];

//?定義FFT運算是否成功的標誌

BOOL?isFFTOK?=?false;

//?判斷計算點數是否為2的整數次冪

if?(N?!=?N1)

{

//?不是2的整數次冪,直接計算DFT

isFFTOK?=?[self?dft:yVector?andOriginalLength:length?andFFTCount:N?andFFTReal:fftYReal?andFFTYImg:fftYImg];

//?返回成功標誌

return?isFFTOK;

}

//?如果計算點數位2的整數次冪,用FFT計算,如下

//?定義變量

float?yVectorN[N1];?//?N點運算的原始數據

NSInteger?powOfN?=?log2(N1);//?N?=?2^powOfN,用於標記最大運算級數(公式中表示為:M)

NSInteger?level?=?1;//?運算級數(第幾次運算),最大為powOfN,初值為第壹級運算(公式中表示為:L)

NSInteger?lineNum;//?行號,倒序排列後的蝶形運算行號(公式中表示為:k)

float?inverseOrderY[N1];//?yVector倒序x

NSInteger?distanceLine?=?1;?//?行間距,第level級運算每個蝶形的兩個節點距離為distanceLine?=?2^(L-1)(公式中表示為:B)

NSInteger?p;//?旋轉因子的階數,旋轉因子表示為?W(N,?p),p?=?J*2^(M-L)

NSInteger?J;//?旋轉因子的階數,旋轉因子表示為?W(2^L,?J),J?=?0,?1,?2,...,?2^(L-1)?-?1?=?distanceLine?-?1

float?realTemp,?imgTemp,?twiddleReal,?twiddleImg,?twiddleTheta,?twiddleTemp?=?PI_x_2/N1;

NSInteger?N_4?=?N1/4;

//?判斷點數是否夠FFT運算點數

if?(length?<=?N1)

{

//?如果N至少為length,先把yVector全部賦值

for?(NSInteger?i?=?0;?i?<?length;?i++)

{

yVectorN[i]?=?yVector[i];

}

if?(length?<?N1)

{

//?如果?N?>?length?後面補零

for?(NSInteger?i?=?length;?i?<?N1;?i++)

{

yVectorN[i]?=?0.0;

}

}

}

else

{

//?如果?N?<?length?截取相應長度的數據進行運算

for?(NSInteger?i?=?0;?i?<?N1;?i++)

{

yVectorN[i]?=?yVector[i];

}

}

//?調用倒序方法

[self?inverseOrder:yVectorN?andN:N1?andInverseOrderVector:inverseOrderY];

//?初始值

for?(NSInteger?i?=?0;?i?<?N1;?i++)

{

fftYReal[i]?=?inverseOrderY[i];

fftYImg[i]?=?0.0;

}

//?三層循環

//?第三層(最裏):完成相同旋轉因子的蝶形運算

//?第二層(中間):完成旋轉因子的變化,步進為2^level

//?第壹層(最外):完成M次叠代過程,即計算出x(k)?=?A0(k),?A1(k),...,Am(k)?=?X(k)

//?第壹層循環

while?(level?<=?powOfN)

{

distanceLine?=?powf(2,?level?-?1);?//?初始條件?distanceLine?=?2^(level-1)

J?=?0;

NSInteger?pow2_Level?=?distanceLine?*?2;?//?2^level

NSInteger?pow2_NSubL?=?N1/pow2_Level;//?2^(M-L)

//?第二層循環

while?(J?<?distanceLine)

{

p?=?J?*?pow2_NSubL;

lineNum?=?J;

NSInteger?stepCount?=?0;?//?J運算的步進計數

//?求旋轉因子

if?(p==0)

{

twiddleReal?=?1.0;

twiddleImg?=?0.0;

}

else?if?(p?==?N_4)

{

twiddleReal?=?0.0;

twiddleImg?=?-1.0;

}

else

{

//?計算尤拉公式中的θ

twiddleTheta?=?twiddleTemp?*?p;

//?計算復數的實部與虛部

twiddleReal?=?cos(twiddleTheta);

twiddleImg?=?-11?*?sin(twiddleTheta);

}

//?第三層循環

while?(lineNum?<?N1)

{

//?計算下角標

NSInteger?footNum?=?lineNum?+?distanceLine;

/*---------------------------------------?

*?用復數運算計算每級中各行的蝶形運算結果?

*?X(k)?=?X(k)?+?X(k+B)*W(N,p)?

*?X(k+B)?=?X(k)?-?X(k+B)*W(N,p)?

*---------------------------------------*/

realTemp?=?fftYReal[footNum]?*?twiddleReal?-?fftYImg[footNum]?*?twiddleImg;

imgTemp=?fftYReal[footNum]?*?twiddleImg?+?fftYImg[footNum]?*?twiddleReal;

//?將計算後的實部和虛部分別存放在返回數組中

fftYReal[footNum]?=?fftYReal[lineNum]?-?realTemp;

fftYImg[footNum]=?fftYImg[lineNum]?-?imgTemp;

fftYReal[lineNum]?=?fftYReal[lineNum]?+?realTemp;

fftYImg[lineNum]=?fftYImg[lineNum]?+?imgTemp;

stepCount?+=?pow2_Level;

//?行號改變

lineNum?=?J?+?stepCount;

}

//?旋轉因子的階數變換,達到旋轉因子改變的效果

J++;

}

//?運算級數加壹

level++;

}

isFFTOK?=?true;

return?isFFTOK;

}