2011-02-16 71 views
7

我想了解FFT算法,到目前爲止我認爲我理解它背後的主要概念。不過,我對'framesize'和'window'之間的區別感到困惑。與FFT算法混淆

根據我的理解,它們似乎彼此是多餘的?例如,我將輸入的一個樣本塊的幀大小設置爲1024.因此,我將字節[1024]顯示爲輸入。

那麼窗口函數的目的是什麼?自從開始以來,我認爲窗口函數的目的是從原始數據中選擇樣本塊。

謝謝!

回答

13

那麼窗口函數的目的是什麼?

這是要處理所謂的「頻譜泄漏」:FFT假定無限序列,重複給定的樣本幀一遍又一遍。如果你的樣本幀中有一個正弦波是整數個週期,那麼所有的都是好的,FFT在適當的頻率給你一個很好的窄峯。但是如果你有一個不是整數個週期的正弦波,最後一個和第一個樣本之間會有一個不連續點,而FFT會給你提供假的諧波。

窗口函數降低了採樣幀開始和結束時的幅度,以減少由這種不連續性引起的諧波。

National Instruments webpage on windowing一些圖:

週期積分#:循環

enter image description here

非整數#:

enter image description here

的其他信息:

http://www.tmworld.com/article/322450-Windowing_Functions_Improve_FFT_Results_Part_I.php

http://zone.ni.com/reference/en-XX/help/371361B-01/lvanlsconcepts/char_smoothing_windows/

http://www.physik.uni-wuerzburg.de/~praktiku/Anleitung/Fremde/ANO14.pdf

+0

稀釋我明白了。所以基本上,窗口函數只是爲了改進FFT算法的結果而修改或改進樣本中的數據。我對嗎?謝謝! – user488792 2011-02-16 04:00:04

+0

@ user488792:是的,這幾乎就是它 - 窗口函數*平滑了否則在採樣窗口邊緣會出現瞬態。 – 2011-02-16 09:11:14

+0

是的,我明白了。非常感謝您的澄清和提供一個很好的答案! – user488792 2011-02-16 13:54:52

2

如果不修改的樣本值,並選擇數據作爲FFT長度的相同的長度,這等同於使用矩形窗口,在其中情況下框架和窗口是相同的。然而,將輸入數據乘以時域中的矩形窗口與將輸入信號的頻譜與頻域中的Sinc函數進行卷積相同,這將在頻域中的FFT孔徑中不完全週期性地頻散任何頻譜峯值整個頻譜。

通常使用非矩形窗口,因此得到的FFT頻譜與Sinc函數相比有更多「聚焦」的卷積。

您還可以使用與FFT長度或光圈不同的矩形窗口。在數據窗口較短的情況下,FFT幀可以被填充爲零,這可以導致更平滑的內插FFT結果頻譜。您甚至可以使用矩形窗口,該窗口的長度大於FFT的長度,方法是通過以循環合計的方式將數據包裹在FFT窗口周圍,以獲得頻率分辨率的一些有趣效果。

ADDED由於請求:

通過在時域中的窗口相乘產生相同的結果作爲與該窗口的在頻域中變換進行卷積。

一般來說,一個更窄的時域窗口產生更寬的頻域變換。這是零填充產生更平滑頻率圖的原因。較窄的時域窗口產生更寬的Sinc,與幀寬度相比,相對於幀寬度更豐富和更平滑的曲線,從而使內插頻率結果看起來比其相同的非零填充FFT更平滑幀長度。

反過來在一定程度上也是如此。更寬的矩形窗口將產生更窄的Sinc,空值更接近峯值。因此,您可能可以使用精心選擇的較寬窗口來產生更窄的外觀Sinc,以便將頻率更接近感興趣的頻段的頻率設置爲低於1頻率範圍。你如何使用更寬的窗戶?將數據包裹起來並進行求和,這與使用未被截斷爲1FFT幀長的FT基向量相同。但是,由於這樣做時FFT結果向量比數據更短,這是一個有損耗的過程,它將引入僞像,並引入一些新的混疊。但它會給你在每個bin上更尖銳的頻率選擇峯值,並且可以放置在小於1 bin的位置上的陷波濾波器,比如在bin之間的中間等。

6

長度爲M的矩形窗口的頻率響應爲sin(ω*M/2)/sin(ω/2),對於k≠0,當ω = 2*π*k/M爲零。對於長度爲N的DFT,其中ω = 2*π*n/N,在n = k * N/M處存在空值。比率N/M不一定是整數。例如,如果N = 40,M = 32,那麼在1.25的倍數處有零點,但在DFT中將僅出現整數倍數,在這種情況下是DFT 5,10,15和20。

這裏的一個32點的矩形窗口的1024點DFT的曲線圖:

M = 32 
N = 1024 
w = ones(M) 
W = rfft(w, N) 
K = N/M 
nulls = abs(W[K::K]) 
plot(abs(W)) 
plot(r_[K:N/2+1:K], nulls, 'ro') 
xticks(r_[:512:64]) 
grid(); axis('tight') 

DFT of a 32-point rectangular window

注意在每一個N/M = 32的二進制位的空值。如果N = M(即窗口長度等於DFT長度),則除了n = 0之外的所有窗口中都有空值。

當您將窗口乘以信號時,頻域中的對應操作是窗口頻譜與信號頻譜的循環卷積。例如,正弦曲線的DTFT是位於正弦曲線的正頻率和負頻率的加權德爾塔函數(即具有無限高度,無窮小延伸和有限區域的脈衝)。使用delta函數來描述頻譜只是將其轉換到三角洲的位置並按三角洲的權重進行縮放。因此,當您在樣本域中用正弦曲線乘以一個窗口時,窗口的頻率響應會縮放並轉換爲正弦曲線的頻率。

有幾種情況可以檢查矩形窗口的長度。首先讓我們看看窗口長度是正弦曲線週期的整數倍的情況,例如,餘弦的32個樣本的矩形窗口週期爲32/8 = 4個樣本:

x1 = cos(2*pi*8*r_[:32]/32) # ω0 = 8π/16, bin 8/32 * 1024 = 256 
X1 = rfft(x1 * w, 1024) 
plot(abs(X1)) 
xticks(r_[:513:64]) 
grid(); axis('tight') 

DFT of cosine at w0 = 8π/16 with a 32-point rectangular window

如前,有在N/M = 32,但該窗口的倍數空頻譜已經轉移到正弦曲線的二進制256,並按正弦頻率和負頻率(我只繪製正頻率)之間的0.5倍進行縮放。如果DFT長度爲32,那麼空值將在每個垃圾箱中排隊,這提示外觀沒有泄漏。但是這種誤導性的外觀只是DFT長度的一個函數。如果你用零填充窗口信號(如上),你將會看到空值之間頻率的類似於sinc的響應。

現在讓我們看看窗口長度不是正弦曲線週期的整數倍的情況,例如,用的7.5π/ 16的角頻率的餘弦(週期爲64個樣品):

x2 = cos(2*pi*15*r_[:32]/64) # ω0 = 7.5π/16, bin 15/64 * 1024 = 240 
X2 = rfft(x2 * w, 1024) 
plot(abs(X2)) 
xticks(r_[-16:513:64]) 
grid(); axis('tight') 

DFT of cosine at w0 = 7.5π/16 with a 32-point rectangular window

中心倉位置不再在32的整數倍,但由一個半錯開下降到倉240.所以讓我們看看相應的32點DFT是什麼樣子的(推斷32點矩形窗口)。我會計算並繪製X2 [N]的32點DFT,併疊加1024點DFT的32倍抽取副本:

X2_32 = rfft(x2, 32) 
X2_sample = X2[::32] 
stem(r_[:17],abs(X2_32)) 
plot(abs(X2_sample), 'rs') # red squares 
grid(); axis([0,16,0,11]) 

32-point DFT of cosine at w0 = 7.5π/16

正如你在前面的情節看,零點不再以32的倍數對齊,所以32點DFT的大小在每個bin處都是非零的。在32點DFT中,窗口的零點仍然以N/M = 32/32 = 1 bin爲間隔,但由於ω0=7.5π/ 16,中心位於'bin'7.5,零點爲0.5,1.5等等,所以他們不在32點DFT中。

的一般信息是,一個窗信號的頻譜泄漏是總是存在,但可以在DFT被掩蔽,如果信號specrtum,窗口長度,並且DFT長度在只是以正確的方式來一起排隊空。除此之外,您應該忽略這些DFT僞像,並專注於信號的DTFT(即填充零點以更高分辨率對DTFT進行採樣,以便您可以清楚地檢查泄漏)。

由窗口光譜的卷積引起的光譜泄漏將始終存在,這就是爲什麼製作特殊形狀窗戶的藝術如此重要。每個窗口類型的頻譜都針對特定任務進行了定製,例如動態範圍或靈敏度。

這裏的一個矩形窗的輸出進行比較Vs的漢明窗的示例:

from pylab import * 
import wave 

fs = 44100 
M = 4096 
N = 16384 
# load a sample of guitar playing an open string 6 
# with a fundamental frequency of 82.4 Hz 
g = fromstring(wave.open('dist_gtr_6.wav').readframes(-1), 
       dtype='int16') 
L = len(g)/4 
g_t = g[L:L+M] 
g_t = g_t/float64(max(abs(g_t))) 
# compute the response with rectangular vs Hamming window 
g_rect = rfft(g_t, N) 
g_hamm = rfft(g_t * hamming(M), N) 

def make_plot(): 
    fmax = int(82.4 * 4.5/fs * N) # 4 harmonics 
    subplot(211); title('Rectangular Window') 
    plot(abs(g_rect[:fmax])); grid(); axis('tight') 
    subplot(212); title('Hamming Window') 
    plot(abs(g_hamm[:fmax])); grid(); axis('tight') 

if __name__ == "__main__": 
    make_plot() 

rectangular vs hamming window