时域特征提取:短时能量、短时过零率、短时自相关函数
时域特征,说白了就是直接从波形上算出来的东西。不需要做傅里叶变换,不需要看频谱,就看信号本身随时间怎么变。我刚开始做语音处理那会儿,觉得时域特征太简单了,不就是算个平均值嘛。后来才发现,这三个特征要是用好了,能解决不少实际问题。
核心思路:语音信号是非平稳的,但在一段很短的时间内(10-30ms)可以看作是平稳的。所以我们加一个窗,一段一段地算,这就是「短时」的含义。
2.1 短时能量
短时能量衡量的是某一帧信号的强弱。公式很简单:
E = sum(x[n]^2) # 对一帧内的所有采样点平方求和
或者用绝对值:
E = sum(|x[n]|) # 平均幅度,计算量更小
我在项目中遇到过一个问题:用短时能量做语音端点检测(VAD),结果安静环境下老是误判。后来发现是直流偏置没去掉。你想想看,麦克风采集的信号往往有个直流分量,这个分量会让能量一直偏高。
我的习惯:算短时能量之前,先对每一帧做去均值处理。也就是 x[n] = x[n] - mean(x),这样算出来的能量才是真正的交流能量。
短时能量能干什么?
- 区分清音和浊音:浊音能量大,清音能量小。一般浊音能量是清音的 10-20 倍。
- 语音端点检测:设置一个阈值,能量高于阈值就是有话,低于阈值就是静音。
- 检测爆破音:/p/、/t/、/k/ 这类音在释放瞬间能量会突然飙升。
避坑指南:我曾经在嘈杂环境下用固定阈值做 VAD,结果一塌糊涂。后来改用自适应阈值——取前几帧的噪声能量作为基准,动态调整。效果好了很多。
2.2 短时过零率
过零率,就是在一帧内信号穿过零轴的次数。对于离散信号,就是相邻采样点符号变化的次数。
ZCR = (1/2) * sum(|sign(x[n]) - sign(x[n-1])|)
嗯,这里要注意:如果信号有直流偏置,过零率会严重失真。因为整个波形被抬高了,穿过零轴的次数会变少甚至为零。
过零率有什么用?我告诉你,这个特征在区分清音和浊音时特别好用:
| 音素类型 | 过零率特点 | 典型值(8kHz采样) |
|---|---|---|
| 浊音(元音) | 低频为主,过零率低 | 10-30 次/帧 |
| 清音(摩擦音) | 高频为主,过零率高 | 50-100 次/帧 |
| 静音/噪声 | 随机波动,过零率中等 | 20-50 次/帧 |
我记得有一次做音乐流派分类,发现金属乐和古典乐的过零率差异特别大。金属乐失真吉他声过零率极高,古典乐弦乐过零率低。这个特征虽然简单,但区分度意外地好。
实用技巧:过零率对噪声敏感。如果信号信噪比低,建议先做简单的带通滤波(比如 80-4000Hz),把低频噪声和高频噪声滤掉一部分,过零率会更稳定。
2.3 短时自相关函数
自相关函数,用来衡量信号和它自身延迟后的相似度。公式:
R(k) = sum(x[n] * x[n+k]) # k 是延迟量
这个特征最经典的应用就是基频检测。为什么?因为语音信号是准周期的,自相关函数在基频周期处会出现一个明显的峰值。
我刚开始做基频检测时,直接找自相关函数的第一个峰值。结果发现经常出错——有时候第一个峰值是基频的整数倍(倍频错误),有时候是分数倍(半频错误)。
我的经验:不要直接找第一个峰值。先设定一个合理的基频范围(比如 80-400Hz),在这个范围内找最大值。同时,可以用三电平削波预处理,减少共振峰干扰。
自相关函数的计算量比较大。如果帧长 512 点,延迟范围 0-511,复杂度是 O(N²)。实际应用中常用两种优化:
- FFT加速:利用维纳-辛钦定理,自相关函数 = IFFT(|FFT(x)|²)。复杂度降到 O(N log N)。
- 简化自相关:只计算少数几个延迟点,比如只算基频范围内的延迟。
# FFT加速自相关计算
def autocorrelation_fft(x):
N = len(x)
X = np.fft.rfft(x, n=2*N) # 补零到2N避免循环卷积
power = np.abs(X)**2
R = np.fft.irfft(power)[:N]
return R / R[0] # 归一化
2.4 三个特征的关系与选择
这三个特征各有侧重,我一般这样搭配使用:
| 应用场景 | 推荐特征 | 原因 |
|---|---|---|
| 语音端点检测 | 短时能量 + 过零率 | 能量区分有话/无话,过零率辅助判断清音段 |
| 基频提取 | 短时自相关函数 | 直接反映周期性,峰值位置对应基频 |
| 清浊音判别 | 过零率 + 能量 | 浊音低过零率高能量,清音高过零率低能量 |
| 音乐节拍检测 | 短时能量 | 打击乐在能量包络上有明显冲击 |
下面这张图展示了这三个特征的提取流程和它们之间的关系:
2.5 实战中的注意事项
最后,我总结几个实战中容易踩的坑:
- 帧长选择:太短(<10ms)统计不稳定,太长(>50ms)会模糊语音的快速变化。我一般用 20-30ms,采样率 16kHz 时对应 320-480 点。
- 帧移设置:通常取帧长的一半(50% 重叠),这样特征序列更平滑。做实时系统时可以用更小的帧移(10ms 步进)。
- 窗函数影响:短时能量受窗函数影响很大。汉明窗会压低两端,能量会比矩形窗小一些。如果做能量对比,要统一窗类型。
- 归一化:不同录音设备的增益不同,能量绝对值没有可比性。我习惯做归一化——除以帧内最大能量或全局最大能量。
重要提醒:这三个特征虽然简单,但它们是很多高级特征的基础。比如 MFCC 的第一步就是短时能量(取对数后做 DCT)。把基础打牢,后面学起来会轻松很多。