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
保留人的说话声音,而将身边的噪声,例如风扇声,吃东西的声音消除,主要依据是人声的频率和噪声的频率和能量不同。
噪声抑制的基本思路是:
噪声估计 (Noise Estimation):在语音静默段或利用统计方法估计噪声的频谱特性
信噪比估计 (SNR Estimation):估计每个频率 bin 上的信噪比
增益计算 (Gain Calculation):根据信噪比计算每个频率 bin 的抑制增益
增益应用 (Gain Application):将增益应用于含噪语音的频谱,得到降噪后的语音
用数学公式表示,含噪语音信号可以建模为:
其中 \(y(n)\) 是含噪语音,\(s(n)\) 是纯净语音,\(d(n)\) 是噪声。 在频域中:
噪声抑制的目标是从 \(Y(k)\) 中估计出 \(\hat{S}(k)\)。
噪声抑制算法
谱减法 (Spectral Subtraction)
谱减法是最经典的噪声抑制方法,其基本思想是从含噪语音的功率谱中减去噪声的功率谱估计:
其中 \(|\hat{D}(k)|^2\) 是噪声功率谱的估计,通常在语音静默段(由 VAD 检测)进行更新。
为了避免过减(over-subtraction)导致的负值,引入过减因子 \(\alpha\) 和谱下限 \(\beta\):
谱减法的优点是计算简单、实时性好;缺点是容易产生 音乐噪声 (Musical Noise), 即由于帧间频谱估计的随机波动导致的不自然的音调噪声。
维纳滤波 (Wiener Filter)
维纳滤波是一种最优线性滤波方法,其目标是最小化估计信号与真实信号之间的均方误差(MSE)。 维纳滤波器的频域增益函数为:
其中 \(\text{SNR}(k)\) 是第 \(k\) 个频率 bin 的先验信噪比 (a priori SNR)。
在实际应用中,先验信噪比通常使用 Decision-Directed 方法估计:
其中 \(\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 的增益函数为:
其中 \(\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: Mild、1: Medium、2: Aggressive);而对外的 APM 配置
AudioProcessing::Config::NoiseSuppression 提供 4 档(kLow、kModerate、kHigh、kVeryHigh)。
下表以对外的 4 档配置为准。
WebRTC APM 对外提供 4 个抑制等级,对应不同的噪声抑制强度:
等级 |
名称 |
说明 |
|---|---|---|
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 等,需另行集成。
特性 |
传统方法 (谱减法/维纳滤波) |
深度学习方法 (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)
表示噪声抑制后信噪比的提升量,单位为 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) 提出,结合了最小值跟踪和递归平均:
使用时间递归平均来平滑功率谱
使用局部最小值来检测语音存在
根据语音存在概率来控制噪声估计的更新速率
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 源码
WebRTC NS 模块(传统维纳滤波,非神经网络): https://webrtc.googlesource.com/src/+/refs/heads/main/modules/audio_processing/ns/
WebRTC NoiseSuppressor(“NS2”,同为维纳滤波): https://webrtc.googlesource.com/src/+/refs/heads/main/modules/audio_processing/ns/noise_suppressor.cc
WebRTC APM 配置: https://webrtc.googlesource.com/src/+/refs/heads/main/modules/audio_processing/include/audio_processing.h
WebRTC Transient Suppressor: https://webrtc.googlesource.com/src/+/refs/heads/main/modules/audio_processing/transient/
RNNoise 项目(第三方,Chromium 中位于 third_party/rnnoise): https://github.com/xiph/rnnoise
其他资源
RNNoise 演示: https://jmvalin.ca/demo/rnnoise/
DTLN 项目: https://github.com/breizhn/DTLN
DNS Challenge (Deep Noise Suppression): https://github.com/microsoft/DNS-Challenge