Automatic Noise Suppression

Abstract

Automatic Noise Suppression

Authors

Walter Fan

Status

v1.0

Updated

2026-07-07

概述

背景噪声抑制(ANS, Automatic Noise Suppression)指的是将声音中的背景噪声识别并进行消除的处理。 在实时通信场景中,背景噪声会严重影响语音的可懂度和通话体验。ANS 的目标是在尽可能保留语音信号的前提下, 最大程度地抑制背景噪声。

噪声抑制是 WebRTC 音频处理流水线(Audio Processing Module, APM)中的关键模块之一, 通常在回声消除(AEC)之后、自动增益控制(AGC)之前执行。其处理链路为:

麦克风采集 → AEC → ANS → AGC → 编码 → 网络传输

噪声的分类

要有效地抑制噪声,首先需要了解噪声的类型。根据噪声的时频特性,可以将其分为以下几类:

平稳噪声 (Stationary Noise)

平稳噪声的频谱特性随时间变化缓慢,其统计特性(均值、方差)在较长时间内保持相对稳定。典型的平稳噪声包括:

  • 风扇噪声 (Fan noise):电脑风扇、空调出风口产生的持续低频噪声

  • 空调噪声 (Air conditioning noise):HVAC 系统产生的宽带背景噪声

  • 电气噪声 (Electrical noise):电源线干扰、接地回路产生的 50/60Hz 工频噪声

  • 白噪声 (White noise):麦克风电路本底噪声

平稳噪声的特点是频谱包络变化缓慢,因此可以通过估计噪声的长期频谱特性来进行有效抑制。

非平稳噪声 (Non-stationary Noise)

非平稳噪声的频谱特性随时间快速变化,统计特性不稳定。典型的非平稳噪声包括:

  • 键盘敲击声 (Keyboard typing):短促的宽带冲击噪声

  • 关门声 (Door slam):低频为主的冲击噪声

  • 背景人声 (Background speech/babble noise):其他人的说话声,频谱与目标语音高度重叠

  • 音乐声 (Background music):频谱结构复杂,与语音有部分重叠

  • 交通噪声 (Traffic noise):汽车、火车等产生的时变噪声

非平稳噪声的抑制难度远大于平稳噪声,传统的频谱减法对其效果有限,通常需要基于深度学习的方法。

瞬态噪声 (Transient Noise)

瞬态噪声是持续时间极短(通常 < 10ms)的突发噪声,其能量在短时间内急剧上升又迅速衰减。典型的瞬态噪声包括:

  • 鼠标点击声 (Mouse click)

  • 咳嗽声 (Cough)

  • 纸张翻动声 (Paper rustling)

  • 杯子碰撞声 (Cup clinking)

瞬态噪声需要专门的检测和抑制算法,WebRTC 中有独立的 Transient Suppressor 模块来处理此类噪声。

Background noise removal

保留人的说话声音,而将身边的噪声,例如风扇声,吃东西的声音消除,主要依据是人声的频率和噪声的频率和能量不同。

噪声抑制的基本思路是:

  1. 噪声估计 (Noise Estimation):在语音静默段或利用统计方法估计噪声的频谱特性

  2. 信噪比估计 (SNR Estimation):估计每个频率 bin 上的信噪比

  3. 增益计算 (Gain Calculation):根据信噪比计算每个频率 bin 的抑制增益

  4. 增益应用 (Gain Application):将增益应用于含噪语音的频谱,得到降噪后的语音

用数学公式表示,含噪语音信号可以建模为:

\[y(n) = s(n) + d(n)\]

其中 \(y(n)\) 是含噪语音,\(s(n)\) 是纯净语音,\(d(n)\) 是噪声。 在频域中:

\[Y(k) = S(k) + D(k)\]

噪声抑制的目标是从 \(Y(k)\) 中估计出 \(\hat{S}(k)\)

噪声抑制算法

谱减法 (Spectral Subtraction)

谱减法是最经典的噪声抑制方法,其基本思想是从含噪语音的功率谱中减去噪声的功率谱估计:

\[|\hat{S}(k)|^2 = |Y(k)|^2 - |\hat{D}(k)|^2\]

其中 \(|\hat{D}(k)|^2\) 是噪声功率谱的估计,通常在语音静默段(由 VAD 检测)进行更新。

为了避免过减(over-subtraction)导致的负值,引入过减因子 \(\alpha\) 和谱下限 \(\beta\)

\[|\hat{S}(k)|^2 = \max\left(|Y(k)|^2 - \alpha \cdot |\hat{D}(k)|^2, \quad \beta \cdot |Y(k)|^2\right)\]

谱减法的优点是计算简单、实时性好;缺点是容易产生 音乐噪声 (Musical Noise), 即由于帧间频谱估计的随机波动导致的不自然的音调噪声。

维纳滤波 (Wiener Filter)

维纳滤波是一种最优线性滤波方法,其目标是最小化估计信号与真实信号之间的均方误差(MSE)。 维纳滤波器的频域增益函数为:

\[H(k) = \frac{|S(k)|^2}{|S(k)|^2 + |D(k)|^2} = \frac{\text{SNR}(k)}{\text{SNR}(k) + 1}\]

其中 \(\text{SNR}(k)\) 是第 \(k\) 个频率 bin 的先验信噪比 (a priori SNR)。

在实际应用中,先验信噪比通常使用 Decision-Directed 方法估计:

\[\text{SNR}_{\text{priori}}(k, m) = \alpha_{\text{dd}} \cdot \frac{|\hat{S}(k, m-1)|^2}{|\hat{D}(k)|^2} + (1 - \alpha_{\text{dd}}) \cdot \max\left(\text{SNR}_{\text{post}}(k, m) - 1, 0\right)\]

其中 \(\alpha_{\text{dd}}\) 是平滑因子(通常取 0.98),\(\text{SNR}_{\text{post}}\) 是后验信噪比。

维纳滤波相比谱减法产生的音乐噪声更少,但计算复杂度稍高。

MMSE 估计器 (Minimum Mean Square Error Estimator)

MMSE 估计器假设语音和噪声的 DFT 系数服从高斯分布,在此假设下推导出最优的频谱幅度估计。 常用的变体包括:

  • MMSE-STSA (Short-Time Spectral Amplitude):最小化频谱幅度的均方误差

  • MMSE-LSA (Log-Spectral Amplitude):最小化对数频谱幅度的均方误差,听感更自然

MMSE-LSA 的增益函数为:

\[G_{\text{LSA}}(k) = \frac{\xi(k)}{1 + \xi(k)} \cdot \exp\left(\frac{1}{2} \int_{v(k)}^{\infty} \frac{e^{-t}}{t} dt\right)\]

其中 \(\xi(k)\) 是先验信噪比,\(v(k) = \frac{\xi(k)}{1+\xi(k)} \cdot \gamma(k)\)\(\gamma(k)\) 是后验信噪比。

基于深度学习的噪声抑制

近年来,基于深度学习的噪声抑制方法取得了显著进展,在非平稳噪声和低信噪比条件下远超传统方法。

备注

下面这几种方案都是**真正基于神经网络**的降噪,但它们**都不属于 WebRTC 官方的 ns/ 模块**:

  • RNNoise 在 Chromium 中以第三方库形式存在(third_party/rnnoise), 主要用于 VAD 等语音处理场景,而非替换 APM 的标准 NS。

  • 各家会议/通话软件宣传的 “AI 降噪” 大多是**厂商在 libwebrtc 之外自研**的, 常见做法是通过 Audio Worklet / Insertable Streams 外挂一层模型, 或 fork libwebrtc 后替换 APM 里的 NS。

换句话说,想在 WebRTC 里用上 NN 降噪,现实路径是**自己集成**,而不是指望官方 ns/ 模块。

RNNoise

RNNoise 是由 Mozilla 的 Jean-Marc Valin 提出的基于 RNN 的噪声抑制方案,其特点包括:

  • 使用 GRU (Gated Recurrent Unit) 网络

  • 在 Bark 频率尺度上操作,将频谱划分为 22 个频带

  • 模型极其轻量(约 85KB),适合实时处理

  • 每帧处理仅需约 0.1ms(在现代 CPU 上)

  • 同时输出 VAD 概率和每个频带的增益

RNNoise 的处理流程:

输入帧 → 加窗 → FFT → 提取特征(42维) → GRU网络 → 频带增益(22个) → 插值到FFT bins → IFFT → 输出帧

DTLN (Dual-signal Transformation LSTM Network)

DTLN 是一种双阶段的噪声抑制网络:

  • 第一阶段在 STFT 域操作,估计频谱幅度掩码

  • 第二阶段在时域操作,进一步细化降噪结果

  • 使用 LSTM 层捕获时序依赖关系

  • 模型大小约 2MB,适合移动端部署

PercepNet

PercepNet 是 Jean-Marc Valin 等人(发表时供职于 Amazon)提出的感知驱动噪声抑制方案, 是 RNNoise 思路的进一步发展,与 Google 的 WebRTC 团队无关

  • 结合了传统信号处理和深度学习

  • 在感知频率尺度(Bark scale)上操作

  • 使用 pitch filtering 增强周期性语音成分

  • 使用 comb filtering 保留语音的谐波结构

Single Talk and Multiple talker

Single talker

在家或者办公室开会,你在说话,不想让身边人的声音传进去,主要方法是将近端的声音(能量较大)放大或保留,将远端的声音(能量较小)减小或消除

Multiple talker

在会议室开会,你在说话,也想让身边人的声音传进去,无论近端或远端的声音就保留,并做出一些必要的 AGC

WebRTC ANS 实现

警告

一个常见误解需要先澄清。 WebRTC 官方的噪声抑制模块(modules/audio_processing/ns/自始至终都是基于传统信号处理(维纳滤波 + 噪声谱估计)的实现,从未引入过神经网络(RNN/GRU 等)。 社区里有人把 2020 年前后那次代码重写(新的 C++ NoiseSuppressor 类)非正式地称为 “NS2”, 但那只是**对旧实现的重构**,算法内核没变,仍是维纳滤波,不是深度学习降噪

如果你在 ns/ 目录下找不到任何神经网络代码,这是正常的——不是"后来被删了", 而是它从来就不在那里。真正基于深度学习的降噪方案(RNNoise、DTLN 等) 属于**第三方库或厂商自研**,详见后文"基于深度学习的噪声抑制"一节。

WebRTC 中的噪声抑制经历过一次较大的代码演进,但两套实现**在算法层面都属于传统信号处理**:

  • 旧实现:早期的 C 语言实现,核心接口是 WebRtcNs_*``(float 版)和 ``WebRtcNsx_*``(定点版), ``NoiseSuppressionImpl 封装。

  • 新实现(社区俗称 NS2):2020 年前后重写的 C++ 版本,核心类为 NoiseSuppressor, 代码更现代、结构更清晰,但**算法仍是维纳滤波 + 噪声谱估计**。

下面分别介绍。

旧 NS 实现

早期的噪声抑制实现位于 modules/audio_processing/ns/ 目录下, 核心接口为 C 语言的 WebRtcNs_* 系列函数,由 NoiseSuppressionImpl 类封装。

NS 等级 (Suppression Level)

备注

等级命名在不同层面略有差异:旧的 C 接口 WebRtcNs_set_policy 只有 3 档 (0: Mild1: Medium2: Aggressive);而对外的 APM 配置 AudioProcessing::Config::NoiseSuppression 提供 4 档(kLowkModeratekHighkVeryHigh)。 下表以对外的 4 档配置为准。

WebRTC APM 对外提供 4 个抑制等级,对应不同的噪声抑制强度:

NS 抑制等级

等级

名称

说明

0

Low (低)

轻度抑制,语音失真最小,适合安静环境

1

Moderate (中等)

中等抑制,平衡噪声抑制和语音质量

2

High (高)

较强抑制,适合中等噪声环境,可能有轻微语音失真

3

Very High (非常高)

最强抑制,适合高噪声环境,可能有明显语音失真

处理流水线 (Processing Pipeline)

NS 的处理流程如下:

输入帧(10ms PCM)
  ↓
分帧与加窗 (Windowing) — 使用 Hanning 窗
  ↓
FFT — 将时域信号转换到频域
  ↓
噪声估计 (Noise Estimation) — 基于 MCRA/IMCRA 算法
  ↓
先验 SNR 估计 (A Priori SNR Estimation)
  ↓
频谱增益计算 (Spectral Gain Calculation) — 维纳滤波
  ↓
增益应用 (Gain Application)
  ↓
IFFT — 将频域信号转换回时域
  ↓
重叠相加 (Overlap-Add) — 合成输出帧
  ↓
输出帧(10ms PCM)

核心组件

  • NsCore: 噪声抑制的核心处理逻辑

    • 维护噪声功率谱估计

    • 计算先验和后验信噪比

    • 应用维纳滤波增益

  • NoiseEstimator: 噪声估计器

    • 使用 Minimum Statistics 或 MCRA 算法

    • 在语音活动期间冻结噪声估计更新

    • 支持噪声功率谱的平滑更新

  • SpeechProbabilityEstimator: 语音存在概率估计

    • 基于先验和后验 SNR 估计语音存在概率

    • 用于控制噪声估计的更新速率

关键参数

// NS 核心参数
struct NsConfig {
  // FFT 大小,通常为 256(对应 16kHz 采样率)
  static constexpr int kFftSize = 256;
  // 分析窗长度
  static constexpr int kAnalysisSize = 256;
  // 帧移(10ms @ 16kHz = 160 samples)
  static constexpr int kFrameSize = 160;
  // 噪声估计平滑因子
  float noise_smoothing_factor = 0.7f;
  // 过减因子
  float over_subtraction_factor = 1.0f;
  // 最小增益(谱下限),防止过度抑制
  float min_gain = 0.01f;  // -40 dB
};

新 NS 实现(NoiseSuppressor,社区俗称 NS2)

2020 年前后,WebRTC 把旧的 C 语言 NS 代码**重写**成了更现代的 C++ 实现, 核心类为 NoiseSuppressor,同样位于 modules/audio_processing/ns/ 目录下。 社区里有人非正式地把它称为 “NS2”。

重要

“NS2” 只是**代码层面的重写(refactor)**,不是算法层面的换代。 它**依然使用维纳滤波 + 噪声谱估计**,没有引入任何神经网络。 把它理解成"基于 RNN 的降噪"是一个流传较广的误解。

NoiseSuppressor 类

从当前主干代码(ns/noise_suppressor.cc)可以看到,NoiseSuppressor 的真实结构是:

  • 每个通道持有一个 **维纳滤波器**(WienerFilter)、一个 **噪声估计器**(NoiseEstimator) 和一个 **语音存在概率估计器**(SpeechProbabilityEstimator

  • 多通道时对各通道的维纳滤波增益取逐频点最小值(AggregateWienerFilters

  • 使用 Decision-Directed 方法估计先验 SNR,再由维纳滤波公式计算频域增益

  • 相比旧实现,主要改进是代码结构、可读性和多通道支持,算法内核不变

// NoiseSuppressor 的核心接口(algorithm 仍为维纳滤波,无神经网络)
class NoiseSuppressor {
public:
  NoiseSuppressor(const NsConfig& config,
                  size_t sample_rate_hz,
                  size_t num_channels);

  // 估计当前帧的噪声(不修改信号)
  void Analyze(const AudioBuffer& audio);
  // 对信号施加噪声抑制增益
  void Process(AudioBuffer* audio);

private:
  // 每个通道独立维护的处理状态
  struct ChannelState {
    NoiseEstimator noise_estimator;                 // 噪声谱估计(Minimum Statistics / 分位数法)
    WienerFilter wiener_filter;                     // 维纳滤波增益
    SpeechProbabilityEstimator speech_probability_estimator;  // 语音存在概率
    // ... 频谱缓存、prev spectrum 等
  };
  std::vector<std::unique_ptr<ChannelState>> channels_;
};

新实现(NS2)相比旧实现的改进

注意这里对比的是**同为传统算法**的新旧两版实现,而不是"传统 vs 深度学习":

  • C++ 重写,结构清晰、更易维护

  • 原生支持多通道处理

  • 更规范的多频带(split-band)处理,适配 16/32/48kHz

  • 在同样的维纳滤波框架下,参数和实现细节有所打磨,语音质量略有提升

如果需要对非平稳噪声、低 SNR 场景有质的提升,仍然需要**真正的深度学习方案** (见下一节),而这些方案并不在 WebRTC 官方 ns/ 模块之内。

传统方法 vs 深度学习方法对比

备注

这里对比的是两类**算法**:传统信号处理 vs 深度学习。 请注意 WebRTC 官方的 NS(无论旧实现还是新的 NoiseSuppressor/“NS2”) 都属于左列的"传统方法";右列的深度学习方法对应 RNNoise、DTLN 等,需另行集成。

传统 NS vs 深度学习 NS 对比

特性

传统方法 (谱减法/维纳滤波)

深度学习方法 (RNN/LSTM)

平稳噪声抑制

效果好

效果好

非平稳噪声抑制

效果有限

效果显著

语音失真

高抑制等级下明显

较小

音乐噪声

容易产生

很少产生

计算复杂度

中等(需要矩阵运算)

模型大小

无需模型

需要模型文件(几十KB~几MB)

适应性

需要噪声估计收敛

端到端学习,适应性强

可解释性

强(基于明确的数学模型)

弱(黑盒模型)

WebRTC 中的配置

在 WebRTC 中,可以通过 AudioProcessing::Config 来配置噪声抑制:

// C++ API 配置
AudioProcessing::Config config;
config.noise_suppression.enabled = true;
config.noise_suppression.level =
    AudioProcessing::Config::NoiseSuppression::kHigh;

auto apm = AudioProcessingBuilder().SetConfig(config).Create();

在 JavaScript 中,可以通过 MediaConstraints 来启用噪声抑制:

// JavaScript API 配置
const constraints = {
  audio: {
    noiseSuppression: true,           // 启用噪声抑制
    autoGainControl: true,            // 通常与 AGC 配合使用
    echoCancellation: true            // 通常与 AEC 配合使用
  }
};

navigator.mediaDevices.getUserMedia(constraints)
  .then(stream => {
    // 使用降噪后的音频流
    const audioTrack = stream.getAudioTracks()[0];
    const settings = audioTrack.getSettings();
    console.log('Noise suppression:', settings.noiseSuppression);
  });

也可以通过 MediaTrackConstraints 进行更精细的控制:

// 使用 advanced constraints
const constraints = {
  audio: {
    advanced: [{
      noiseSuppression: { exact: true }
      // 注意:早期 Chrome 的 goog* 私有约束(如 googNoiseSuppression、
      // googHighpassFilter 等)大多已废弃,行为不可靠,不建议在生产中使用。
      // 标准约束只有 noiseSuppression 一个开关,无法通过约束选择"新/旧 NS 实现"。
    }]
  }
};

性能指标

评估噪声抑制算法的性能通常使用以下指标:

SNR 改善 (SNR Improvement / ΔSNR)

\[\Delta\text{SNR} = \text{SNR}_{\text{output}} - \text{SNR}_{\text{input}}\]

表示噪声抑制后信噪比的提升量,单位为 dB。典型的 WebRTC NS 在不同等级下的 SNR 改善:

  • Level 0 (Low): 6~10 dB

  • Level 1 (Moderate): 10~15 dB

  • Level 2 (High): 15~20 dB

  • Level 3 (Very High): 20~25 dB

语音失真 (Speech Distortion)

  • PESQ (Perceptual Evaluation of Speech Quality):ITU-T P.862 标准,评分范围 1.0~4.5

  • POLQA (Perceptual Objective Listening Quality Analysis):ITU-T P.863 标准,PESQ 的升级版

  • STOI (Short-Time Objective Intelligibility):评估语音可懂度,范围 0~1

噪声抑制量 (Noise Attenuation)

在纯噪声段测量的噪声衰减量,单位为 dB。

音乐噪声 (Musical Noise)

音乐噪声是频谱减法类算法的典型伪影,表现为随机出现的短促音调。 可以通过主观听音测试(MOS 评分)或客观指标(如频谱方差)来评估。

噪声估计算法

噪声估计是噪声抑制的关键环节,常用的算法包括:

Minimum Statistics

由 Martin (2001) 提出,基于含噪语音功率谱的局部最小值来估计噪声功率谱。 其核心思想是:在一个较长的时间窗口内,功率谱的最小值近似等于噪声的功率谱。

MCRA (Minima Controlled Recursive Averaging)

由 Cohen 和 Berdugo (2002) 提出,结合了最小值跟踪和递归平均:

  1. 使用时间递归平均来平滑功率谱

  2. 使用局部最小值来检测语音存在

  3. 根据语音存在概率来控制噪声估计的更新速率

IMCRA (Improved MCRA)

MCRA 的改进版本,使用两次平滑来提高噪声估计的鲁棒性。

瞬态噪声抑制

WebRTC 中有专门的 TransientSuppressor 模块来处理瞬态噪声:

  • 使用短时能量检测来识别瞬态事件

  • 对检测到的瞬态事件应用快速衰减

  • 与 NS 模块独立工作,互不干扰

// TransientSuppressor 配置
config.transient_suppression.enabled = true;

参考资料

论文

  • Boll, S. (1979). "Suppression of acoustic noise in speech using spectral subtraction." IEEE Transactions on Acoustics, Speech, and Signal Processing.

  • Ephraim, Y., & Malah, D. (1984). "Speech enhancement using a minimum-mean square error short-time spectral amplitude estimator." IEEE Transactions on Acoustics, Speech, and Signal Processing.

  • Martin, R. (2001). "Noise power spectral density estimation based on optimal smoothing and minimum statistics." IEEE Transactions on Speech and Audio Processing.

  • Cohen, I., & Berdugo, B. (2002). "Noise estimation by minima controlled recursive averaging for robust speech enhancement." IEEE Signal Processing Letters.

  • Valin, J.M. (2018). "A Hybrid DSP/Deep Learning Approach to Real-Time Full-Band Speech Enhancement." IEEE MMSP.

WebRTC 源码

其他资源