博主最近轉戰語音增強研究,剛學習了最基礎也是最成熟的方法——譜減法,最早是boll提出的《Suppression of acousic noise in speech using spectral subtraction》。http://blog.csdn.net/leixiaohua1020/article/details/47276353 鏈接中的這邊博客給我幫助很大,比較詳細,matlab源碼也可以找到,對於剛入門音頻處理的小白來講,先從這邊文獻《Enhencement OF Speech Corrupted by Aconstic Noise》開始是不錯的選擇,要講的源碼也是對應這篇文獻的。
一、原理
顧名思義,譜減法,就是用帶噪信號的頻譜減去噪聲信號的頻譜。譜減法基於一個簡單的假設:假設語音中的噪聲只有加性噪聲,只要將帶噪語音譜減去噪聲譜,就可以得到純凈語音,這么做的前提是噪聲信號是平穩的或者緩慢變化的。提出這個假設就是基於短時譜(25ms),就是頻譜在短時間內是平穩不變的。
早期文獻中的方法較為簡單粗暴,公式如下:
Ps(w)是輸入的帶噪語音的頻譜,Pn(w)是估計出的噪音的頻譜,兩者相減得到D(w)差值頻譜。由於相減后可能會出現負值,所以就簡單粗暴地加上一個判斷條件,將負值全部置為0,這樣得到的結果作為最終輸出去噪語音的頻譜。
那噪音是怎么估計出來的呢?文獻中一般都假設輸入的一段語音中前n幀作為silence時間,也就是說這段時間沒有語音輸入,只有噪音,可以稱之為底噪,將這5幀中的噪音強度取平均值,作為估計出來的噪音。
但是這樣做的方法有一個缺點就是由於我們估計噪音的時候取得平均值,那么有的地方噪音強度大於平均值的時候,相減后會有殘留的噪音存在。在噪音波形譜上表現為一個一個的小尖峰,我們將這種殘存的噪聲稱之為音樂噪聲(music noise)。更為專業點的解釋如下:
為了改善這種情況,許多人都對傳統的譜減法進行了改進,今天主要說的是 Berouti的改進方法,上個世紀的論文了《Enhencement OF Speech Corrupted by Aconstic Noise》。該方法將上面的公式進行了如下修改:
可見多了兩個參數alpha 和 beta。我們將alpha稱之為相減因子,beta稱之為頻譜下限閾值參數。alpha>1,這樣可以保證相比於之前的方法能夠有更強的去噪效果,能夠去除大部分的噪聲,這樣殘余的噪聲就會少很多。但是同樣的相減后差值如果為負值,這個負值也就會更大。老方法中是將負值直接設為0,這樣殘余噪音的峰值和0之間的差值還是較為顯著,所以Berouti就想了一個辦法,就是設置一個語音的下限值beta* Pn(w)。將相減后的幅值小於此下限值得統一設置為這個固定值,這個下限值其實也是寬帶的噪音,只不過設置下限值的好處是殘余峰值相比之下沒有那么顯著,從而減小了“音樂噪聲”的影響。可以通過調整beta的值來調整這個寬帶的噪聲的強度。
好了基本的原理就是這個了,接下來就是參數的設置,文獻中根據輸入信號的SNR做了大量實現來確定alpha和beta的值,最終給出的alpha隨每一個音頻幀的SNR的變換曲線是這樣的:
也就是alpha的不能為一個固定值,需要根據每一個音頻幀的信噪比大小來確定合適的值。計算alpha的公式如下,其中1/s為斜率,alpha0位期望的SNR為0時的值:
好了,alpha得值已經確定,beta的值文獻中也給出了詳細的說明,我就不贅述了。
至於還有其他的參數,比如說frameSize, windowOverlap, DFT order等直接去看原文獻就可以。
二 、實現
下面說一下算法的代碼流程(matlab實現,分步代碼,完整代碼請參見文章開始的鏈接)
1.讀入語音數據,matlab有現成的函數,waveread()和audioread()都可以,不過waveread()函數將來會被移除。分通道進行處理。
2.設置好frameSize,windowOverlap,shift等參數
3.因為要對語音進行分幀處理,所以需要生成漢明窗hamming window,並且取前5幀估計噪聲。
4. 根據公式求出每一幀的去噪后的幅值sub_speech。
5.更新噪聲的估計
6.從頻域轉換為時域,相位信息還是采用輸入信號的相位。
7. 輸出最終去噪后的語音
有空再把圖貼上,如有理解錯誤的,請指正,謝謝。
貼圖如下:
帶噪語音波形圖
利用過減技術的譜減法去除噪音后的波形圖,beta值不同,得到的寬帶噪音和”音樂噪音“的比例也不同。
(1)beta=0.005,寬帶噪音基本上被完全去除,但是“音樂噪聲"很明顯。
(2)beta=0.01, 既含有寬帶噪音,也含有部分”音樂噪聲“
(3)beta=0.05,含有大量寬帶噪音,去噪效果不明顯,但是幾乎沒有”音樂噪音“