深入浅出讲解谱减法
在語音去噪中最常用的方法是譜減法,其基本思想是通過靜音段(噪聲段)估計語音中的噪聲成分,然后將含噪聲語音減去估計的噪聲就得到了純凈的語音。
思考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');
結果如下所示
總結
- 上一篇: 基于谱减法的声音去噪
- 下一篇: 小波变换理论讲解