深入浅出讲解谱减法
在語(yǔ)音去噪中最常用的方法是譜減法,其基本思想是通過(guò)靜音段(噪聲段)估計(jì)語(yǔ)音中的噪聲成分,然后將含噪聲語(yǔ)音減去估計(jì)的噪聲就得到了純凈的語(yǔ)音。
思考1,:譜減法適用于整個(gè)語(yǔ)音中都有穩(wěn)定的噪聲成分。
思考2:靜音段如何控制是否需要端點(diǎn)檢測(cè),還是手動(dòng)調(diào)節(jié)?
思考3:估計(jì)的噪聲如何描述(每一幀中的平均能量)。
思考4:如何減去噪聲?
帶著這些思考我們開(kāi)始對(duì)譜減法原理上的探索。
語(yǔ)音的事件序列為x(n),加窗分幀處理后可以得到第i幀語(yǔ)音信號(hào)為xi(m),幀長(zhǎng)為N。任何一幀語(yǔ)音信號(hào)xi(m)做DFT(譜減法就要變換到頻域)后為
接著,我們需要得到兩個(gè)分量用于后續(xù)的計(jì)算一個(gè)是幅值,一個(gè)是相位角。其中幅值就是|x(k)|,相位角為
到現(xiàn)在前面的處理已經(jīng)完整,現(xiàn)需要根據(jù)靜音段估計(jì)噪聲,假設(shè)前面噪聲段時(shí)長(zhǎng)為IS,對(duì)應(yīng)的幀數(shù)為NIS,那么可以用噪聲段的平均能量值來(lái)描述噪聲成分。
其能量值為
接下來(lái)就需要用原始語(yǔ)音減去這個(gè)噪聲成分了,其計(jì)算過(guò)程如下:
式中,a和b是兩個(gè)嘗試,a為過(guò)減因子,b為增益補(bǔ)償因子。
此時(shí)我們已經(jīng)得到了在頻域干凈了語(yǔ)音,只需要經(jīng)過(guò)快速傅里葉逆變換就可以得到時(shí)域的語(yǔ)音序列。此時(shí)這里的相位角就可以發(fā)揮作用了,由于語(yǔ)音信號(hào)相位不靈敏的特征,可以直接將相位角信息用到譜減后的信號(hào)中。
其流程如圖所示:
整個(gè)過(guò)程的處理MATLAB程序如下所示
調(diào)用格式:output=simplesubspec(signal,wlen,inc,NIS,a,b)
參數(shù)single為帶噪語(yǔ)音序列,wlen為幀長(zhǎng),ins為幀移,NIS為無(wú)語(yǔ)音段噪聲幀數(shù),a為過(guò)減因子,b為增益補(bǔ)償因子,output為譜減法減噪的語(yǔ)音序列。
function output=simplesubspec(signal,wlen,inc,NIS,a,b)
wnd=hamming(wlen); ? ? ? ? ? ? ? ? ? ? ?% 設(shè)置窗函數(shù)
N=length(signal); ? ? ? ? ? ? ? ? ? ? ? % 計(jì)算信號(hào)長(zhǎng)度
y=enframe(signal,wnd,inc)'; ? ? ? ? ? ? % 分幀
fn=size(y,2); ? ? ? ? ? ? ? ? ? ? ? ? ? % 求幀數(shù)
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); ? ? ? ? ? ? ? % 計(jì)算噪聲段平均能量
nl2=wlen/2+1; ? ? ? ? ? ? ? ? ? ? ? ? ? % 求出正頻率的區(qū)間
for i = 1:fn; ? ? ? ? ? ? ? ? ? ? ? ? ? % 進(jìn)行譜減
? ? 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)); ? ? ? ? ? ? % 把能量開(kāi)方得幅值
? ? end
? ? X(:,i)=U;
end;
output=OverlapAdd2(X,y_phase(1:nl2,:),wlen,inc); ? % 合成譜減后的語(yǔ)音
Nout=length(output); ? ? ? ? ? ? ? ? ? ?% 把譜減后的數(shù)據(jù)長(zhǎng)度補(bǔ)足與輸入等長(zhǎng)
if Nout>N
? ? output=output(1:N);
elseif Nout<N
? ? output=[output; zeros(N-Nout,1)];
end
output=output/max(abs(output)); ? ? ? ? % 幅值歸一
實(shí)例講解:
讀入一個(gè)語(yǔ)音數(shù)據(jù),疊加上5dB的白噪聲,通過(guò)調(diào)用譜減法函數(shù)simplesubspec對(duì)待噪語(yǔ)音信號(hào)減噪。
程序如下:
%
clear all; clc; close all;
filedir=[]; ? ? ? ? ? ? ? ? ? ? ? ? ? ? % 指定文件路徑
filename='bluesky1.wav'; ? ? ? ? ? ? ? ?% 指定文件名
fle=[filedir filename] ? ? ? ? ? ? ? ? ?% 構(gòu)成路徑和文件名的字符串
[xx,fs]=wavread(fle); ? ? ? ? ? ? ? ? ? % 讀入數(shù)據(jù)文件
xx=xx-mean(xx); ? ? ? ? ? ? ? ? ? ? ? ? % 消除直流分量
x=xx/max(abs(xx)); ? ? ? ? ? ? ? ? ? ? ?% 幅值歸一化
IS=0.25; ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?% 設(shè)置前導(dǎo)無(wú)話(huà)段長(zhǎng)度
wlen=200; ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? % 設(shè)置幀長(zhǎng)為25ms
inc=80; ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? % 設(shè)置幀移為10ms
SNR=5; ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?% 設(shè)置信噪比SNR
N=length(x); ? ? ? ? ? ? ? ? ? ? ? ? ? ?% 信號(hào)長(zhǎng)度
time=(0:N-1)/fs; ? ? ? ? ? ? ? ? ? ? ? ?% 設(shè)置時(shí)間
signal=Gnoisegen(x,SNR); ? ? ? ? ? ? ? ?% 疊加噪聲
snr1=SNR_singlech(x,signal); ? ? ? ? ? ?% 計(jì)算初始信噪比
overlap=wlen-inc; ? ? ? ? ? ? ? ? ? ? ? % 求重疊區(qū)長(zhǎng)度
NIS=fix((IS*fs-wlen)/inc +1); ? ? ? ? ? % 求前導(dǎo)無(wú)話(huà)段幀數(shù)
a=4; b=0.001; ? ? ? ? ? ? ? ? ? ? ? ? ? % 設(shè)置參數(shù)a和b
output=simplesubspec(signal,wlen,inc,NIS,a,b);% 譜減
snr2=SNR_singlech(x,output); ? ? ? ? ? ?% 計(jì)算譜減后的信噪比
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('純語(yǔ)音波形'); ylabel('幅值')
subplot 312; plot(time,signal,'k'); grid; axis tight;
title(['帶噪語(yǔ)音 信噪比=' num2str(SNR) 'dB']); ylabel('幅值')
subplot 313; plot(time,output,'k');grid;%hold on;
title('譜減后波形'); ylabel('幅值'); xlabel('時(shí)間/s');
結(jié)果如下所示
總結(jié)
- 上一篇: 基于谱减法的声音去噪
- 下一篇: 小波变换理论讲解