一、基礎知識
考研階段學習過傅里葉級數,而最近的項目正好是用C語言編寫傅里葉變換,於是很認真的複習了傅里葉級數。可是無奈,看來看去反而暈暈乎乎的。後經師兄師姐的指教,才得知對於工程中的信號處理,研究週期性的傅里葉變換都沒有現實意義,而傅里葉級數更沒有什麼關係。
工程中待處理的信號,通常具有非週期性,故我們需要對離散傅里葉變換進行研究。離散公式:
【x(n)是採樣的時域信號,X(k)是對於不同頻率k的頻域信號。】
而快速傅里葉變換又是對離散傅里葉變換的改進,通過蝶形運算(網上的圖片如下),計算速度可大大提升,使計算量呈指數型下降。
一、最左的x(n)是採樣的時域信號,最右的X(k)是算出的頻域信號。可以看到左邊的x(n)中,n 的序列並非正常的遞增,這是爲了使得輸出的X(k)中的k頻率呈遞增序列。
二、[n]的序列是通過將十進制n轉化成的二進制數字後,倒序排列生成的,如4的二進制碼爲100,倒序爲001,故排在第二位。
三、在上圖中,共8個信號,可分成3級。第一級,每個分組兩個節點,一個蝶形單元。第二級,每個分組四個節點,兩個蝶形單元。第三級,每個分組八個節點,四個蝶形單元。
二、算法語言實現
下面是一段HTML快速傅里葉核心代碼,和C語言差不多:
<span style="font-size:12px;">
void fft(complex f[], int N)
{
complex t, wn;//中間變量
int i, j, k, la, lb, lc, l, r, m, n;//中間變量
//M:分解運算級數
int M;
/*----計算分解的級數M=nextpow2(N)----*/
for (i = N, M = 1; (i = i / 2) != 1; M++);
/*----輸入信號二進制碼位倒序*/
for (i = 1, j = N / 2; i <= N - 2; i++)
{
if (i<j)
{
t = f[j];
f[j] = f[i];
f[i] = t;
}
k = N / 2;
while (k <= j)
{
j = j - k;
k = k / 2;
}
j = j + k;
}
/*----FFT算法----*/
for (m = 1; m <= M; m++)
{
la = pow(2.0, m); //la=2^m代表第m級每個分組所含節點數
lb = la / 2; //lb代表第m級每個分組所含碟形單元數
//同時它也表示每個碟形單元上下節點之間的距離
/*----碟形運算----*/
for (l = 1; l <= lb; l++)
{
r = (l - 1)*pow(double(2), M - m);
for (n = l - 1; n<N - 1; n = n + la) //遍歷每個分組,分組總數爲N/la
{
lc = n + lb; //n,lc分別代表一個碟形單元的上、下節點編號
Wn_i(N, r, &wn, 1);//wn=Wnr
c_mul(f[lc], wn, &t);//t = f[lc] * wn複數運算
c_sub(f[n], t, &(f[lc]));//f[lc] = f[n] - f[lc] * Wnr
c_plus(f[n], t, &(f[n]));//f[n] = f[n] + f[lc] * Wnr
}
}
}
}
</span>