㈠ dft這個函數什麼意思
這是dft變換的函橋睜數呀~~你耐明找個信號處理,和數字數字信號敏畝歲處理 看看dft變換在含義和使用方法就能知道怎麼用了
㈡ 我做「基於FFT演算法與實現」和「FIR濾波器的設計與實現」的實驗。。
1.1 實驗目的
1.了解數字信號處理系統的一般構成;
2.掌握奈奎斯特抽樣定理。
1.2 實驗儀器
1.YBLD智能綜合信號源測試儀 1台
2.雙蹤示波器 1台
3.MCOM-TG305數字信號處理與現代通信技術實驗箱 1台
4.PC機(裝有MATLAB、MCOM-TG305配套實驗軟體) 1台
1.3 實驗原理
一個典型的DSP系統除了數字信號處理部分外,還包括A/D和D/A兩部分。這是因為自然界的信號,如聲音、圖像等大多是模擬信號,因此需要將其數字化後進行數字信號處理,模擬信號的數字化即稱為A/D轉換。數字信號處理後的數據可能需還原為模擬信號,這就需要進行D/A轉換。一個僅包括A/D和D/A兩部分的簡化數字信號處理系統功能如圖1所示。
A/D轉換包括三個緊密相關的過程,即抽樣、量化和編碼。A/D轉換中需解決的以下幾個重要問題:抽樣後輸出信號中還有沒有原始信號的信息?如果有能不能把它取出來?抽樣頻率應該如何選擇?
奈奎斯特抽樣定理(即低通信號的均勻抽樣定理)告訴我們,一個頻帶限制在0至fx以內的低通信號x(t),如果以fs≥2fx的抽樣速率進行均勻抽樣,則x(t)可以由抽樣後的信號xs(t)完全地確定,即xs(t)包含有x(t)的成分,可以通過適當的低通濾波器不失真地恢復出x(t)。最小抽樣速率fs=2fx稱為奈奎斯特速率。
低通
解碼
編碼
量化
抽樣
輸入信號 樣點輸出 濾波輸出
A/D(模數轉換) D/A(數模轉換)
圖1 低通采樣定理演示
為方便實現,實驗中更換了一種表現形式,即抽樣頻率固定(10KHz),通過改變輸入模擬信號的頻率來展示低通抽樣定理。我們可以通過研究抽樣頻率和模擬信號最高頻率分量的頻率之間的關系,來驗證低通抽樣定理。
1.4 實驗內容
1.軟體模擬實驗:編寫並調試MATLAB程序,分析有關參數,記錄有關波形。
2.硬體實驗:輸入不同頻率的正弦信號,觀察采樣時鍾波形、輸入信號波形、樣點輸出波形和濾波輸出波形。
1.5 MATLAB參考程序和模擬內容
%*******************************************************************%
%f—餘弦信號的頻率
% M—基2 FFT冪次數 N=2^M為采樣點數,這樣取值是為了便於作基2的FFT分析
%2. 采樣頻率Fs
%*******************************************************************%
function samples(f,Fs,M)
N=2^M; % fft點數=取樣總點數
Ts=1/Fs; % 取樣時間間隔
T=N*Ts; % 取樣總時間=取樣總點數*取樣時間間隔
n=0:N-1;
t=n*Ts;
Xn=cos(2*f*pi*t);
subplot(2,1,1);
stem(t,Xn);
axis([0 T 1.1*min(Xn) 1.1*max(Xn)]);
xlabel('t -->');
ylabel('Xn');
Xk=abs(fft(Xn,N));
subplot(2,1,2);
stem(n,Xk);
axis([0 N 1.1*min(Xk) 1.1*max(Xk)]);
xlabel('frequency -->');
ylabel('!Xk!');
%*******************************************************************%
假如有一個1Hz的餘弦信號y=cos(2*π*t),對其用4Hz的采樣頻率進行采樣,共采樣32點,只需執行samples(1,4,5),即可得到模擬結果。
軟體模擬實驗內容如下表所示:
模擬參數
f
Fs
Wo(計算)
Xn(圖形)
Xk(圖形)
(1,4,5)
另外記錄圖形,並標圖號
(1,8,5)
(2,8,6)
自 選
1.6 硬體實驗步驟
本實驗箱采樣頻率fs固定為10KHz,低通濾波器的截止頻率約為4.5KHz。
1、用低頻信號源產生正弦信號,正弦信號源頻率f自定,並將其接至2TP2(模擬輸入)端,將示波器通道一探頭接至2TP6(采樣時鍾)端觀察采樣時鍾波形,示波器通道二探頭接至2TP2觀察並記錄輸入信號波形。
2、將示波器通道二探頭接至2TP3觀察並記錄樣點輸出波形。
3、將示波器通道二探頭接至2TP4觀察並記錄濾波輸出波形。
4、根據采樣定理,分f=fs /8、f=fs/4、f=fs/2等3種情況更改正弦信號頻率,重復步驟2至步驟3。
5、用低頻信號源產生方波信號,重復步驟1至步驟4。
1.7 思考題
1、 討論在模擬實驗中所計算的數字域頻率Wo和Xk的圖形中非零譜線位置之間的對應關系。
2、 討論在模擬實驗中自選參數的意義。
3、將在2TP2端加方波信號後的恢復波形,與相同頻率的正弦信號的恢復波形相比,能夠得出哪些結論?
2 FFT頻譜分析實驗
2.1 實驗目的
1.通過實驗加深對快速傅立葉變換(FFT)基本原理的理解。
2.了解FFT點數與頻譜解析度的關系,以及兩種加長序列FFT與原序列FFT的關系。
2.2 實驗儀器
1.YBLD智能綜合信號源測試儀 1台
2.雙蹤示波器 1台
3.MCOM-TG305數字信號處理與現代通信技術實驗箱 1台
4.PC機(裝有MATLAB、MCOM-TG305配套實驗軟體) 1台
2.3 實驗原理
離散傅里葉變換(DFT)和卷積是信號處理中兩個最基本也是最常用的運算,它們涉及到信號與系統的分析與綜合這一廣泛的信號處理領域。實際上卷積與DFT之間有著互通的聯系:卷積可化為DFT來實現,其它的許多演算法,如相關、濾波和譜估計等都可化為DFT來實現,DFT也可化為卷積來實現。
對N點序列x(n),其DFT變換對定義為:
在DFT運算中包含大量的重復運算。FFT演算法利用了蝶形因子WN的周期性和對稱性,從而加快了運算的速度。FFT演算法將長序列的DFT分解為短序列的DFT。N點的DFT先分解為2個N/2點的DFT,每個N/2點的DFT又分解為2個N/4點的DFT。按照此規律,最小變換的點數即所謂的「基數(radix)。」因此,基數為2的FFT演算法的最小變換(或稱蝶形)是2點DFT。一般地,對N點FFT,對應於N個輸入樣值,有N個頻域樣值與之對應。一般而言,FFT演算法可以分為時間抽取(DIT)FFT和頻率抽取(DIF)兩大類。
在實際計算中,可以採用在原來序列後面補0的加長方法來提高FFT的解析度;可以採用在原來序列後面重復的加長方法來增加FFT的幅度。
2.4 實驗內容
1.軟體模擬實驗:分別觀察並記錄正弦序列、方波序列及改變FFT的點數後的頻譜;分別觀察並記錄正弦序列、方波序列及2種加長序列等信號的頻譜。
2.硬體實驗:分別觀察並記錄正弦信號、方波信號及改變FFT的點數後的頻譜。
2.5 MATLAB參考程序和模擬內容
%*******************************************************************%
function[x]=ffts(mode,M)
Nfft=2^M;
x=zeros(1,Nfft); %定義一個長度為Nfft的一維全0數組
if mode= =1 for n=0:Nfft-1 x(n+1)=sin(2*pi*n/Nfft); end
end %定義一個長度為Nfft的單周期正弦序列
if mode= =2 for n=0:Nfft-1 x(n+1)=sin(4*pi*n/Nfft); end
end %定義一個長度為Nfft的雙周期正弦序列
if mode= =3 for n=0:Nfft/2-1 x(n+1)=sin(4*pi*n/Nfft); end
end %定義一個長度為Nfft/2的正弦序列,後面一半為0序列。
if mode= =4 for n=0:Nfft-1 x(n+1)=square(2*pi*n/Nfft); end
end
if mode= =5 for n=0:Nfft-1 x(n+1)=square(2*pi*n/Nfft); end
end
if mode= =6 for n=0:Nfft/2-1 x(n+1)=square(4*pi*n/Nfft); end
end
n=0:Nfft-1;
subplot(2,1,1);
stem(n,x);
axis([0 Nfft-1 1.1*min(x) 1.1*max(x)]);
xlabel('Points-->');
ylabel('x(n)');
X=abs(fft(x,Nfft));
subplot(2,1,2);
stem(n,X);
axis([0 Nfft-1 1.1*min(X) 1.1*max(X)]);
xlabel('frequency-->');
ylabel('!X(k)!');
%*******************************************************************%
假設需觀察方波信號的頻譜,對一個周期的方波信號作32點的FFT,則只需在MATLAB的命令窗口下鍵入:[x]=ffts(21,5) ,程序進行模擬,並且輸出FFT的結果。
關於軟體模擬實驗內容,建議在完成大量模擬例子的基礎上,選擇能夠體現實驗要求的4個以上的例子進行記錄。例如要觀察後面補0的加長方法來提高FFT的解析度的現象,可以模擬ffts(4,5)和ffts(6,6)兩個例子。
2.6 硬體實驗步驟
1.將低頻信號源輸出加到實驗箱模擬通道1輸入端,將示波器探頭接至模擬通道1輸出端。
2.在保證實驗箱正確加電且串口電纜連接正常的情況下,運行數字信號處理與DSP應用實驗開發軟體,在「數字信號處理實驗」菜單下選擇「FFT頻譜分析」子菜單,出現顯示FFT頻譜分析功能提示信息的窗口。
3.用低頻信號產生器產生一個1KHz的正弦信號。
4.選擇FFT頻譜分析與顯示的點數為64點,開始進行FFT運算。此後,計算機將周期性地取回DSP運算後的FFT數據並繪圖顯示
5.改信號源頻率,觀察並記錄頻譜圖的變化。
6.選擇FFT的點數為128點,觀察並記錄頻譜圖的變化。
7.更改正弦信號的頻率,重復步驟4 ~步驟6。
8.用低頻信號產生器產生一個1KHz的方波信號,重復步驟4 ~步驟7。注意:應根據實驗箱采樣頻率fs為10KHz和方波信號的頻帶寬度選擇方波信號的頻率。
本硬體實驗要進行兩種信號,每個信號兩種頻率,每個信號兩種點數等共8次具體實驗內容,性質能夠體現實驗要求的4個以上的例子進行記錄。
2.7 思考題
1.對同一個信號,不同點數FFT觀察到的頻譜圖有何區別?
2.序列加長後FFT與原序列FFT的關系是什麼,試推導其中一種關系。
3.用傅立葉級數理論,試說明正弦信號頻譜和方波信號頻譜之間的關系。
3 IIR濾波器設計實驗
3.1 實驗目的
1.通過實驗加深對IIR濾波器基本原理的理解。
2.學習編寫IIR濾波器的MATLAB模擬程序。
3.2 實驗儀器
1.YBLD智能綜合信號源測試儀 1台
2.雙蹤示波器 1台
3.MCOM-TG305數字信號處理與現代通信技術實驗箱 1台
4.PC機(裝有MATLAB、MCOM-TG305配套實驗軟體) 1台
3.3 實驗原理
IIR濾波器有以下幾個特點:
1.IIR數字濾波器的系統函數可以寫成封閉函數的形式。
2.IIR數字濾波器採用遞歸型結構,即結構上帶有反饋環路。IIR濾波器運算結構通常由延時、乘以系數和相加等基本運算組成,可以組合成直接型、正准型、級聯型、並聯型四種結構形式,都具有反饋迴路。由於運算中的舍入處理,使誤差不斷累積,有時會產生微弱的寄生振盪。
3.IIR數字濾波器在設計上可以藉助成熟的模擬濾波器的成果,如巴特沃斯、契比雪夫和橢圓濾波器等,有現成的設計數據或圖表可查,其設計工作量比較小,對計算工具的要求不高。在設計一個IIR數字濾波器時,我們根據指標先寫出模擬濾波器的公式,然後通過一定的變換,將模擬濾波器的公式轉換成數字濾波器的公式。
4.IIR數字濾波器的相位特性不好控制,對相位要求較高時,需加相位校準網路。
在MATLAB下設計IIR濾波器可使用Butterworth函數設計出巴特沃斯濾波器,使用Cheby1函數設計出契比雪夫I型濾波器,使用Cheby2設計出契比雪夫II型濾波器,使用ellipord函數設計出橢圓濾波器。下面主要介紹前兩個函數的使用。
與FIR濾波器的設計不同,IIR濾波器設計時的階數不是由設計者指定,而是根據設計者輸入的各個濾波器參數(截止頻率、通帶濾紋、阻帶衰減等),由軟體設計出滿足這些參數的最低濾波器階數。在MATLAB下設計不同類型IIR濾波器均有與之對應的函數用於階數的選擇。
一、巴特沃斯IIR濾波器的設計
在MATLAB下,設計巴特沃斯IIR濾波器可使用butter函數。
Butter函數可設計低通、高通、帶通和帶阻的數字和模擬IIR濾波器,其特性為使通帶內的幅度響應最大限度地平坦,但同時損失截止頻率處的下降斜度。在期望通帶平滑的情況下,可使用butter函數。
butter函數的用法為:
[b,a]=butter(n,Wn,/ftype/)
其中n代表濾波器階數,Wn代表濾波器的截止頻率,這兩個參數可使用buttord函數來確定。buttord函數可在給定濾波器性能的情況下,求出巴特沃斯濾波器的最小階數n,同時給出對應的截止頻率Wn。buttord函數的用法為:
[n,Wn]= buttord(Wp,Ws,Rp,Rs)
其中Wp和Ws分別是通帶和阻帶的拐角頻率(截止頻率),其取值范圍為0至1之間。當其值為1時代表采樣頻率的一半。Rp和Rs分別是通帶和阻帶區的波紋系數。
不同類型(高通、低通、帶通和帶阻)濾波器對應的Wp和Ws值遵循以下規則:
1.高通濾波器:Wp和Ws為一元矢量且Wp>Ws;
2.低通濾波器:Wp和Ws為一元矢量且Wp<Ws;
3.帶通濾波器:Wp和Ws為二元矢量且Wp<Ws,如Wp=[0.2,0.7],Ws=[0.1,0.8];
4.帶阻濾波器:Wp和Ws為二元矢量且Wp>Ws,如Wp=[0.1,0.8],Ws=[0.2,0.7]。
二、契比雪夫I型IIR濾波器的設計
在期望通帶下降斜率大的場合,應使用橢圓濾波器或契比雪夫濾波器。在MATLAB下可使用cheby1函數設計出契比雪夫I型IIR濾波器。
cheby1函數可設計低通、高通、帶通和帶阻契比雪夫I型濾IIR波器,其通帶內為等波紋,阻帶內為單調。契比雪夫I型的下降斜度比II型大,但其代價是通帶內波紋較大。
cheby1函數的用法為:
[b,a]=cheby1(n,Rp,Wn,/ftype/)
在使用cheby1函數設計IIR濾波器之前,可使用cheblord函數求出濾波器階數n和截止頻率Wn。cheblord函數可在給定濾波器性能的情況下,選擇契比雪夫I型濾波器的最小階和截止頻率Wn。
cheblord函數的用法為:
[n,Wn]=cheblord(Wp,Ws,Rp,Rs)
其中Wp和Ws分別是通帶和阻帶的拐角頻率(截止頻率),其取值范圍為0至1之間。當其值為1時代表采樣頻率的一半。Rp和Rs分別是通帶和阻帶區的波紋系數。
3.4 實驗內容
1.軟體模擬實驗:編寫並調試MATLAB程序,選擇不同形式,不同類型的4種濾波器進行模擬,記錄幅頻和相頻特性,對比巴特沃斯濾波器和契比雪夫濾波器。
2.硬體實驗:設計IIR濾波器,在計算機上觀察沖激響應、幅頻特性和相頻特性,然後下載到實驗箱。用示波器觀察輸入輸出波形,測試濾波器的幅頻響應特性。
3.5 MATLAB參考程序和模擬內容
%*******************************************************************%
%mode: 1--巴特沃斯低通;2--巴特沃斯高通;3--巴特沃斯帶通;4--巴特沃斯帶阻
% 5--契比雪夫低通;6--契比雪夫高通;7--契比雪夫帶通;8--契比雪夫帶阻
%fp1,fp2: 通帶截止頻率,當高通或低通時只有fp1有效
%fs1, fs2: 阻帶截止頻率,當高通或低通時只有fs1有效
%rp: 通帶波紋系數
%as: 阻帶衰減系數
%sample: 采樣率
%h: 返回設計好的濾波器系數
%*******************************************************************%
function[b,a]=iirfilt(mode,fp1,fp2,fs1,fs2,rp,as,sample)
wp1=2*fp1/sample;wp2=2*fp2/sample;
ws1=2*fs1/sample;ws2=2*fs2/sample;
%得到巴特沃斯濾波器的最小階數N和3bd頻率wn
if mode<3[N,wn]=buttord(wp1,ws1,rp,as);
elseif mode<5[N,wn]=buttord([wp1 wp2],[ws1 ws2],rp,as);
%得到契比雪夫濾波器的最小階數N和3bd頻率wn
elseif mode<7[N,wn]=cheb1ord(wp1,ws1,rp,as);
else[N,wn]=cheblord([wp1 wp2],[ws1 ws2],rp,as);
end
%得到濾波器系數的分子b和分母a
if mode= =1[b,a]=butter(N,wn);end
if mode= =2[b,a]=butter(N,wn,/high/);end
if mode= =3[b,a]=butter(N,wn);end
if mode= =4[b,a]=butter(N,wn,/stop/);end
if mode= =5[b,a]=cheby1(N,rp,wn);end
if mode= =6[b,a]=cheby1(N,rp,wn,/high/);end
if mode= =7[b,a]=cheby1(N,rp,wn);end
if mode= =8[b,a]=cheby1(N,rp,wn,/stop/);end
set(gcf,/menubar/,menubar);
freq_response=freqz(b,a);
magnitude=20*log10(abs(freq_response));
m=0:511;
f=m*sample/(2*511);
subplot(3,1,1);plot(f,magnitude);grid; %幅頻特性
axis([0 sample/2 1.1*min(magnitude) 1.1*max(magnitude)]);
ylabel('Magnitude');xlabel('Frequency-->');
phase=angle(freq_response);
subplot(3,1,2);plot(f,phase);grid; %相頻特性
axis([0 sample/2 1.1*min(phase) 1.1*max(phase)]);
ylabel('Phase');xlabel('Frequency-->');
h=impz(b,a,32); %32點的單位函數響應
t=1:32;
subplot(3,1,3);stem(t,h);grid;
axis([0 32 1.2*min(h) 1.1*max(h)]);
ylabel('h(n)');xlabel('n-->');
%*******************************************************************%
假設需設計一個巴特沃斯低通IIR濾波器,通帶截止頻率為2KHz,阻帶截止頻率為3KHz,通帶波紋系數為1,阻帶衰減系數為20,采樣頻率為10KHz,則只需在MATLAB的命令窗口下鍵入:
[b,a]=iirfilt(1,2000,3000,2400,2600,1,20,10000)
程序進行模擬,並且按照如下順序輸出數字濾波器系統函數
的系數
b= b0 b1 ……bn
a= a0 a1 ……an
關於軟體模擬實驗內容,建議在完成大量模擬例子的基礎上,選擇能夠體現實驗要求的4個例子進行記錄,系統函數只要記錄系統的階數。
3.6 硬體實驗步驟
1.根據實驗箱采樣頻率fs為10KHz的條件,用低頻信號發生器產生一個頻率合適的低頻正弦信號,將其加到實驗箱模擬通道1輸入端,將示波器通道1探頭接至模擬通道1輸入端,通道2探頭接至模擬通道2輸出端。
2.在保證實驗箱正確加電且串口電纜連接正常的情況下,運行數字信號處理與DSP應用實驗開發軟體,在「數字信號處理實驗」菜單下選擇「IIR濾波器」子菜單,出現提示信息。
3.輸入濾波器類型、濾波器截止頻率等參數後,分別點擊「幅頻特性」和「相頻特性」按鈕,在窗口右側觀察IIR濾波器的幅頻特性和相頻特性。此時提示信息將消失,如需查看提示信息,可點擊「設計說明」按鈕。
4.點擊「下載實現」按鈕,IIR濾波器開始工作,此時窗口右側將顯示IIR濾波器的幅頻特性。
5.根據輸入濾波器類型,更改低頻信號源的頻率,觀察示波器上輸入輸出波形幅度的變化情況,測量IIR濾波器的幅頻響應特性,看其是否與設計的幅頻特性一致。
6.更改濾波器類型、濾波器截止頻率等參數(共4種),重復步驟3至步驟5。所選擇的例子參數最好和MATLAB模擬程序的例子一樣。
7.用低頻信號產生器產生一個500Hz的方波信號,分別設計3種濾波器,完成如下表要求的功能,並且記錄參數和波形。
功 能
濾波器類型
參 數
輸出波形
fp1
fp2
fs1
fs2
通過3次及以下次數的諧波
另外記錄圖形,並標圖號
濾除5次及以下次數的諧波
通過3次到5次的諧波
3.7 思考題
1.在實驗箱采樣頻率fs固定為10KHz的條件下,要觀察方波信號頻帶寬度內的各個諧波分量,方波信號的頻率最高不能超過多少,為什麼?
2.硬體實驗內容7中輸出信號各個諧波分量,與原來方波信號同樣諧波分量相比,有沒有發生失真?主要發生了什麼類型的失真?為什麼?
4 窗函數法FIR濾波器設計實驗
4.1 實驗目的
1.通過實驗加深對FIR濾波器基本原理的理解。
2.學習使用窗函數法設計FIR濾波器,了解窗函數的形式和長度對濾波器性能的影響。
4.2 實驗儀器
1.YBLD智能綜合信號源測試儀 1台
2.雙蹤示波器 1台
3.MCOM-TG305數字信號處理與現代通信技術實驗箱 1台
4.PC機(裝有MATLAB、MCOM-TG305配套實驗軟體) 1台
4.3 實驗原理
數字濾波器的設計是數字信號處理中的一個重要內容。數字濾波器設計包括FIR(有限單位脈沖響應)濾波器與IIR(無限單位脈沖響應)濾波器兩種。
與IIR濾波器相比,FIR濾波器在保證幅度特性滿足技術要求的同時,很容易做到嚴格的線性相位特性。設FIR濾波器單位脈沖響應h(n)長度為N,其系統函數H(z)為:
H(z)是z-1的N-1次多項式,它在z平面上有N-1個零點,原點z=0是N-1階重極點,因此H(z)是永遠穩定的。穩定和線性相位特性是FIR濾波器突出的優點。
FIR濾波器的設計任務是選擇有限長度的h(n)。使傳輸函數H( )滿足技術要求。FIR濾波器的設計方法有多種,如窗函數法、頻率采樣法及其它各種優化設計方法,本實驗介紹窗函數法的FIR濾波器設計。
窗函數法是使用矩形窗、三角窗、巴特利特窗、漢明窗、漢寧窗和布萊克曼窗等設計出標准響應的高通、低通、帶通和帶阻FIR濾波器。
一、firl函數的使用
在MATLAB下設計標准響應FIR濾波器可使用firl函數。firl函數以經典方法實現加窗線性相位FIR濾波器設計,它可以設計出標準的低通、帶通、高通和帶阻濾波器。firl函數的用法為:
b=firl(n,Wn,/ftype/,Window)
各個參數的含義如下:
b—濾波器系數。對於一個n階的FIR濾波器,其n+1個濾波器系數可表示為:b(z)=b(1)+b(2)z-1+…+b(n+1)z-n。
n—濾波器階數。
Wn—截止頻率,0≤Wn≤1,Wn=1對應於采樣頻率的一半。當設計帶通和帶阻濾波器時,Wn=[W1 W2],W1≤ω≤W2。
ftype—當指定ftype時,可設計高通和帶阻濾波器。Ftype=high時,設計高通FIR濾波器;ftype=stop時設計帶阻FIR濾波器。低通和帶通FIR濾波器無需輸入ftype參數。
Window—窗函數。窗函數的長度應等於FIR濾波器系數個數,即階數n+1。
二、窗函數的使用
在MATLAB下,這些窗函數分別為:
1.矩形窗:w=boxcar(n),產生一個n點的矩形窗函數。
2.三角窗:w=triang(n),產生一個n點的三角窗函數。
當n為奇數時,三角窗系數為w(k)=
當n為偶數時,三角窗系數為w(k)=
3.巴特利特窗:w=Bartlett(n),產生一個n點的巴特利特窗函數。
巴特利特窗系數為w(k)=
巴特利特窗與三角窗非常相似。巴特利特窗在取樣點1和n上總以零結束,而三角窗在這些點上並不為零。實際上,當n為奇數時bartlett(n)的中心n-2個點等效於triang(n-2)。
4.漢明窗:w=hamming(n),產生一個n點的漢明窗函數。
漢明窗系數為w(k+1)=0.54-0.46cos( ) k=0,…,n-1
5.漢寧窗:w=hanning(n),產生一個n點的漢寧窗函數。
漢寧窗系數為w(k)=0.5[1-cos( )] k=1,…,n
6.布萊克曼窗:w=Blackman(n),產生一個n點的布萊克曼窗函數。
布萊克曼窗系數為w(k)=0.42-0.5cos(2π )+0.8cos(4π )] k=1,…,n
與等長度的漢明窗和漢寧窗相比,布萊克曼窗的主瓣稍寬,旁瓣稍低。
7.凱澤窗:w=Kaiser(n,beta),產生一個n點的凱澤窗數,其中beta為影響窗函數旁瓣的β參數,其最小的旁瓣抑制α與β的關系為:
0.1102(α-0.87) α>50
β= 0.5842(α-21)0.4+0.07886(α-21) 21≤α≤50
0 α<21
增加β可使主瓣變寬,旁瓣的幅度降低。
8.契比雪夫窗:w=chebwin(n,r)產生一個n點的契比雪夫窗函數。其傅里葉變換後的旁瓣波紋低於主瓣r個db數。
4.4 實驗內容
1.軟體模擬實驗:編寫並調試MATLAB程序,觀察不同窗,不同類型濾波器不同點數等共4種FIR濾波器的h(n),並記錄幅頻特性和相頻特性。
2.硬體實驗:用窗函數法設計標准響應的FIR濾波器,在計算機上觀察窗函數幅頻特性、幅頻特性和相頻特性,然後下載到實驗箱。用示波器觀察輸入輸出波形,測試濾波器的幅頻響應特性。
4.5 MATLAB參考程序和模擬內容
%*******************************************************************%
%mode: 模式(1--高通;2--低通;3--帶通;4--帶阻)
%n: 階數,加窗的點數為階數加1
%fp: 高通和低通時指示截止頻率,帶通和帶阻時指示下限頻率
%fs: 帶通和帶阻時指示上限頻率
%window:加窗(1--矩形窗;2--三角窗;3--巴特利特窗;4--漢明窗;
% 5--漢寧窗;6--布萊克曼窗;7--凱澤窗;8--契比雪夫窗)
%r: 代表加chebyshev窗的r值和加kaiser窗時的beta值
%sample: 采樣率
%h: 返回設計好的FIR濾波器系數
%*******************************************************************%
%mode: 模式(1--高通;2--低通;3--帶通;4--帶阻)
%n: 階數,加窗的點數為階數加1
%fp: 高通和低通時指示截止頻率,帶通和帶阻時指示下限頻率
%fs:
㈢ 求FFT的c語言程序
快速傅里葉變換 要用C++ 才行吧 你可以用MATLAB來實現更方便點啊
此FFT 是用VC6.0編寫,由FFT.CPP;STDAFX.H和STDAFX.CPP三個文件組成,編譯成功。程序可以用文件輸入和輸出為文件。文件格式為TXT文件。測試結果如下:
輸入文件:8.TXT 或手動輸入
8 //N
1
2
3
4
5
6
7
8
輸出結果為:或保存為TXT文件。(8OUT.TXT)
8
(36,0)
(-4,9.65685)
(-4,4)
(-4,1.65685)
(-4,0)
(-4,-1.65685)
(-4,-4)
(-4,-9.65685)
下面為FFT.CPP文件:
// FFT.cpp : 定義控制台應用程序的入口點。
#include "stdafx.h"
#include <iostream>
#include <complex>
#include <bitset>
#include <vector>
#include <conio.h>
#include <string>
#include <fstream>
using namespace std;
bool inputData(unsigned long &, vector<complex<double> >&); //手工輸入數據
void FFT(unsigned long &, vector<complex<double> >&); //FFT變換
void display(unsigned long &, vector<complex<double> >&); //顯示結果
bool readDataFromFile(unsigned long &, vector<complex<double> >&); //從文件中讀取數據
bool saveResultToFile(unsigned long &, vector<complex<double> >&); //保存結果至文件中
const double PI = 3.1415926;
int _tmain(int argc, _TCHAR* argv[])
{
vector<complex<double> > vecList; //有限長序列
unsigned long ulN = 0; //N
char chChoose = ' '; //功能選擇
//功能循環
while(chChoose != 'Q' && chChoose != 'q')
{
//顯示選擇項
cout << "\nPlease chose a function" << endl;
cout << "\t1.Input data manually, press 'M':" << endl;
cout << "\t2.Read data from file, press 'F':" << endl;
cout << "\t3.Quit, press 'Q'" << endl;
cout << "Please chose:";
//輸入選擇
chChoose = getch();
//判斷
switch(chChoose)
{
case 'm': //手工輸入數據
case 'M':
if(inputData(ulN, vecList))
{
FFT(ulN, vecList);
display(ulN, vecList);
saveResultToFile(ulN, vecList);
}
break;
case 'f': //從文檔讀取數據
case 'F':
if(readDataFromFile(ulN, vecList))
{
FFT(ulN, vecList);
display(ulN, vecList);
saveResultToFile(ulN, vecList);
}
break;
}
}
return 0;
}
bool Is2Power(unsigned long ul) //判斷是否是2的整數次冪
{
if(ul < 2)
return false;
while( ul > 1 )
{
if( ul % 2 )
return false;
ul /= 2;
}
return true;
}
bool inputData(unsigned long & ulN, vector<complex<double> >& vecList)
{
//題目
cout<< "\n\n\n==============================Input Data===============================" << endl;
//輸入N
cout<< "\nInput N:";
cin>>ulN;
if(!Is2Power(ulN)) //驗證N的有效性
{
cout<< "N is invalid (N must like 2, 4, 8, .....), please retry." << endl;
return false;
}
//輸入各元素
vecList.clear(); //清空原有序列
complex<double> c;
for(unsigned long i = 0; i < ulN; i++)
{
cout << "Input x(" << i << "):";
cin >> c;
vecList.push_back(c);
}
return true;
}
bool readDataFromFile(unsigned long & ulN, vector<complex<double> >& vecList) //從文件中讀取數據
{
//題目
cout<< "\n\n\n===============Read Data From File==============" << endl;
//輸入文件名
string strfilename;
cout << "Input filename:" ;
cin >> strfilename;
//打開文件
cout << "open file " << strfilename << "......." <<endl;
ifstream loadfile;
loadfile.open(strfilename.c_str());
if(!loadfile)
{
cout << "\tfailed" << endl;
return false;
}
else
{
cout << "\tsucceed" << endl;
}
vecList.clear();
//讀取N
loadfile >> ulN;
if(!loadfile)
{
cout << "can't get N" << endl;
return false;
}
else
{
cout << "N = " << ulN << endl;
}
//讀取元素
complex<double> c;
for(unsigned long i = 0; i < ulN; i++)
{
loadfile >> c;
if(!loadfile)
{
cout << "can't get enough infomation" << endl;
return false;
}
else
cout << "x(" << i << ") = " << c << endl;
vecList.push_back(c);
}
//關閉文件
loadfile.close();
return true;
}
bool saveResultToFile(unsigned long & ulN, vector<complex<double> >& vecList) //保存結果至文件中
{
//詢問是否需要將結果保存至文件
char chChoose = ' ';
cout << "Do you want to save the result to file? (y/n):";
chChoose = _getch();
if(chChoose != 'y' && chChoose != 'Y')
{
return true;
}
//輸入文件名
string strfilename;
cout << "\nInput file name:" ;
cin >> strfilename;
cout << "Save result to file " << strfilename << "......" << endl;
//打開文件
ofstream savefile(strfilename.c_str());
if(!savefile)
{
cout << "can't open file" << endl;
return false;
}
//寫入N
savefile << ulN << endl;
//寫入元素
for(vector<complex<double> >::iterator i = vecList.begin(); i < vecList.end(); i++)
{
savefile << *i << endl;
}
//寫入完畢
cout << "save succeed." << endl;
//關閉文件
savefile.close();
return true;
}
void FFT(unsigned long & ulN, vector<complex<double> >& vecList)
{
//得到冪數
unsigned long ulPower = 0; //冪數
unsigned long ulN1 = ulN - 1;
while(ulN1 > 0)
{
ulPower++;
ulN1 /= 2;
}
//反序
bitset<sizeof(unsigned long) * 8> bsIndex; //二進制容器
unsigned long ulIndex; //反轉後的序號
unsigned long ulK;
for(unsigned long p = 0; p < ulN; p++)
{
ulIndex = 0;
ulK = 1;
bsIndex = bitset<sizeof(unsigned long) * 8>(p);
for(unsigned long j = 0; j < ulPower; j++)
{
ulIndex += bsIndex.test(ulPower - j - 1) ? ulK : 0;
ulK *= 2;
}
if(ulIndex > p)
{
complex<double> c = vecList[p];
vecList[p] = vecList[ulIndex];
vecList[ulIndex] = c;
}
}
//計算旋轉因子
vector<complex<double> > vecW;
for(unsigned long i = 0; i < ulN / 2; i++)
{
vecW.push_back(complex<double>(cos(2 * i * PI / ulN) , -1 * sin(2 * i * PI / ulN)));
}
for(unsigned long m = 0; m < ulN / 2; m++)
{
cout<< "\nvW[" << m << "]=" << vecW[m];
}
//計算FFT
unsigned long ulGroupLength = 1; //段的長度
unsigned long ulHalfLength = 0; //段長度的一半
unsigned long ulGroupCount = 0; //段的數量
complex<double> cw; //WH(x)
complex<double> c1; //G(x) + WH(x)
complex<double> c2; //G(x) - WH(x)
for(unsigned long b = 0; b < ulPower; b++)
{
ulHalfLength = ulGroupLength;
ulGroupLength *= 2;
for(unsigned long j = 0; j < ulN; j += ulGroupLength)
{
for(unsigned long k = 0; k < ulHalfLength; k++)
{
cw = vecW[k * ulN / ulGroupLength] * vecList[j + k + ulHalfLength];
c1 = vecList[j + k] + cw;
c2 = vecList[j + k] - cw;
vecList[j + k] = c1;
vecList[j + k + ulHalfLength] = c2;
}
}
}
}
void display(unsigned long & ulN, vector<complex<double> >& vecList)
{
cout << "\n\n===========================Display The Result=========================" << endl;
for(unsigned long d = 0; d < ulN;d++)
{
cout << "X(" << d << ")\t\t\t = " << vecList[d] << endl;
}
}
下面為STDAFX.H文件:
// stdafx.h : 標准系統包含文件的包含文件,
// 或是常用但不常更改的項目特定的包含文件
#pragma once
#include <iostream>
#include <tchar.h>
// TODO: 在此處引用程序要求的附加頭文件
下面為STDAFX.CPP文件:
// stdafx.cpp : 只包括標准包含文件的源文件
// FFT.pch 將成為預編譯頭
// stdafx.obj 將包含預編譯類型信息
#include "stdafx.h"
// TODO: 在 STDAFX.H 中
//引用任何所需的附加頭文件,而不是在此文件中引用
㈣ 離散傅立葉變換(DFT)和快速演算法(FFT)的區別是什麼
fft就是dft的快速坦辯演算法, 結果讓陸缺是一樣的。
應該不會有這個差別。 搞不懂悉御就貼圖看看
這個差別在於, 補0再fft這里0是不受你前面減mean的影響的, 所以你前面減東西相當於是減一個矩形, 所以fft的結果相當於減一個Sa,所以就會對形狀有一些影響。 其實如果不是你選了一個過於短的列, 也不會有這么明顯影響的
㈤ C語言 FFTW 二維
ELEM這個數答塌配組是為了確定二維數組的每個值的確定位置,因衫弊為你申請的in和out都是1維數組(不考慮實部虛部那個0和1)所以要確定在你開辟的這個1維數組中所對應的二維數組是哪個數就用到了ELEM,舉個例子,比如你算二維數組[r,c]這個位置的值,其實是在一維數組的第r*N+c個數,所以就得到了in[r*N+c][0],清指也就是在做fft之前的fftw_complex表示,樓主可能混淆fftw_complex和文中ELEM數組了,ELEM並不是fftw_complex數組的表示,只是為了找到確定數組位置的一個中間數組而已,希望回答能讓你滿意
㈥ C語言計算基波幅值和功率因數,高人指點!
很高深啊
㈦ 離散傅里葉變換的C語言實現代碼
int DFT(int dir,int m,double *x1,double *y1)
{
long i,k;
double arg;
double cosarg,sinarg;
double *x2=NULL,*y2=NULL;
x2=malloc(m*sizeof(double));
y2=malloc(m*sizeof(double));
if(x2==NULL||y2==NULL)return(FALSE);
for(i=0;i<m;i++)
{
x2[i]=0;
y2[i]=0;
arg=-dir*2.0*3.141592654*(double)i/(double)m;
for(k=0;k<m;k++)
{
cosarg=cos(k*arg);
sinarg=sin(k*arg);
x2[i]+=(x1[k]*cosarg-y1[k]*sinarg);
y2[i]+=(x1[k]*sinarg+y1[k]*cosarg);
}
}
/*Copythedataback*/
if(dir==1)
{
for(i=0;i<m;i++)
{
x1[i]=x2[i]/(double)m;
y1[i]=y2[i]/(double)m;
}
}
else
{
for(i=0;i<m;i++)
{
x1[i]=x2[i];
y1[i]=y2[i];
}
}
free(x2);
free(y2);
return(TRUE);
}
㈧ FFT , DTFT, DFT 的區別和聯系
FFT ,DTFT,DFT的聯系:FFT是DFT的一種高效快速演算法,DFT是有限長序列的離散傅里葉變換,DTFT是非周期序列的傅里葉變換,DFT將信號的時域采樣變換為其DTFT的頻域采樣。
FFT , DTFT, DFT 的區別是含義不同、性質不同、用途不同。
1、含義不同:DTFT是離散時間傅里葉變換,DFT是離散傅里葉變換,FFT是DFT的一種高效快速演算法,也稱作快速傅里葉變換。
2、性質不同:DTFT變換後的圖形中的頻率是一般連續的(cos(wn)等這樣的特殊函數除外,其變換後是沖擊串),而DFT是DTFT的等間隔抽樣,是離散的點。
快速傅里葉變換FFT其實是一種對離散傅里葉變換的快速演算法,它的出現解決了離散傅里葉散中變換的計算量極大、不實用的問題,使離散傅里葉變換的計算量降低了 一個或幾個數量級,從而使離散傅里葉變換得到了廣泛應用。
3、用途不同:DFT完全是應計算機技術的發展而來的,因為如果沒有計算機,用DTFT分析看頻率響應就可以,為了適應計算機計算,那麼就必須要用離散的值,因為計算機不能處理連續的值,FFT是為了提高速度而來。另外,FFT的出現也解決了相當多的計算問題,使得其它計算也可以通過FFT來解決。
(8)dft變換c語言擴展閱讀
DTFT是以2pi為周期的。而DFT的序列X(k)是棚渣有限長的。
DTFT是以復指數序列{exp(-jwn)}的加權和來表示的,而DFT是等間隔抽樣,DFT裡面有個重要的參數就是N,抽樣間隔就是將單位元分成N個間隔來抽樣,繞圓一周,(2*pi)/N是間隔(一個圓周是2*pi,分成N個等分)
DTFT和DFT都能表徵原序列的信鏈掘悄息。因為現在計算主要使用計算機,必需要是離散的值才能參與運算,因此在工程中DFT應用比較廣泛,DFT還有一個快速演算法,那就是FFT。
㈨ 離散傅里葉變換的用DFT對模擬信號進行譜分析
在工程實際中經常遇到的模擬信號xn(t),其頻譜函數Xn(jΩ)也是連續函數,為了利用DFT對xn(t)進行譜分析,對xn(t)進行時域采樣得到x(n)= xn(nT),再對x(n)進行DFT,得到X(k)則是x(n)的傅里葉變換X(ejω)在頻率區間[0,2π]上的N點等間隔采樣,這里x(n)和X(k)都是有限長序列
然而,傅里葉變換理論證明,時間有限長的信號其頻譜是無限寬的,反之,弱信號的頻譜有限款的則其持續時間將為無限長,因此,按采樣定理采樣時,采樣序列應為無限長,這不滿足DFT的條件。實際中,對於頻譜很寬的信號,為防止時域采樣後產生『頻譜混疊』,一般用前置濾波器濾除幅度較小的高頻成分,使信號的貸款小於折疊頻率;同樣對於持續時間很長的信號,采樣點數太多也會導致存儲和計算困難,一般也是截取有限點進行計算。上述可以看出,用DFT對模擬信號進行譜分析,只能是近似的,其近似程度取決於信號帶寬、采樣頻率和截取長度
模擬信號xn(t)的傅里葉變換對為
X(jΩ)={-∞,+∞}x(t)*exp^-jΩt dt
x(t)=1/2π{-∞,+∞} X(JΩ)*e^jΩt dt
用DFT方法計算這對變換對的方法如下:
(a)對xn(t)以T為間隔進行采樣,即xn(t)|t=nT= xa(nT)= x(n),由於
t→nT,dt→T, {-∞,+∞}→∑n={-∞,+∞}
因此得到
X(jΩ)≈∑n={-∞,+∞}x(nT)*exp^-jΩnT*T
x(nT)≈1/2π{0, Ωs} X(JΩ)*e^jΩnT Dω
(b)將序列x(n)= xn(t)截斷成包含有N個抽樣點的有限長序列
X(jΩ)≈T∑n={0,N-1}x(nT)*exp^-jΩnT*T
由於時域抽樣,抽樣頻率為fs=1/T,則頻域產生以fs為周期的周期延拓,如果頻域是帶限信號,則有可能不產生頻譜混疊,成為連續周期頻譜序列,頻譜的周期為fs=1/T
(c)為了數值計算,頻域上也要抽樣,即在頻域的一個周期中取N個樣點,fs=NF0,每個樣點間隔為F0,頻域抽樣使頻域的積分式變成求和式,而在時域就得到原來已經截斷的離散時間序列的周期延拓,時間周期為T0=1/F0。因此有
Ω→kΩ0,dΩ→Ω0,{-∞,+∞} dΩ→∑n={-∞,+∞}Ω0
T0=1/F0=N/fs=NT
Ω0=2ΠF0
Ω0T=Ω0/fs=2π/N
X(jkΩ0)≈T∑n={0,N-1}x(nT)*exp^-jkΩ0nT
㈩ 基於FFT的演算法優化 要C語言完整程序(利用旋轉因子的性質),有的請留言,答謝!!!(有核心代碼,望指教
實現(C描述)
#include <stdio.h>
#include <math.h>
#include <stdlib.h>
//#include "complex.h"
// --------------------------------------------------------------------------
#define N 8 //64
#define M 3 //6 //2^m=N
#define PI 3.1415926
// --------------------------------------------------------------------------
float twiddle[N/2] = {1.0, 0.707, 0.0, -0.707};
float x_r[N] = {1, 1, 1, 1, 0, 0, 0, 0};
float x_i[N]; //N=8
/*
float twiddle[N/2] = {1, 0.9951, 0.9808, 0.9570, 0.9239, 0.8820, 0.8317, 0.7733,
0.7075, 0.6349, 0.5561, 0.4721, 0.3835, 0.2912, 0.1961, 0.0991,
0.0000,-0.0991,-0.1961,-0.2912,-0.3835,-0.4721,-0.5561,-0.6349,
-0.7075,-0.7733, 0.8317,-0.8820,-0.9239,-0.9570,-0.9808,-0.9951}; //N=64
float x_r[N]={1,1,1,1,1,1,1,1,
1,1,1,1,1,1,1,1,
1,1,1,1,1,1,1,1,
1,1,1,1,1,1,1,1,
0,0,0,0,0,0,0,0,
0,0,0,0,0,0,0,0,
0,0,0,0,0,0,0,0,
0,0,0,0,0,0,0,0,};
float x_i[N];
*/
FILE *fp;
// ----------------------------------- func -----------------------------------
/**
* 初始化輸出虛部
*/
static void fft_init( void )
{
int i;
for(i=0; i<N; i++) x_i[i] = 0.0;
}
/**
* 反轉演算法.將時域信號重新排序.
* 這個演算法有改進的空間
*/
static void bitrev( void )
{
int p=1, q, i;
int bit_rev[ N ]; //
float xx_r[ N ]; //
bit_rev[ 0 ] = 0;
while( p < N )
{
for(q=0; q<p; q++)
{
bit_rev[ q ] = bit_rev[ q ] * 2;
bit_rev[ q + p ] = bit_rev[ q ] + 1;
}
p *= 2;
}
for(i=0; i<N; i++) xx_r[ i ] = x_r[ i ];
for(i=0; i<N; i++) x_r[i] = xx_r[ bit_rev[i] ];
}
/* ------------ add by sshc625 ------------ */
static void bitrev2( void )
{
return ;
}
/* */
void display( void )
{
printf("\n\n");
int i;
for(i=0; i<N; i++)
printf("%f\t%f\n", x_r[i], x_i[i]);
}
/**
*
*/
void fft1( void )
{ fp = fopen("log1.txt", "a+");
int L, i, b, j, p, k, tx1, tx2;
float TR, TI, temp; // 臨時變數
float tw1, tw2;
/* 深M. 對層進行循環. L為當前層, 總層數為M. */
for(L=1; L<=M; L++)
{
fprintf(fp,"----------Layer=%d----------\n", L);
/* b的意義非常重大,b表示當前層的顆粒具有的輸入樣本點數 */
b = 1;
i = L - 1;
while(i > 0)
{
b *= 2;
i--;
}
// -------------- 是否外層對顆粒循環, 內層對樣本點循環邏輯性更強一些呢! --------------
/*
* outter對參與DFT的樣本點進行循環
* L=1, 循環了1次(4個顆粒, 每個顆粒2個樣本點)
* L=2, 循環了2次(2個顆粒, 每個顆粒4個樣本點)
* L=3, 循環了4次(1個顆粒, 每個顆粒8個樣本點)
*/
for(j=0; j<b; j++)
{
/* 求旋轉因子tw1 */
p = 1;
i = M - L; // M是為總層數, L為當前層.
while(i > 0)
{
p = p*2;
i--;
}
p = p * j;
tx1 = p % N;
tx2 = tx1 + 3*N/4;
tx2 = tx2 % N;
// tw1是cos部分, 實部; tw2是sin部分, 虛數部分.
tw1 = ( tx1>=N/2)? -twiddle[tx1-N/2] : twiddle[ tx1 ];
tw2 = ( tx2>=N/2)? -twiddle[tx2-(N/2)] : twiddle[tx2];
/*
* inner對顆粒進行循環
* L=1, 循環了4次(4個顆粒, 每個顆粒2個輸入)
* L=2, 循環了2次(2個顆粒, 每個顆粒4個輸入)
* L=3, 循環了1次(1個顆粒, 每個顆粒8個輸入)
*/
for(k=j; k<N; k=k+2*b)
{
TR = x_r[k]; // TR就是A, x_r[k+b]就是B.
TI = x_i[k];
temp = x_r[k+b];
/*
* 如果復習一下 (a+j*b)(c+j*d)兩個復數相乘後的實部虛部分別是什麼
* 就能理解為什麼會如下運算了, 只有在L=1時候輸入才是實數, 之後層的
* 輸入都是復數, 為了讓所有的層的輸入都是復數, 我們只好讓L=1時候的
* 輸入虛部為0
* x_i[k+b]*tw2是兩個虛數相乘
*/
fprintf(fp, "tw1=%f, tw2=%f\n", tw1, tw2);
x_r[k] = TR + x_r[k+b]*tw1 + x_i[k+b]*tw2;
x_i[k] = TI - x_r[k+b]*tw2 + x_i[k+b]*tw1;
x_r[k+b] = TR - x_r[k+b]*tw1 - x_i[k+b]*tw2;
x_i[k+b] = TI + temp*tw2 - x_i[k+b]*tw1;
fprintf(fp, "k=%d, x_r[k]=%f, x_i[k]=%f\n", k, x_r[k], x_i[k]);
fprintf(fp, "k=%d, x_r[k]=%f, x_i[k]=%f\n", k+b, x_r[k+b], x_i[k+b]);
} //
} //
} //
}
/**
* ------------ add by sshc625 ------------
* 該實現的流程為
* for( Layer )
* for( Granule )
* for( Sample )
*
*
*
*
*/
void fft2( void )
{ fp = fopen("log2.txt", "a+");
int cur_layer, gr_num, i, k, p;
float tmp_real, tmp_imag, temp; // 臨時變數, 記錄實部
float tw1, tw2;// 旋轉因子,tw1為旋轉因子的實部cos部分, tw2為旋轉因子的虛部sin部分.
int step; // 步進
int sample_num; // 顆粒的樣本總數(各層不同, 因為各層顆粒的輸入不同)
/* 對層循環 */
for(cur_layer=1; cur_layer<=M; cur_layer++)
{
/* 求當前層擁有多少個顆粒(gr_num) */
gr_num = 1;
i = M - cur_layer;
while(i > 0)
{
i--;
gr_num *= 2;
}
/* 每個顆粒的輸入樣本數N' */
sample_num = (int)pow(2, cur_layer);
/* 步進. 步進是N'/2 */
step = sample_num/2;
/* */
k = 0;
/* 對顆粒進行循環 */
for(i=0; i<gr_num; i++)
{
/*
* 對樣本點進行循環, 注意上限和步進
*/
for(p=0; p<sample_num/2; p++)
{
// 旋轉因子, 需要優化...
tw1 = cos(2*PI*p/pow(2, cur_layer));
tw2 = -sin(2*PI*p/pow(2, cur_layer));
tmp_real = x_r[k+p];
tmp_imag = x_i[k+p];
temp = x_r[k+p+step];
/*(tw1+jtw2)(x_r[k]+jx_i[k])
*
* real : tw1*x_r[k] - tw2*x_i[k]
* imag : tw1*x_i[k] + tw2*x_r[k]
* 我想不抽象出一個
* typedef struct {
* double real; // 實部
* double imag; // 虛部
* } complex; 以及針對complex的操作
* 來簡化復數運算是否是因為效率上的考慮!
*/
/* 蝶形演算法 */
x_r[k+p] = tmp_real + ( tw1*x_r[k+p+step] - tw2*x_i[k+p+step] );
x_i[k+p] = tmp_imag + ( tw2*x_r[k+p+step] + tw1*x_i[k+p+step] );
/* X[k] = A(k)+WB(k)
* X[k+N/2] = A(k)-WB(k) 的性質可以優化這里*/
// 旋轉因子, 需要優化...
tw1 = cos(2*PI*(p+step)/pow(2, cur_layer));
tw2 = -sin(2*PI*(p+step)/pow(2, cur_layer));
x_r[k+p+step] = tmp_real + ( tw1*temp - tw2*x_i[k+p+step] );
x_i[k+p+step] = tmp_imag + ( tw2*temp + tw1*x_i[k+p+step] );
printf("k=%d, x_r[k]=%f, x_i[k]=%f\n", k+p, x_r[k+p], x_i[k+p]);
printf("k=%d, x_r[k]=%f, x_i[k]=%f\n", k+p+step, x_r[k+p+step], x_i[k+p+step]);
}
/* 開跳!:) */
k += 2*step;
}
}
}
/*
* 後記:
* 究竟是顆粒在外層循環還是樣本輸入在外層, 好象也差不多, 復雜度完全一樣.
* 但以我資質愚鈍花費了不少時間才弄明白這數十行代碼.
* 從中我發現一個於我非常有幫助的教訓, 很久以前我寫過一部分演算法, 其中絕大多數都是遞歸.
* 將數據量減少, 減少再減少, 用歸納的方式來找出數據量加大代碼的規律
* 比如FFT
* 1. 先寫死LayerI的代碼; 然後再把LayerI的輸出作為LayerII的輸入, 又寫死代碼; ......
* 大約3層就可以統計出規律來. 這和遞歸也是一樣, 先寫死一兩層, 自然就出來了!
* 2. 有的功能可以寫偽代碼, 不急於求出結果, 降低復雜性, 把邏輯結果定出來後再添加.
* 比如旋轉因子就可以寫死, 就寫1.0. 流程出來後再寫旋轉因子.
* 寥寥數語, 我可真是流了不少汗! Happy!
*/
void dft( void )
{
int i, n, k, tx1, tx2;
float tw1,tw2;
float xx_r[N],xx_i[N];
/*
* clear any data in Real and Imaginary result arrays prior to DFT
*/
for(k=0; k<=N-1; k++)
xx_r[k] = xx_i[k] = x_i[k] = 0.0;
// caculate the DFT
for(k=0; k<=(N-1); k++)
{
for(n=0; n<=(N-1); n++)
{
tx1 = (n*k);
tx2 = tx1+(3*N)/4;
tx1 = tx1%(N);
tx2 = tx2%(N);
if(tx1 >= (N/2))
tw1 = -twiddle[tx1-(N/2)];
else
tw1 = twiddle[tx1];
if(tx2 >= (N/2))
tw2 = -twiddle[tx2-(N/2)];
else
tw2 = twiddle[tx2];
xx_r[k] = xx_r[k]+x_r[n]*tw1;
xx_i[k] = xx_i[k]+x_r[n]*tw2;
}
xx_i[k] = -xx_i[k];
}
// display
for(i=0; i<N; i++)
printf("%f\t%f\n", xx_r[i], xx_i[i]);
}
// ---------------------------------------------------------------------------
int main( void )
{
fft_init( );
bitrev( );
// bitrev2( );
//fft1( );
fft2( );
display( );
system( "pause" );
// dft();
return 1;
}
本文來自CSDN博客,轉載請標明出處:http://blog.csdn.net/sshcx/archive/2007/06/14/1651616.aspx