根据我的理解,它们似乎是多余的?例如,我将一个帧大小为1024的样本块作为输入呈现。因此,我有byte[1024]作为输入。
那么,窗口函数的目的是什么?最初,我认为窗口函数的目的是从原始数据中选择样本块。
谢谢!
窗口函数降低了样本帧开头和结尾的振幅,以减少由此不连续性引起的谐波。
来自National Instruments窗口函数网页的一些示意图:
整数个周期:
非整数周期:
获取更多信息:
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
sin(ω*M/2)/sin(ω/2)
,当ω = 2*π*k/M
时,其中k≠0时为零。对于长度为N的DFT,其中ω = 2*π*n/N
,在n = k * N/M
处存在空值。N/M的比值不一定是整数。例如,如果N = 40,M = 32,则在1.25的倍数处存在空值,但只有整数倍数会出现在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')
注意每个 N/M = 32 个bin处的零点。如果N=M(即窗口长度等于DFT长度),则除n=0外,所有bin处都有零点。
当你将一个窗口乘以一个信号时,在频域中对应的操作是窗口谱与信号谱的循环卷积。例如,正弦波的DTFT是位于正负频率上的加权δ函数(即高度无限、极小的延伸和有限面积的脉冲)。将一个频谱与δ函数卷积只会将其移动到δ的位置,并按δ的权重进行缩放。因此,当你在采样域中将一个窗口乘以一个正弦波时,窗口的频率响应被缩放并移动到正弦波的频率。
关于矩形窗口长度的问题,有几种情况需要考虑。首先让我们看一下窗口长度是正弦波周期的整数倍的情况,例如,一个周期为32/8=4个样本的余弦函数的32个样本矩形窗口:
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')
与以前一样,N/M的倍数为32的地方存在空洞。但是窗口的频谱已经被移动到正弦波的256个bin,并按其幅度缩放,幅度在正频率和负频率之间平分(我只绘制正频率)。如果DFT长度为32,则空洞将在每个bin处排列,引发“看上去不存在泄漏”的外观。但这种误导性的外观只与DFT长度有关。如果您用零填充窗口信号(如上所示),则可以查看空洞之间频率上的sinc响应。
现在让我们来看一个窗口长度不是正弦波周期的整数倍的情况,例如角频率为7.5π/16的cosine(周期为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')
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的倍数处对齐,因此32点DFT的幅度在每个频率点都是非零的。在32点DFT中,窗口的空洞仍然每隔N/M = 32/32 = 1个频率点出现一次,但由于ω0 = 7.5π/16,中心位于第7.5个“频率点”,因此空洞位于0.5、1.5等位置,因此它们不会出现在32点DFT中。
总体来说,窗函数信号的频谱泄漏总是存在的,但如果信号频谱、窗口长度和DFT长度恰好排列成一条直线,则可以在DFT中掩盖这些泄漏。除此之外,应该忽略这些DFT伪像,并集中精力研究信号的DTFT(即通过填充零以更高分辨率采样DTFT,以便清晰地检查泄漏)。
由于卷积窗口的频谱引起的频谱泄漏始终存在,因此制作特定形状的窗口的艺术非常重要。每种窗口类型的频谱都经过了特定任务的调整,例如动态范围或灵敏度。
这里是一个比较矩形窗口和汉明窗口输出的示例:
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()