2、语音特征提取(上):预加重、分帧、加窗、短时傅里叶变换
各位好,欢迎来到语音特征提取的上半部分。说实话,语音信号处理里,特征提取是真正决定系统上限的环节。我见过不少同学模型调得飞起,结果前端特征一塌糊涂,最后精度死活上不去。今天咱们就把预加重、分帧、加窗和STFT这几个基本功彻底讲透。
核心认知:语音信号是非平稳的,但它在10~30ms的短时片段内可以看作平稳信号。这就是所有短时处理技术的理论基础。
2.1 预加重:为什么要先“提亮”高频?
先问一个问题:你说话时,高频能量和低频能量哪个大?
答案是低频。人的声门脉冲激励信号,其频谱大约以每倍频程6dB的速度衰减。也就是说,发同一个音,2000Hz的能量可能只有200Hz的十分之一。如果不做处理,后续分析时高频信息会被低频完全淹没。
预加重就是为了解决这个问题。它本质上是一个一阶高通滤波器:
y[n] = x[n] - α · x[n-1]
α通常取0.95~0.97。我习惯用0.97,这个值在大多数语音数据集上表现最稳。
我的经验:曾经有个项目,做远场语音识别,模型在低频噪声环境下频频出错。后来我把预加重系数从0.95调到0.98,高频细节更突出,识别率直接涨了3个点。别小看这一步。
预加重的作用可以总结为三点:
- 补偿高频衰减——让频谱更平坦,便于后续分析
- 数值稳定——避免高频分量在FFT时被舍入误差吃掉
- 提升信噪比——尤其对清音(如/s/、/ʃ/)这类高频为主的音素
注意:预加重不是万能的。如果信号本身高频噪声严重(比如录音设备底噪大),预加重反而会放大噪声。这时候我建议先做降噪,再做预加重。
2.2 分帧:把连续信号切成“小段”
语音信号是时变的——你发“啊”和“一”时,声道形状完全不同。但如果你只取20ms来看,声道几乎没动,信号特性基本稳定。这就是分帧的物理依据。
分帧有两个关键参数:
| 参数 | 典型值 | 说明 |
|---|---|---|
| 帧长 | 20~30ms | 太短则频率分辨率不够;太长则失去平稳性 |
| 帧移 | 10~15ms | 相邻帧重叠60%~70%,保证连续性 |
举个例子:采样率16kHz,帧长25ms就是400个采样点,帧移10ms就是160个点。每帧比上一帧前进160点,重叠240点。
# 伪代码示意
fs = 16000
frame_len = int(0.025 * fs) # 400点
hop_len = int(0.010 * fs) # 160点
num_frames = (len(signal) - frame_len) // hop_len + 1
for i in range(num_frames):
start = i * hop_len
frame = signal[start : start + frame_len]
避坑指南:我曾经在嵌入式设备上做实时语音处理,帧移设得太小导致计算量爆炸。后来发现,对于大多数任务,帧移取帧长的40%就够用了。别盲目追求高重叠率。
2.3 加窗:为什么不能直接切?
直接切帧会带来一个问题——频谱泄漏。你想想看,截断一段信号相当于在时域乘了一个矩形窗,矩形窗的频谱是sinc函数,旁瓣很高。这会导致本应集中在某个频率的能量“泄漏”到其他频率上。
汉明窗(Hamming Window)就是用来解决这个问题的。它的公式是:
w[n] = 0.54 - 0.46 · cos(2πn / (N-1)), 0 ≤ n ≤ N-1
汉明窗的特点:主瓣宽度适中,旁瓣衰减大(约-43dB)。相比矩形窗,它能有效抑制频谱泄漏。
其他常用窗函数对比:
| 窗类型 | 主瓣宽度 | 旁瓣衰减 | 适用场景 |
|---|---|---|---|
| 矩形窗 | 最窄 | -13dB | 频率分辨率优先,不关心泄漏 |
| 汉明窗 | 中等 | -43dB | 语音分析最常用 |
| 汉宁窗 | 中等 | -32dB | 与汉明窗类似,两端更平滑 |
| 布莱克曼窗 | 最宽 | -58dB | 需要极低旁瓣时 |
我的建议:除非你有特殊需求,否则语音特征提取默认用汉明窗。我在多个项目里对比过,汉明窗在识别率和鲁棒性之间平衡得最好。
2.4 短时傅里叶变换(STFT):时频分析的基石
好了,前面三步做完,我们得到了加窗后的每一帧信号。现在要问:这一帧里包含哪些频率成分?
答案就是做FFT。对每一帧做N点FFT,得到该帧的频谱。把所有帧的频谱按时间堆叠起来,就得到了一个时频矩阵——这就是STFT。
数学上,STFT定义为:
X[m, k] = Σ x[n] · w[n - m] · e^(-j·2π·k·n / N)
其中m是帧索引,k是频率索引,w是窗函数。
STFT的输出通常用两种方式表示:
- 幅度谱:|X[m, k]|,反映各频率的能量大小
- 功率谱:|X[m, k]|²,幅度谱的平方,物理意义更直接
实际应用中,我们一般只取前N/2+1个频率点(因为FFT结果是对称的)。比如512点FFT,只取前257点。
重要提醒:FFT点数N一般取2的幂次,且不小于帧长。如果帧长400点,我建议做512点FFT(补零到512)。补零不会增加频率分辨率,但能让频谱更平滑。
2.5 完整流程与知识图谱
下面这张图把整个流程串起来了。从原始波形到STFT时频矩阵,每一步都在解决一个具体问题。
2.6 实际项目中的参数选择
说了这么多理论,最后给点实在的。不同任务下,参数怎么选?我列个表:
| 任务类型 | 采样率 | 帧长 | 帧移 | FFT点数 | 窗函数 |
|---|---|---|---|---|---|
| 语音识别(ASR) | 16kHz | 25ms | 10ms | 512 | 汉明窗 |
| 说话人识别 | 16kHz | 20ms | 10ms | 512 | 汉明窗 |
| 语音增强 | 16kHz | 32ms | 8ms | 512 | 汉宁窗 |
| 音乐分析 | 44.1kHz | 46ms | 23ms | 2048 | 布莱克曼窗 |
我的经验:如果你刚开始做语音项目,直接用16kHz采样率、25ms帧长、10ms帧移、512点FFT、汉明窗。这套参数在90%的场景下都够用。等遇到具体问题了,再针对性地调。