3. 噪声类型与特性

做语音降噪,说白了就是跟时域信号打交道。你连信号长什么样都不清楚,后面那些滤波器、神经网络再花哨也白搭。这一节我把最核心的几个概念串起来讲,都是我在项目里天天用的东西。

3.1 采样率与量化位数

模拟信号是连续的,计算机只能处理离散的点。怎么把连续信号变成离散点?两个步骤:采样和量化。

采样,就是每隔一段时间取一个值。这个间隔的倒数就是采样率。比如 16kHz 采样率,意味着每秒取 16000 个点。我最早做语音增强时,客户给的数据是 8kHz 采样的,听起来糊得不行,高频信息全丢了。后来我学乖了,拿到数据先看采样率。

量化,是把采样得到的电压值用有限个二进制位表示。16 位量化,就是每个采样点用 16 个 bit 存,能表示 65536 个不同的幅度等级。位数越高,动态范围越大,底噪越低。

参数 常见值 说明
采样率 8kHz / 16kHz / 44.1kHz 语音常用 16kHz,音乐用 44.1kHz
量化位数 16 bit / 24 bit / 32 bit float 16 bit 是语音标配,32 bit float 用于中间处理
比特率 采样率 × 量化位数 × 声道数 16kHz × 16bit × 1 = 256kbps
我的习惯:做降噪算法原型时,统一用 16kHz、16bit、单声道。这个配置在效果和计算量之间最平衡。部署到嵌入式设备时,再根据硬件资源降采样率或量化位数。

3.2 奈奎斯特定理

这个定理很简单:采样率必须大于信号最高频率的两倍,否则就会发生混叠。混叠是什么?就是高频信号伪装成低频信号混进来,你根本分不清。

举个例子。语音信号最高频率通常认为是 8kHz(实际上大部分能量在 4kHz 以下),所以 16kHz 采样率刚好满足奈奎斯特条件。如果你用 8kHz 采样率去采一个 5kHz 的信号,采出来的结果看起来像 3kHz 的信号——这就是混叠。

我曾经踩过的坑:有一次在嵌入式平台上做降噪,为了省内存把采样率从 16kHz 降到 12kHz,结果高频噪声反而变大了。查了半天才发现,12kHz 采样率对应的奈奎斯特频率是 6kHz,而麦克风硬件本身会拾取 6-8kHz 的噪声,这些噪声全部混叠到了低频段。后来我在 ADC 前加了一个抗混叠滤波器,问题才解决。

所以,部署时要注意三点:

  • 采样率必须大于信号最高频率的两倍
  • ADC 前必须有抗混叠低通滤波器(硬件或软件)
  • 降采样前必须先做低通滤波,再抽取

3.3 分帧

语音信号是非平稳的,但它在很短的时间内(10-30ms)可以看作是平稳的。所以我们把信号切成一段一段的帧来处理。

分帧有两个参数:帧长和帧移。帧长一般取 20-30ms,帧移通常取帧长的一半,这样相邻帧之间有 50% 的重叠。为什么要重叠?因为加窗后帧两端的信号会被削弱,重叠可以保证信息不丢失。

以 16kHz 采样率、25ms 帧长为例:

  • 帧长 = 0.025 × 16000 = 400 个采样点
  • 帧移 = 200 个采样点(50% 重叠)
  • 每秒帧数 = 16000 / 200 = 80 帧
部署时的选择:帧长越长,频率分辨率越高,但时间分辨率越低。做降噪时我一般用 20-30ms 帧长,既能捕捉到语音的短时平稳特性,又不会让噪声估计滞后太多。

3.4 加窗

分帧之后,每一帧的两端是截断的。直接做 FFT 会产生频谱泄漏——就是能量从主瓣泄漏到旁瓣,看起来像多了很多虚假的频率成分。加窗就是为了缓解这个问题。

常用的窗函数有三种:

窗函数 主瓣宽度 旁瓣衰减 适用场景
矩形窗 最窄 -13dB 几乎不用,频谱泄漏严重
汉明窗 较宽 -43dB 语音处理最常用
汉宁窗 较宽 -32dB 噪声估计、谱减法常用

汉明窗和汉宁窗长得像,但公式差一点:

汉明窗: w[n] = 0.54 - 0.46 × cos(2πn/N)
汉宁窗: w[n] = 0.50 - 0.50 × cos(2πn/N)

我个人习惯在降噪算法里用汉明窗。它的旁瓣衰减更大,能更好地抑制频谱泄漏。但如果你做的是谱减法,汉宁窗的旁瓣衰减虽然小一点,但主瓣更平滑,反而更适合。

避坑指南:加窗后记得做重叠相加(OLA)或重叠保留(OLS)来恢复信号。我见过有人加窗后直接做 IFFT 拼接,结果信号幅度忽大忽小,听起来像在喘气。正确的做法是:加窗 → 处理 → IFFT → 重叠相加。

3.5 短时能量与过零率

这两个特征在语音端点检测(VAD)里用得最多。虽然现在深度学习 VAD 很流行,但传统方法在低资源设备上依然有优势。

短时能量,就是一帧内所有采样点的平方和。公式很简单:

E = Σ x[n]²   (n = 0, 1, ..., N-1)

能量高的帧大概率是语音,能量低的帧大概率是静音或背景噪声。但要注意,噪声的能量也可能很高,比如有人在旁边敲键盘。所以单靠能量做 VAD 不够可靠。

过零率,就是一帧内信号穿过零轴的次数。语音的过零率比噪声低,因为语音主要集中在低频,而噪声(尤其是白噪声)高频成分多,过零率自然高。

我做过一个项目,在 Cortex-M4 上跑实时 VAD,只用能量和过零率两个特征,配合一个简单的阈值判断,就能在安静环境下达到 95% 以上的准确率。代码量不到 50 行,延迟只有一帧。

// 短时能量计算
float compute_energy(float *frame, int frame_len) {
    float energy = 0.0f;
    for (int i = 0; i < frame_len; i++) {
        energy += frame[i] * frame[i];
    }
    return energy;
}

// 过零率计算
int compute_zcr(float *frame, int frame_len) {
    int zcr = 0;
    for (int i = 1; i < frame_len; i++) {
        if ((frame[i] > 0 && frame[i-1] < 0) || 
            (frame[i] < 0 && frame[i-1] > 0)) {
            zcr++;
        }
    }
    return zcr;
}
注意:过零率对直流偏移非常敏感。如果信号有直流分量,过零率会变成 0 或很小。做 VAD 之前一定要先做直流滤波。我吃过这个亏,调试了整整一天才发现是 ADC 的直流偏置没去掉。

3.6 本章知识体系

下面这张图把本章的核心概念串起来了。从模拟信号到数字信号,再到分帧加窗和特征提取,每一步都有对应的部署要点。

时域信号处理知识体系 模拟信号 采样 (16kHz) 量化 (16bit) 奈奎斯特定理 分帧 (25ms, 50%重叠) 加窗 (汉明/汉宁) 特征提取 短时能量 过零率 部署要点 抗混叠滤波器 帧长与延迟权衡 重叠相加恢复 直流滤波预处理

这张图从左到右展示了信号处理的完整流程。左边是信号数字化,中间是分帧加窗和特征提取,右边是部署时要注意的工程细节。你想想看,每一步都有坑,但每一步也都有成熟的解决方案。

好了,时域信号基础就讲到这里。这些概念在后面的章节里会反复用到,尤其是分帧加窗和特征提取,几乎是每个降噪算法的起点。你先把这些基础打牢,后面学滤波器设计和神经网络部署时就会轻松很多。