关闭

深入浅出讲解谱减法

575人阅读 评论(0) 收藏 举报
分类:

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

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



结果如下所示


0
0

查看评论
* 以上用户言论只代表其个人观点,不代表CSDN网站的观点或立场
    个人资料
    • 访问:137940次
    • 积分:2031
    • 等级:
    • 排名:千里之外
    • 原创:25篇
    • 转载:264篇
    • 译文:0篇
    • 评论:2条