4. 噪声抑制(NS)基础:噪声类型、谱减法、维纳滤波与DNN方法

各位好,欢迎来到噪声抑制这一章。说实话,在智能音箱的音频链路里,NS(Noise Suppression)是我个人觉得最有「技术美感」的一环。为什么?因为你要在「去掉噪声」和「保留语音」之间走钢丝,稍微偏一点,要么噪声没消干净,要么语音变得像机器人。

我在项目中遇到过不少次,算法在安静环境下跑得漂漂亮亮,一放到真实的客厅、厨房场景,立马翻车。嗯,这里的关键在于——你面对的噪声类型不一样了。

4.1 噪声类型:平稳 vs 非平稳

先搞清楚你的敌人是谁。噪声大致分两类:

  • 平稳噪声:统计特性随时间变化不大。比如空调声、风扇声、电脑散热器的嗡嗡声。这类噪声的频谱相对稳定,好对付。
  • 非平稳噪声:统计特性随时间剧烈变化。比如键盘敲击声、关门声、小孩哭声、电视里突然的广告声。这类噪声,说实话,是传统算法的噩梦。

我的经验:在智能音箱产品中,80%以上的投诉都来自非平稳噪声场景。用户不会在意空调声,但会在意「音箱突然被一声咳嗽打断」。

你想想看,平稳噪声你可以在静默期估计个噪声谱,然后一直用。但非平稳噪声呢?等你估计完,噪声早就变了。所以算法设计时,必须区分对待。

特性 平稳噪声 非平稳噪声
频谱变化 缓慢 快速
典型例子 空调、风扇 键盘、电视、人声干扰
传统算法效果 较好 较差
DNN适用性 可以 更优

4.2 谱减法:最朴素的思路

谱减法,说白了就是「有噪声的时候减去噪声」。它的数学基础很简单:

|Y(f)|² = |X(f)|² - |N(f)|²

其中Y是增强后的语音幅度谱,X是带噪语音,N是估计的噪声谱。然后结合原始相位,做IFFT恢复时域信号。

为什么说它朴素?因为它假设噪声是加性的,而且你事先知道噪声谱。我在早期做项目时,第一次实现谱减法,效果还挺惊喜的——空调声确实没了。但问题很快就来了:

  • 音乐噪声:减过头了,残留一些「吱吱吱」的伪影,听着像背景里有只蟋蟀。
  • 过减问题:减多了,语音失真严重。

我曾经踩过的坑:谱减法里有个参数叫「过减因子α」,我一开始设成1.0,结果语音质量惨不忍睹。后来调到1.2~1.5之间,配合一个谱下限(floor),才勉强能听。但说实话,谱减法在信噪比低于5dB时基本就废了。

改进版谱减法会引入平滑机制,比如:

|Y(f)|² = max(|X(f)|² - α·|N(f)|², β·|X(f)|²)

这里的β就是谱下限,防止减成负数。α控制减法力度。这两个参数,我建议你在实际产品中做可调,因为不同麦克风、不同场景,最优值差很多。

4.3 维纳滤波:从统计角度出发

维纳滤波比谱减法聪明一点。它不再简单粗暴地做减法,而是估计一个增益函数,对每个频点做加权。

核心公式:

H(f) = ξ(f) / (1 + ξ(f))

其中ξ(f)是先验信噪比(prior SNR),即纯净语音功率与噪声功率的比值。这个值越大,增益越接近1(保留语音);越小,增益越接近0(抑制噪声)。

我个人习惯用「决策导向法」(Decision-Directed)来估计先验信噪比:

ξ(k) = α·|Y(k-1)|²/|N(k-1)|² + (1-α)·max(γ(k)-1, 0)

这里的α通常取0.98左右。为什么?因为语音是连续的,前一帧的信息对当前帧有参考价值。我在项目中试过α=0.9,结果语音有颤音感;调到0.98,平滑多了。

小技巧:维纳滤波对平稳噪声效果很好,但对非平稳噪声,增益更新跟不上。我建议在维纳滤波前加一个VAD(语音活动检测),只在非语音段更新噪声估计。这样能避免语音段被误伤。

维纳滤波的优点是音乐噪声比谱减法少很多,缺点是计算量稍大(需要实时估计先验SNR),但在嵌入式平台上,用定点数优化后完全跑得动。

4.4 基于DNN的噪声抑制:新时代的解法

好了,前面两种方法都是传统信号处理的思路。它们有个共同的问题:对非平稳噪声,效果天花板很低。你想想看,键盘敲击声的频谱和语音重叠度很高,传统方法根本分不开。

DNN方法就不一样了。它直接学习从带噪语音到纯净语音的映射。常见架构有两种:

  • 时域方法:比如Conv-TasNet,直接处理波形。
  • 频域方法:比如CRNN(卷积+循环神经网络),处理频谱图。

我在实际产品中更倾向于频域方法,原因很简单:嵌入式平台的算力有限,频域方法可以用较小的模型达到不错的效果。一个典型的DNN NS模型结构:

输入: 带噪语音频谱 (257维, 16kHz)
↓
2层卷积 (提取局部特征)
↓
2层GRU (捕捉时序依赖)
↓
全连接层 (输出mask)
↓
逐元素乘: mask * 带噪频谱 = 增强频谱

这个mask就是所谓的「理想比值掩膜」(IRM),取值范围0~1。模型训练的目标就是让输出的mask尽可能接近真实的IRM。

我的建议:不要一上来就追求大模型。在智能音箱上,我见过很多团队用几百KB的模型就达到了比传统算法好得多的效果。关键是训练数据要覆盖各种噪声场景,尤其是你产品实际会遇到的那些。

DNN方法的优势很明显:

  • 对非平稳噪声效果好
  • 语音失真小
  • 可以联合优化其他任务(比如VAD、DOA)

但缺点也摆在那:

  • 需要大量标注数据
  • 模型部署需要量化、剪枝
  • 对未见过的噪声类型可能泛化不好

我曾经翻过车:第一次部署DNN NS模型时,没做定点量化,直接用float32跑,结果DSP内存爆了。后来用INT8量化,模型从2MB压缩到500KB,推理速度提升了4倍,效果只损失了不到0.5dB。所以,嵌入式部署一定要做量化,别偷懒。

4.5 三种方法的对比与选型建议

方法 计算量 平稳噪声 非平稳噪声 语音质量 部署难度
谱减法
维纳滤波
DNN方法

我个人在实际项目中,通常这样搭配:

  • 低端芯片(比如Cortex-M4):用维纳滤波 + 谱减法混合,参数调好也能用。
  • 中端芯片(比如Cortex-A系列 + DSP):用轻量级DNN模型,配合维纳滤波做后处理。
  • 高端芯片(比如带NPU的):直接上全DNN方案,效果最好。

好了,这一章的内容就到这里。噪声抑制是个「入门容易精通难」的领域,希望你能从这三种方法中找到适合自己产品的路子。下一章我们会聊回声消除,那个坑更多,到时候再细说。