时域特征提取:短时能量、短时过零率、短时自相关函数

时域特征,说白了就是直接从波形上算出来的东西。不需要做傅里叶变换,不需要看频谱,就看信号本身随时间怎么变。我刚开始做语音处理那会儿,觉得时域特征太简单了,不就是算个平均值嘛。后来才发现,这三个特征要是用好了,能解决不少实际问题。

核心思路:语音信号是非平稳的,但在一段很短的时间内(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 三个特征的关系与选择

这三个特征各有侧重,我一般这样搭配使用:

应用场景 推荐特征 原因
语音端点检测 短时能量 + 过零率 能量区分有话/无话,过零率辅助判断清音段
基频提取 短时自相关函数 直接反映周期性,峰值位置对应基频
清浊音判别 过零率 + 能量 浊音低过零率高能量,清音高过零率低能量
音乐节拍检测 短时能量 打击乐在能量包络上有明显冲击

下面这张图展示了这三个特征的提取流程和它们之间的关系:

时域特征提取流程 输入语音信号 分帧 + 加窗 短时能量 短时过零率 短时自相关 VAD / 端点检测 爆破音检测 清浊音判别 噪声检测 基频提取 周期检测 特征融合 / 联合决策 最终特征向量 💡 组合使用效果更佳 能量 + 过零率 → VAD 自相关 + 能量 → 基频

2.5 实战中的注意事项

最后,我总结几个实战中容易踩的坑:

  1. 帧长选择:太短(<10ms)统计不稳定,太长(>50ms)会模糊语音的快速变化。我一般用 20-30ms,采样率 16kHz 时对应 320-480 点。
  2. 帧移设置:通常取帧长的一半(50% 重叠),这样特征序列更平滑。做实时系统时可以用更小的帧移(10ms 步进)。
  3. 窗函数影响:短时能量受窗函数影响很大。汉明窗会压低两端,能量会比矩形窗小一些。如果做能量对比,要统一窗类型。
  4. 归一化:不同录音设备的增益不同,能量绝对值没有可比性。我习惯做归一化——除以帧内最大能量或全局最大能量。

重要提醒:这三个特征虽然简单,但它们是很多高级特征的基础。比如 MFCC 的第一步就是短时能量(取对数后做 DCT)。把基础打牢,后面学起来会轻松很多。