3. 音频信号基础:采样率、量化位数、傅里叶变换、梅尔频谱、MFCC特征提取
好,咱们正式开始聊音频信号处理。说实话,很多做语音唤醒的同行,一开始都急着调模型、调参数,结果发现效果上不去,回头一看——连音频基础都没搞扎实。我个人习惯是,不管项目多紧,先把这几个核心概念吃透,后面才不会走弯路。
3.1 采样率:把连续的声音变成离散的点
声音本质上是连续的波,但计算机只能处理离散的数字。采样,就是每隔一段时间,记录一下声音的“快照”。
采样率,说白了就是每秒采多少个点。单位是Hz(赫兹)。
- 8kHz:电话语音,够用但音质差
- 16kHz:语音识别常用,唤醒词模型也常用这个
- 44.1kHz:CD音质,音乐处理用得多
- 48kHz:视频、专业音频
这里有个关键定理——奈奎斯特采样定理:采样率必须大于信号最高频率的两倍,否则会出现混叠失真。
核心结论:人声的主要能量集中在4kHz以下,所以16kHz采样率(能覆盖8kHz带宽)对语音唤醒来说足够了。我见过有人用44.1kHz采样率做唤醒词,白白增加计算量,效果没提升。
我的经验:项目中如果资源紧张,可以降到8kHz试试。但要注意,8kHz下高频信息丢失,某些辅音(比如/s/、/sh/)的区分度会下降。我曾经在低功耗芯片上被迫用8kHz,结果唤醒率掉了3个点,后来加了高频补偿才拉回来。
3.2 量化位数:决定声音的“细腻程度”
采样决定了时间上的精度,量化决定了幅度上的精度。
量化位数,就是用一个数字来表示声音的“高度”。常见的有:
- 8位:256个等级,噪声大,基本不用
- 16位:65536个等级,语音处理的标配
- 24位:1677万个等级,录音棚级别
- 32位浮点:科学计算用,精度极高
量化位数越高,动态范围越大,信噪比越高。每增加1位,信噪比提升约6dB。
注意:量化位数不是越高越好。16位已经能覆盖人耳的听觉范围(约96dB动态范围)。在嵌入式设备上,用32位浮点反而会浪费存储和计算资源。我建议唤醒词模型统一用16位PCM格式,兼容性最好。
3.3 傅里叶变换:从时域到频域的“翻译官”
音频信号在时域上看,就是一条上下波动的曲线。但这条曲线里藏着什么频率成分?我们看不出来。
傅里叶变换就是干这个的——把信号从时域变到频域。
公式长这样(别怕,理解意思就行):
X(f) = ∫ x(t) · e^(-j2πft) dt
说白了,就是把信号拆解成不同频率的正弦波叠加。每个频率对应一个幅度和相位。
但在实际工程中,我们用的是短时傅里叶变换(STFT)。为什么?因为语音信号是非平稳的,频率成分随时间变化。我们需要把信号切成一小段一小段(通常20-40ms),假设每段内是平稳的,再分别做傅里叶变换。
关键参数:
- 窗长:一般取25ms,比如16kHz采样率下就是400个点
- 帧移:一般取10ms,即160个点
- 窗函数:汉明窗、汉宁窗最常用,能减少频谱泄露
嗯,这里要注意:窗长太短,频率分辨率差;窗长太长,时间分辨率差。这是个trade-off。我个人习惯在唤醒词任务中,窗长25ms、帧移10ms,这个组合比较稳妥。
3.4 梅尔频谱:模拟人耳的听觉特性
傅里叶变换得到的频谱,是线性频率刻度。但人耳对频率的感知不是线性的——对低频更敏感,对高频越来越迟钝。
梅尔刻度就是模拟这种感知的。转换公式:
Mel(f) = 2595 · log10(1 + f/700)
你看,低频段变化快,高频段变化慢。把线性频谱映射到梅尔刻度上,就得到了梅尔频谱。
具体做法是:
- 对STFT得到的幅度谱,取平方得到能量谱
- 通过一组梅尔滤波器组(通常是40-80个三角滤波器)
- 每个滤波器输出一个能量值
- 取对数(模拟人耳的对数感知)
结果就是一张梅尔频谱图——横轴是时间帧,纵轴是梅尔频率通道,颜色深浅代表能量大小。
避坑指南:我曾经在训练唤醒词模型时,直接用线性频谱作为输入,结果模型在安静环境下表现不错,一到嘈杂环境就崩。后来换成梅尔频谱,鲁棒性明显提升。说白了,梅尔频谱相当于帮模型做了“听觉预处理”,让它更关注人耳敏感的频率区域。
3.5 MFCC特征提取:语音识别的“黄金标准”
MFCC(梅尔频率倒谱系数)是梅尔频谱的进一步处理。它提取的是频谱的“包络”信息,而不是精细的谐波结构。
提取步骤:
- 计算梅尔频谱(上面讲过了)
- 取对数
- 做离散余弦变换(DCT)
- 保留前12-13个系数(去掉高阶系数,因为它们代表频谱的快速变化,通常是噪声)
- 加上一阶差分、二阶差分(捕捉动态变化)
最终得到一个特征向量,通常是39维(13个静态系数 + 13个一阶差分 + 13个二阶差分)。
为什么MFCC好用?
- DCT去除了特征之间的相关性,更适合GMM/HMM等传统模型
- 低阶系数代表频谱的整体形状,对噪声不敏感
- 差分系数捕捉了语音的动态变化,比如音调升降
不过,现在深度学习时代,很多模型直接用梅尔频谱甚至原始波形作为输入,MFCC的地位有所下降。但在资源受限的嵌入式设备上,MFCC仍然是个不错的选择——特征维度低,计算量小。
我的建议:如果你的唤醒词模型跑在MCU上,用MFCC;如果跑在手机或树莓派上,用梅尔频谱就够了。我曾经在Cortex-M4芯片上部署唤醒词,MFCC+轻量CNN的方案,RAM占用不到50KB,效果还不错。
3.6 实战:用Python提取MFCC特征
说了这么多理论,咱们来点实际的。用librosa库提取MFCC,代码很简单:
import librosa
import numpy as np
# 加载音频文件
audio, sr = librosa.load('wake_word.wav', sr=16000)
# 提取MFCC特征
mfcc = librosa.feature.mfcc(
y=audio,
sr=sr,
n_mfcc=13, # 取13个系数
n_fft=400, # 窗长400点(25ms)
hop_length=160, # 帧移160点(10ms)
n_mels=40, # 40个梅尔滤波器
fmin=0, # 最低频率
fmax=8000 # 最高频率(奈奎斯特频率)
)
# 加上一阶差分和二阶差分
mfcc_delta = librosa.feature.delta(mfcc)
mfcc_delta2 = librosa.feature.delta(mfcc, order=2)
# 拼接成39维特征
mfcc_features = np.vstack([mfcc, mfcc_delta, mfcc_delta2])
print(f"MFCC特征形状: {mfcc_features.shape}")
# 输出: (39, 帧数)
小技巧:实际部署时,我建议把MFCC特征做归一化,比如减去均值除以标准差。这样模型对不同音量、不同麦克风的鲁棒性会好很多。我曾经踩过坑——没做归一化,换了个麦克风,唤醒率直接掉了一半。
3.7 总结一下
好,咱们快速回顾一下:
- 采样率:决定频率范围,16kHz是语音唤醒的黄金标准
- 量化位数:决定动态范围,16位PCM最常用
- 傅里叶变换:把时域变到频域,STFT是实际工程中的主角
- 梅尔频谱:模拟人耳听觉,比线性频谱更鲁棒
- MFCC:进一步压缩和去相关,适合资源受限的场景
这些基础概念,说白了就是语音信号处理的“砖块”。后面咱们搭建唤醒词模型时,所有的输入数据都要经过这些处理。你想想看,如果连砖块都没烧好,房子能盖得稳吗?
下一章,咱们开始聊唤醒词模型的数据准备——怎么采集数据、怎么做数据增强、怎么避免过拟合。到时候见!