在语音去噪中最常用的方法是谱减法,其基本思想是通过静音段(噪声段)估计语音中的噪声成分,然后将含噪声语音减去估计的噪声就得到了纯净的语音。
思考1,:谱减法适用于整个语音中都有稳定的噪声成分。
思考2:静音段如何控制是否需要端点检测,还是手动调节?
思考3:估计的噪声如何描述(每一帧中的平均能量)。
思考4:如何减去噪声?
带着这些思考我们开始对谱减法原理上的探索。
语音的事件序列为x(n),加窗分帧处理后可以得到第i帧语音信号为xi(m),帧长为N。任何一帧语音信号xi(m)做DFT(谱减法就要变换到频域)后为
接着,我们需要得到两个分量用于后续的计算一个是幅值,一个是相位角。其中幅值就是|x(k)|,相位角为
到现在前面的处理已经完整,现需要根据静音段估计噪声,假设前面噪声段时长为IS,对应的帧数为NIS,那么可以用噪声段的平均能量值来描述噪声成分。
其能量值为
接下来就需要用原始语音减去这个噪声成分了,其计算过程如下:
式中,a和b是两个尝试,a为过减因子,b为增益补偿因子。
此时我们已经得到了在频域干净了语音,只需要经过快速傅里叶逆变换就可以得到时域的语音序列。此时这里的相位角就可以发挥作用了,由于语音信号相位不灵敏的特征,可以直接将相位角信息用到谱减后的信号中。
其流程如图所示:
整个过程的处理MATLAB程序如下所示
调用格式:output=simplesubspec(signal,wlen,inc,NIS,a,b)
参数single为带噪语音序列,wlen为帧长,ins为帧移,NIS为无语音段噪声帧数,a为过减因子,b为增益补偿因子,output为谱减法减噪的语音序列。
function output=simplesubspec(signal,wlen,inc,NIS,a,b)
wnd=hamming(wlen); % 设置窗函数
N=length(signal); % 计算信号长度
y=enframe(signal,wnd,inc)'; % 分帧
fn=size(y,2); % 求帧数
y_fft = fft(y); % FFT
y_a = abs(y_fft); % 求取幅值
y_phase=angle(y_fft); % 求取相位角
y_a2=y_a.^2; % 求能量
Nt=mean(y_a2(:,1:NIS),2); % 计算噪声段平均能量
nl2=wlen/2+1; % 求出正频率的区间
for i = 1:fn; % 进行谱减
for k= 1:nl2
if y_a2(k,i)>a*Nt(k)
temp(k) = y_a2(k,i) - a*Nt(k);
else
temp(k)=b*y_a2(k,i);
end
U(k)=sqrt(temp(k)); % 把能量开方得幅值
end
X(:,i)=U;
end;
output=OverlapAdd2(X,y_phase(1:nl2,:),wlen,inc); % 合成谱减后的语音
Nout=length(output); % 把谱减后的数据长度补足与输入等长
if Nout>N
output=output(1:N);
elseif Nout
end
output=output/max(abs(output)); % 幅值归一
实例讲解:
读入一个语音数据,叠加上5dB的白噪声,通过调用谱减法函数simplesubspec对待噪语音信号减噪。
程序如下:
%
clear all; clc; close all;
filedir=[]; % 指定文件路径
filename='bluesky1.wav'; % 指定文件名
fle=[filedir filename] % 构成路径和文件名的字符串
[xx,fs]=wavread(fle); % 读入数据文件
xx=xx-mean(xx); % 消除直流分量
x=xx/max(abs(xx)); % 幅值归一化
IS=0.25; % 设置前导无话段长度
wlen=200; % 设置帧长为25ms
inc=80; % 设置帧移为10ms
SNR=5; % 设置信噪比SNR
N=length(x); % 信号长度
time=(0:N-1)/fs; % 设置时间
signal=Gnoisegen(x,SNR); % 叠加噪声
snr1=SNR_singlech(x,signal); % 计算初始信噪比
overlap=wlen-inc; % 求重叠区长度
NIS=fix((IS*fs-wlen)/inc +1); % 求前导无话段帧数
a=4; b=0.001; % 设置参数a和b
output=simplesubspec(signal,wlen,inc,NIS,a,b);% 谱减
snr2=SNR_singlech(x,output); % 计算谱减后的信噪比
snr=snr2-snr1;
fprintf('snr1=%5.4f snr2=%5.4f snr=%5.4f\n',snr1,snr2,snr);
wavplay(signal,fs);
pause(1)
wavplay(output,fs);
% 作图
subplot 311; plot(time,x,'k'); grid; axis tight;
title('纯语音波形'); ylabel('幅值')
subplot 312; plot(time,signal,'k'); grid; axis tight;
title(['带噪语音 信噪比=' num2str(SNR) 'dB']); ylabel('幅值')
subplot 313; plot(time,output,'k');grid;%hold on;
title('谱减后波形'); ylabel('幅值'); xlabel('时间/s');
结果如下所示