他们都同属于升余弦家族,只是常数不一样。
注意,所以不管是hann还是hamming都在处相等。
hann
标准写法
中心对称写法
什么是窗函数的中心对称
其实这两个写法是等价的,只是第二种把“对称中心”给显式写出来了
定义:一个长度为的窗函数$\omegaii_c =\frac{N-1}{2}\omega[i_c+k]=\omega[i_c -k]i_c$,左右完全一样。
这里就会出现两种情况:
N为奇数
中点则为结果是一个整数;
这里以为例,得出
则对应关系为:
w[0]<->w[6]
w[1]<->w[5]
w[2]<->w[4]
w[3]和自己相对,自己是中心
N为偶数
中点则为结果是个小数以结尾;
这里以举例,
则对应关系为:
w[0]<->w[7]
w[1]<->w[6]
w[2]<->w[5]
w[3]<->w[4]
所以这个并不是随便写的,而是偶数长度时中心点落在两个采样点之间的自然结果
代码演示
我们可以用代码来验证一下
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21
| import numpy as np import matplotlib.pyplot as plt plt.rcParams['font.sans-serif'] = ['SimHei'] plt.rcParams['axes.unicode_minus'] = False
fig, axes = plt.subplots(1, 2, figsize=(12, 4))
for ax, N in zip(axes, [7, 8]): i = np.arange(N) w = 0.5 - 0.5 * np.cos(2 * np.pi * i / (N - 1)) ax.plot(i, w, 'o-', color='steelblue') ax.axvline((N - 1) / 2, color='red', linestyle='--', label=f'对称轴 i={(N-1)/2}') ax.set_title(f'N={N}({"奇数" if N%2 else "偶数"})') ax.set_xlabel('i') ax.set_ylabel('w[i]') ax.grid(alpha=0.3) ax.legend()
plt.tight_layout() plt.show()
|

最常见的Hann窗的写法是:
当然也可以写成:
从公式中看不出“对称中心”在哪,因为余弦是从扫到的对称轴在中间。
对称
我们首先定义为相对中心的偏移。
则原式为:
- x的范围为:,关于0对称
- 是偶函数则
- 所以关于对称,也就是关于对称
当 时:
当时:
综上所述的作用就是把余弦的对称中心从平移到窗的中点
hamming
和Hann只差一个常数:
上面说过hann和hamming的中心处都等于1,所以中心对称的写法:
hamming两端不为0,时为了让窗函数在边界处的一阶不连续变小,从而压低第一旁瓣。
时域和频域的对比
时域
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21
| import numpy as np import matplotlib.pyplot as plt plt.rcParams['font.sans-serif'] = ['SimHei'] plt.rcParams['axes.unicode_minus'] = False
N = 64 n = np.arange(N)
w_hann = 0.5 - 0.5 * np.cos(2 * np.pi * n / (N - 1)) w_hamm = 0.54 - 0.46 * np.cos(2 * np.pi * n / (N - 1))
plt.figure(figsize=(10, 4)) plt.plot(n, w_hann, 'o-', label='Hann', markersize=4) plt.plot(n, w_hamm, 's--', label='Hamming', markersize=4) plt.title('Hann vs Hamming 时域 (N=64)') plt.xlabel('n') plt.ylabel('w[n]') plt.legend() plt.grid(alpha=0.3) plt.show()
|

频域
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35
| import numpy as np import matplotlib.pyplot as plt plt.rcParams['font.sans-serif'] = ['SimHei'] plt.rcParams['axes.unicode_minus'] = False
N = 64 n = np.arange(N)
w_hann = 0.5 - 0.5 * np.cos(2 * np.pi * n / (N - 1)) w_hamm = 0.54 - 0.46 * np.cos(2 * np.pi * n / (N - 1))
nfft = 8192 W_hann = np.fft.fftshift(np.fft.fft(w_hann, nfft)) W_hamm = np.fft.fftshift(np.fft.fft(w_hamm, nfft))
f = np.arange(nfft) - nfft//2 f = f / (nfft / N)
W_hann_dB = 20 * np.log10(np.abs(W_hann) / np.max(np.abs(W_hann)) + 1e-12) W_hamm_dB = 20 * np.log10(np.abs(W_hamm) / np.max(np.abs(W_hamm)) + 1e-12)
plt.figure(figsize=(10, 6)) plt.plot(f, W_hann_dB, label='Hann', linewidth=2) plt.plot(f, W_hamm_dB, '--', label='Hamming', linewidth=2)
plt.xlim(-5, 5) plt.ylim(-100, 5)
plt.title('Hann vs Hamming 频谱包络对比 (N=64)') plt.xlabel('归一化频率 (单位: 原始 bin 间距)') plt.ylabel('幅度 (dB)') plt.grid(alpha=0.3) plt.legend() plt.tight_layout() plt.show()
|

总结
hann是”近端稍差,远端好”;Hamming是”近端好,远端差”
场景
- Hann
- 一般谱分析,要求远端旁瓣干净
- 需要窗两端严格为0(重叠相加、滤波器设计)
- 经典FFT谱分析常用Hann
- Hamming
- 要求第一旁瓣极低,容忍远端旁瓣
- 语音处理、音频分析(STFT)常用Hamming
经验
- 关心邻近强信号泄露->Hamming(第一旁瓣低)
- 关心宽带噪声底、远端泄露->Hann(旁瓣衰减快)
- 不确定时,Hann更为通用