3. 分帧与加窗
任务说明
本案例处理一段已知采样率的离散语音信号,实现两个核心操作:分帧(将连续采样点切分为固定长度的帧,相邻帧间有重叠)与加窗(对每一帧乘以汉明窗系数)。最终输出加窗后的时域帧数据,并计算其幅度谱,用于观察加窗对帧内信号及频谱的影响。
实现方案
采用Python与NumPy实现,不依赖额外音频文件。输入信号由两个不同频率的正弦波叠加合成,模拟包含浊音与清音成分的短时平稳信号。分帧参数为:帧长256点,帧移128点(50%重叠)。汉明窗按标准公式生成,逐点与帧数据相乘。对加窗后的帧执行FFT并取模,得到幅度谱。
代码实现
import numpy as np
# ---------- 参数配置 ----------
fs = 16000 # 采样率 16kHz
frame_len = 256 # 帧长(16ms)
hop = 128 # 帧移(50%重叠)
N_fft = 512 # FFT点数
# ---------- 生成测试信号(两正弦叠加,模拟语音段) ----------
t_total = 0.1 # 总时长 100ms
n_total = int(fs * t_total)
n = np.arange(n_total)
# 低频分量模拟浊音(200Hz),高频分量模拟清音(3000Hz)
x = 0.6 * np.sin(2 * np.pi * 200 * n / fs) + 0.4 * np.sin(2 * np.pi * 3000 * n / fs)
# ---------- 分帧 ----------
num_frames = 1 + (len(x) - frame_len) // hop
frames = np.zeros((num_frames, frame_len))
for i in range(num_frames):
start = i * hop
frames[i, :] = x[start:start + frame_len]
# ---------- 汉明窗 ----------
hamming_win = 0.54 - 0.46 * np.cos(2 * np.pi * np.arange(frame_len) / (frame_len - 1))
# ---------- 加窗 ----------
windowed_frames = frames * hamming_win
# ---------- 频谱计算(取第3帧作为观测对象) ----------
obs_idx = 2 # 观察第3帧(索引从0开始)
frame_td = windowed_frames[obs_idx] # 加窗后时域帧
spectrum = np.abs(np.fft.rfft(frame_td, N_fft)) # 幅度谱
freq_axis = np.fft.rfftfreq(N_fft, 1 / fs)
# ---------- 输出观测数据 ----------
print("帧总数:", num_frames)
print("第3帧前10个加窗采样值:", np.round(frame_td[:10], 4))
print("第3帧幅度谱峰值频率(Hz):", freq_axis[np.argmax(spectrum)])
print("第3帧幅度谱前5个频点幅度:", np.round(spectrum[:5], 4))
运行与验证
运行方式:将上述代码保存为 framing_windowing.py,在已安装NumPy的Python环境中执行 python framing_windowing.py。
预期输出与判定标准:
- 程序打印帧总数为
13(由100ms信号长度与分帧参数决定)。 - 第3帧加窗后的时域采样值两端接近0(汉明窗两端为零),中间部分数值较大。
- 幅度谱峰值频率应接近200Hz(因200Hz正弦分量幅度0.6大于3000Hz分量的0.4,主峰在低频处)。
- 若打印的峰值频率在195~205Hz范围内,且帧首尾采样值明显小于帧中部,则说明分帧与汉明窗加窗实现正确。
验证逻辑:汉明窗在两端(n=0和n=255)系数为0.08,因此加窗后帧首尾应接近0;200Hz分量幅度更高,FFT主峰应出现在200Hz附近。观察这两点即可确认分帧与加窗链路自洽。