您的位置:首页 > 其它

深入浅出谱减法去噪

2016-07-06 20:36 931 查看
在语音去噪中最常用的方法是谱减法,其基本思想是通过静音段(噪声段)估计语音中的噪声成分,然后将含噪声语音减去估计的噪声就得到了纯净的语音。

思考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<N

output=[output; zeros(N-Nout,1)];

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');

结果如下所示

内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: