2. 改进谱减法
任务目标
在基本谱减法基础上引入两个参数:过减因子(over-subtraction factor)和噪声底限(spectral floor),抑制残留的“音乐噪声”,并与基本谱减法做对比验证。
核心原理
基本谱减法估计噪声谱后直接做幅度相减,当估计偏差导致负值时被置零,形成随机出现的窄带尖峰——即音乐噪声。改进策略:
- 过减因子 α(α > 1):对噪声谱做放大后再减,更激进地压制噪声,但可能损伤语音;
- 噪声底限 β(0 < β < 1):对减后谱设下限,避免置零产生的孤立尖峰,保留少量背景噪声以掩蔽音乐噪声。
依赖与环境
需要 numpy、scipy。音频文件建议使用16-bit PCM WAV格式,采样率8k或16k均可。
关键完整代码
import numpy as np
from scipy.io import wavfile
from scipy.signal import stft, istft
def improved_spectral_subtraction(x, sr, alpha=3.0, beta=0.02, n_fft=512, hop=128, noise_frames=10):
"""
改进谱减法:过减因子alpha + 噪声底限beta
x: 含噪语音信号 (float64, 范围[-1,1])
sr: 采样率
返回: 增强后信号
"""
# STFT
f, t, Zxx = stft(x, fs=sr, nperseg=n_fft, noverlap=n_fft-hop)
mag = np.abs(Zxx)
phase = np.angle(Zxx)
# 取前noise_frames帧估计噪声谱(假设起始为纯噪声段)
noise_mu = np.mean(mag[:, :noise_frames], axis=1, keepdims=True)
# 过减 + 底限
mag_enhanced = mag - alpha * noise_mu
mag_enhanced = np.maximum(mag_enhanced, beta * noise_mu)
# 重建信号
Zxx_enhanced = mag_enhanced * np.exp(1j * phase)
_, x_enhanced = istft(Zxx_enhanced, fs=sr, nperseg=n_fft, noverlap=n_fft-hop)
return x_enhanced
def basic_spectral_subtraction(x, sr, n_fft=512, hop=128, noise_frames=10):
"""基本谱减法(alpha=1, beta=0)作为对比"""
return improved_spectral_subtraction(x, sr, alpha=1.0, beta=0.0,
n_fft=n_fft, hop=hop, noise_frames=noise_frames)
# ---- 最小调用示例 ----
if __name__ == "__main__":
sr, data = wavfile.read("noisy_speech.wav")
if data.dtype != np.float64:
data = data.astype(np.float64) / 32768.0 # 16-bit PCM转[-1,1]
enhanced_improved = improved_spectral_subtraction(data, sr)
enhanced_basic = basic_spectral_subtraction(data, sr)
# 保存结果(转回16-bit)
wavfile.write("enhanced_improved.wav", sr, (enhanced_improved * 32767).astype(np.int16))
wavfile.write("enhanced_basic.wav", sr, (enhanced_basic * 32767).astype(np.int16))
print("处理完成,输出: enhanced_improved.wav, enhanced_basic.wav")
运行与验证
- 准备含噪语音文件
noisy_speech.wav,确保前10帧(约80ms)为纯噪声段(无语音),否则需调整noise_frames或手动指定噪声帧区间。 - 运行脚本:
python spectral_subtraction.py - 验证方法:
- 主观听感:对比两个输出文件,改进版应明显减少音乐噪声(不再有“叮叮”的残留音),但可能略有背景底噪(β的作用);
- 客观指标:若原始干净语音
clean.wav可用,计算分段信噪比(segSNR)或PESQ,改进版通常高于基本版; - 波形/语谱观察:用matplotlib绘制语谱图,基本版在无声段有大量随机离散点(音乐噪声),改进版无声段平坦连续。
参数调优建议
- α 取值范围2~5,噪声大时取大值;α过大会导致语音失真(出现“水下效应”);
- β 取值范围0.005~0.05,β越大背景噪声越明显但音乐噪声越弱;
- 若语音段起始处无纯噪声段,可改为噪声估计模块(如最小值统计),本案例为聚焦参数改进,采用前帧估计。
常见问题
- 输出有金属感/颤抖:α过大或β过小,适当降低α或增大β;
- 语音段被削弱:α过大导致过减,语音段幅度被过度压制,减小α;
- 前10帧含语音:噪声估计不准,需调整
noise_frames或改用语音活动检测(VAD)定位纯噪声段。