離散傅里葉變換DFT與FFT,MATLAB的FFT函數使用(原創)——如何使用fft()繪製出真正的頻譜圖像

以前一直對MATLAB中fft()函數的使用一直存在疑惑,爲什麼要加一
些參數,並且如何確定這些參數,也查了許多資料,但很多都感覺只是
表面一說根本沒有講清其本質。但隨着學習的推進,慢慢有所領悟,所
以打算把自己的一些所懂分享下,有什麼問題也希望大家指正。
本文主要先對DFT、FFT的一些概念進行介紹,然後通過MATLAB仿真
進行fft()分析,從而解釋上述參數。

一、DFT與FFT
首先是對DFT與FFT的一些概念上的介紹,其實FFT與DFT是等價的,他們實現的功能是一樣的,只是FFT是DFT的算法優化,因爲畢竟要用電腦來計算,DFT算的太慢了,就優化下也就成了FFT。所以此處我們對DFT與FFT的介紹是等價的。
那麼我們就來介紹DFT,它也被叫做離散傅里葉變換,其實它就是DFS離散傅里葉級數的時域頻域主值序列,或者也是DTFT離散時間傅里葉變換的頻域採樣。至於DFS與DTFT相信大家也是明白,那麼很多人好奇爲什麼還要DFT這玩意,主要呢,還是因爲計算機,因爲計算機不可能處理無限長的信號而DFS和DTFT要麼時域無限長,要麼頻域無限長,所以就搞了個DFT。
好的,那麼我們就來直接看公式(這裏我就假想大家都對其來源及原因都清楚了):
在這裏插入圖片描述

在這裏插入圖片描述
注意看上圖,這就是我們接下來的所有依據,X(k)是正變換,x(n)反變換,此處務必注意x(n)那個式子有個1/N,這對後面的理解很關鍵。
好的那麼接下來我們就可以利用MATLAB來進行分析了。

二、MATLAB的FFT函數使用
首先說明下什麼情況下我們要用FFT,這是很簡單的,但還是要說說:因爲現實世界都是連續的信號,相信我們要分析它時單純靠我們人算是很麻煩的,所有這些都是需要計算機進行計算,那麼答案就有了,我們其實都是處理連續信號,也就是說我們都是想要FFT來分析連續信號。
OK
1、那麼這樣FFT第一個步驟就出現了,那就是A/D轉換,也就是對連續信號採樣。而這裏我們就要確定一個參數採樣頻率Fs,說到採樣,大家肯定會想到採樣定理,其內容就是當對信號進行以採樣頻率爲Fs>=2fc的採樣時,信息不急丟失(fc爲原始連續信號的最大截止頻率),那麼這樣第一個參數Fs就這樣確定了,其應該滿足Fs>=2fc,這時採樣週期爲Ts=1/Fs。
2、既然確定了採樣頻率Fs,那麼我們就要想信號的時域應該怎麼確定,換句話說,我們將採樣好的信號給計算機處理時,應該給計算機多少個。這裏就出現了第二個參數即序列個數L,好的,在這裏由於第一個參數確定的Fs,相應的也是採樣週期Ts,所以我們就可以得出時域信號的橫座標時間的變化範圍,也就是
t=(0:L-1)Ts
那麼這裏就確定了N嗎?不,我們這裏還沒確定,對於L的確立我們需要上面這個語句的幫助。那麼究竟怎麼確定呢,這裏我們就要想到DFT的來源了:爲什麼DFT可以用來進行表示信號的頻譜響應,因爲其時域頻域都是信號的相應時域頻域的主值區間,所以說我們要用DTF可以表示這個信號時,應儘可能的包含這個信號的一個週期或整數倍週期也就是上述t的範圍應該是信號的一個週期範圍或整數倍週期範圍,否則則會發生頻譜泄露,至於頻譜泄露其實就是出現了本來沒有的頻率分量。比如說,10Hz的cos(2π10t),本來只有一種頻率分量f=10Hz,但分析結果卻包含了與10Hz頻率相近的其它頻率分量。下述將會進行仿真分析。所以說此處L的確定應是LxTs=mT(T爲信號的最小週期,m爲正整數),常常m=1。那麼或許有人問怎麼平常我看到的都不是這樣,L都是取和Fs一樣的值(注意爲了頻率分辨率爲1Hz,下文會討論)。其實對於這個也有它的道理,不妨我們推到下:
LxTs=L/Fs=1,也就是說其表達的時域t範圍爲1,那麼平常我們的信號最小週期一般都小於1的,要是當信號最小週期大於1時其就是錯誤的啦,所以這個只是對大部分來說是有用的。
那麼說了這麼多究竟怎麼確定,要是按LxTs=mT確定會不會太麻煩,確實有時我們真的不能知道確定的信號最小週期,所以這裏就放寬點,只要
保證LxTs>=T
就可以,當然如果可以取整數倍就最好了。
OK
可是上面說又會發生頻率泄露,這可怎麼辦?那麼這裏就只能儘可能提高N-DFT的N點啦,這樣能使儘可能更多的能量落到正確的頻率點上,也就是說這樣誤差會更小,這樣就能達到我們的目的。
3、於是第三個參數N-DFT的N就出現了,根據上述2情況,我們知道N的提高有利於提高精確的,那麼它還有其它約束嗎?答案肯定有的,這裏就需要些理論知識了:
先來了解下頻域採樣定理:頻域以N點爲採樣週期的採樣,在時域就是原序列的以週期N的延拓
那麼這樣也就是說上述2中的序列長度L必須小於或等於N,否則就會發生時域混疊,所以說L>=N這就是限制條件,常常我們取L=N,當發生頻譜泄露比較嚴重時我們就可以考慮將L增大,這樣就可以減小頻譜泄露的的影響。

綜上,以上就是MATLAB相關的所有參數了,它們分別就採樣頻率Fs,原序列長度L,N-DFT變換的N,其主要確定關係總結如下:
Fs>=2fc(fc爲信號最高截止頻率)
LxTs>=T(T爲信號的最小週期,若能取LxTs=T則應儘可能取,可以避免頻譜泄露)
N>=L(N常常應爲2^m,因爲FFT運算就是不斷模2進行DFT,所以N爲2的次方利於提高速度)
對於其常取值,Fs=1024,N=1024,L=1024,注意滿足上述條件就好

說完了這些參數,我們就講講MATLAB的fft函數,其用法主要Y=fft(x,N),x爲原信號序列,Y爲DFT(也就是FFT)變換後的,但是大家會發現其變換後幅度變了而且變了很大,其實就是跟最初的那個式子有關,其頻域幅值增大了N倍
在這裏插入圖片描述
並且發現其橫軸也都是整數,所以這時也要對其橫軸座標進行變換,即要乘以相應的頻率分辨率Fs/N,所以說上面爲什麼,常常也取Fs=L,N=L,這樣爲了頻率分辨率爲1Hz,對於這些我們需用以下MATLAB語句進行實現

Y=fft(x,N);%N一定到大於信號序列x的長度,不過一般等於,決不能小於
%因爲若要小於時域就會發生混疊
Y=abs(Y);
Y=Y./N;
%Y=Y.*2./N;Y(1)=Y(1)./2;若考慮將負頻率的幅度折算到正頻率時應這樣處理
%因爲變換後有個N的乘積因子的影響,根據DFT公式可知,故消除其影響
f=(0:N-1)*Fs./N;
%頻率正常化,因爲變換後橫座標是每個點對應的個數,故應轉化成實際的頻率
%由於頻譜是對稱的,且週期的故常常只畫一半如下
subplot(2,1,1);
plot(f(1:N/2),Y(1:N./2));
%當然也可以畫平常我們見到的有對稱的如下
f=f-Fs./2;
subplot(212);
plot(f,fftshift(Y));

上述代碼也有相關解釋,那麼我也就對相關幾個語句進行介紹解釋:
f=(0:N-1)*Fs./N;這是N-DFT變換後的橫軸座標,也就是真實頻率值;
Y=Y./N;這是對DFT變換後幅值處理,也就是要除於N纔是真實的幅值
%Y=Y.*2./N;Y(1)=Y(1)./2;而這個是鑑於無真實的負頻率,其與正頻率對稱的原理,把負頻率去掉,全變爲正頻率的幅值處理。

下面語句是爲了變成我們平常看到有正負頻率的圖像
f=f-Fs./2;
subplot(212);
plot(f,fftshift(Y));

三、仿真試驗
OK接下來就是仿真試驗啦。
我們直接考慮x(t)=cos(2π10t);其週期T=0.1s,fc=10Hz
1、首先考慮Fs=512,L=512,N=512,滿足上述三個關係吧,
Fs=512>=2fc;LxTs=1s>=T(也是10T,故沒頻率泄露);N=512>=L=512;那麼我們看下仿真結果是否對得到:
在這裏插入圖片描述
可以看到只有一個頻率,可以完全表示,故與上述推理一樣。代碼如下

Fs=512;%採樣頻率
Ts=1/Fs;%採樣週期
N=512;%N—DFT
L=512;%原信號序列長度
t=(0:L-1).*Ts;%時域自變量
x=cos(10*2*pi*t);%原信號
subplot(311);
plot(t,x);
title("原信號")
xlabel("t/s")
grid on
Y=fft(x,N);%fft變換
Y=abs(Y)./N;%實際幅值變換
f=(0:N-1)*Fs./N;%實際頻率變換
subplot(312);
plot(f(1:N/2),Y(1:N./2));
title("N-DFT變換幅頻響應單邊")
xlabel("f/Hz")
grid on
f=f-Fs./2;%移位
subplot(313);
plot(f,fftshift(Y));%移位
title("N-DFT變換幅頻響應雙邊")
xlabel("f/Hz")
grid on

2、那麼我們再來考慮Fs=512,L=128,N=128,滿足上述三個關係吧,
Fs=512>=2fc;LxTs=0.15s>=T(不是T的整數倍,故有頻率泄露);N=128>=L=128;那麼我們看下仿真結果是否對得到(這次頻譜用stem繪製更明顯點):
在這裏插入圖片描述
可以看到出現了些不應該出現的頻率,也驗證了我們的推論,其代碼如下:

Fs=512;%採樣頻率
Ts=1/Fs;%採樣週期
N=128;%N—DFT
L=128;%原信號序列長度
t=(0:L-1).*Ts;%時域自變量
x=cos(10*2*pi*t);%原信號
subplot(311);
plot(t,x);
title("原信號")
xlabel("t/s")
grid on
Y=fft(x,N);%fft變換
Y=abs(Y)./N;%實際幅值變換
f=(0:N-1)*Fs./N;%實際頻率變換
subplot(312);
stem(f(1:N/2),Y(1:N./2));
title("N-DFT變換幅頻響應單邊")
xlabel("f/Hz")
grid on
f=f-Fs./2;%移位
subplot(313);
stem(f,fftshift(Y));%移位
title("N-DFT變換幅頻響應雙邊")
xlabel("f/Hz")
grid on

3、那麼我們再來看下增大N點是否可以減小頻譜泄露的影響,考慮Fs=512,L=128,N=1024,滿足上述三個關係吧,
Fs=512>=2fc;LxTs=0.15s>=T(不是T的整數倍,故有頻率泄露);N=1024>=L=128;那麼我們看下仿真結果是否對得到(這次頻譜用stem繪製更明顯點):
在這裏插入圖片描述
很明顯可以看到與N=128時,其往所求正確頻率處更靠近集中,故增大N可以減小頻率響應的影響。代碼如下:

Fs=512;%採樣頻率
Ts=1/Fs;%採樣週期
N=1024;%N—DFT
L=128;%原信號序列長度
t=(0:L-1).*Ts;%時域自變量
x=cos(10*2*pi*t);%原信號
subplot(311);
plot(t,x);
title("原信號")
xlabel("t/s")
grid on
Y=fft(x,N);%fft變換
Y=abs(Y)./N;%實際幅值變換
f=(0:N-1)*Fs./N;%實際頻率變換
subplot(312);
stem(f(1:N/2),Y(1:N./2));
title("N-DFT變換幅頻響應單邊")
xlabel("f/Hz")
grid on
f=f-Fs./2;%移位
subplot(313);
stem(f,fftshift(Y));%移位
title("N-DFT變換幅頻響應雙邊")
xlabel("f/Hz")
grid on

4、最後看下它可不可ifft()變回去:
在這裏插入圖片描述
這是對於1的ifft只在後面加上下述代碼:

figure
subplot(211)
plot(t,x)
title("原信號")
xlabel("t/s")
grid on
Y=fft(x);
xx=ifft(Y);
subplot(212)
plot(t,xx)
title("ifft原信號")
xlabel("t/s")
grid on

所以ifft變換時,應把一開始的N因子變回去。
對於非週期信號,其原理差不多,關鍵是時域能否儘可能取到一個週期等,或者對於無限長的信號,只能採取截取出其中最主要的信息了。

綜上,差不多就這樣了,可能多少有些問題,歡迎大家指正互相進步。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章