webRTC中語音降噪模組ANS細節詳解(二)
上篇(webRTC中語音降噪模組ANS細節詳解(一))講了維納濾波的基本原理。本篇先給出webRTC中ANS的基本處理過程,然後講其中兩步(即時域轉頻域和頻域轉時域)中的一些處理細節。
ANS的基本處理過程如下圖1:
圖1
從圖1可以看出,處理過程主要分6步,具體如下:
1) 把輸入的帶噪訊號從時域轉到頻域,主要包括分幀、加窗和短時傅里葉變換(STFT)等
2) 做初始雜訊估計,基於估計出的雜訊算先驗信噪比和後驗信噪比
3) 計算分類特徵,這些特徵包括似然比檢驗(LRT)、頻譜平坦度和頻譜差異。根據這些特徵確定語音/雜訊概率,從而判定當前訊號是語音還是雜訊。
4) 根據算出來的語音/雜訊概率去更新雜訊估計
5) 基於維納濾波去噪
6) 把去噪後的訊號從頻域轉換回時域,主要包括短時傅里葉逆變換(ISTFT)、加窗和重疊相加等。
我用於理解和調試的版本是以前的C版本,裡面又分為浮點和定點兩種實現方式。對於演算法理解來說,最好看浮點實現的版本,因為它能和演算法原理中的數學表達式很好的聯繫起來。定點實現中有很多諸如定標等工程實現上的技巧,跟數學表達式很難直接聯繫。部署時如有load等制約因素,最好用定點的實現,因為通常定點實現的load比浮點實現的小不少。ANS支援8k/16k/32k HZ等三種取樣率。對於語音來說,最常用的是16k HZ的,本文以及後續的均設定採用率為16k HZ。語音訊號處理時以幀為單位,ANS中一幀為10 ms,可以算出一幀是160個取樣點。語音訊號處理又通常在頻域下進行的,因此先要把時域訊號變成頻域訊號,處理後再把頻域訊號變回時域訊號。時域訊號變頻域訊號在ANS降噪處理過程的開始部分,頻域訊號變時域訊號在ANS降噪處理過程的結束部分,但它們是相對稱的,且它們與降噪處理演算法無關,因此把它們放在一起講。下面講講時頻互轉中的一些細節。
先看從時域訊號變成頻域訊號。主要步驟是分幀、加窗和做短時傅里葉變換(STFT)。分幀上面說過,10 ms一幀,每幀160個取樣點。加窗的目的是避免頻譜泄漏。有多種窗函數,常見的有矩形窗、三角窗、漢寧(hanning)窗和海明(hamming)窗等。語音處理中常用的是漢寧窗和海明窗。ANS中用的是漢寧窗和矩形窗混在一起的混合窗。做STFT要求點數是2的N次方,現在每幀160個點,大於160的最近的2的N次方是256,所以STFT一次處理256個點(這也是程式碼中256(#define ANAL_BLOCKL_MAX 256)的由來)。現在每幀160個點,需要補成256個點。一種做法是在160個點後面補零補成256個點。ANS用了一種更好的方法。用上一幀的尾部的96個點來補從而形成256個點。這樣從時域訊號變成頻域訊號的處理流程如下圖2:
圖2
因為對256點做STFT,所以加窗的點數也是256。ANS用的是窗是漢寧和矩形混合窗。漢寧窗函數是w(n) = 0.5 * (1 + cos(2*pi*n / (N-1))),範圍是(0,1),波形如下圖3。
圖3
這個混合窗是把192(96*2)點的漢寧窗在頂點處插入64點的幅值為1的矩形窗,從而形成256(256 = 192 + 64)點的混合窗,波形如下圖4。
圖4
至於為什麼要這麼做,後面講頻域轉換到時域時再說。256個點的值與相應的窗函數相乘,得到要送進STFT處理的值。STFT處理後得到256個頻點的值,這些值除了第0點和第N/2點(N=256,即第128點)點是實數外,其餘點都是複數,且關於第N/2點共軛對稱。因為共軛對稱,一個點知道了,它的對稱點就可以求出來。所以STFT處理後有(N/2 + 1)個點的值。這裡N=256,STFT的輸出是129個點的值。這也是程式碼中129(#define HALF_ANAL_BLOCKL 129)的由來。得到129個頻點的值後還要算每個頻點的幅度譜和能量等,用於後面降噪演算法,具體處理如下面程式碼,已給出詳細的注釋,就不細說了。
在頻域做完降噪處理後需要把訊號從頻域變回時域,即訊號的重建或者合成,主要步驟是做短時傅里葉反變換(ISTFT)、加窗和重疊相加(overlap add, OLA)等,處理流程如下圖5。
圖5
先做ISTFT(短時傅里葉反變換),得到256點的實數值。這256點包括上一幀的尾部的96點,即有重疊。該怎麼拼接保證聲音連貫呢?上面講從時域到頻域變換時用的窗是漢寧矩形混合窗,漢寧窗前半部分(頭部96點)類似於做正弦操作,後半部分(尾部96點)類似於做餘弦操作。重疊部分是在上一幀的尾部,加窗做的是類餘弦操作,在當前幀是頭部,加窗做的是類正弦操作。訊號重建疊加時一般要求能量或者幅值不變,能量是幅值的平方。那些重疊的點(假設幅值為m)在上一幀中加窗時做了類餘弦操作,加窗後幅值變成了m*cosθ,在當前幀中加窗時做了類正弦操作,加窗後幅值變成了m*sinθ,能量和為m2*cos2θ + m2*sin2θ, 正好等於m2(原訊號的能量),這說明只要把重疊部分相加就可以保證語音訊號的連貫了。這就解釋了程式碼中把ISTFT後的值再做一次加窗操作並把重疊部分相加的原因。具體程式碼見下圖6。
圖6
至於矩形窗部分,幅值為1,即加窗後訊號幅值不變,因而不需要做處理,直接填上就可以了。需要注意的是圖6中還有一個能量縮放因子factor。它在前200幀默認為1,後續幀按如下邏輯關係得到。
圖7給出了做完ISTFT後數據拼接的示意圖。做完ISTFT後有256點數據,當前幀的頭部96點數據與上一幀的尾部96點數據相加,中間64點數據不變,當前幀尾部96點數據與下一幀的頭部96點數據相加,這樣就能很好的拼接處連貫的語音數據了。
圖7
下篇將講雜訊的初始估計以及基於估計出來的雜訊算先驗信噪比和後驗信噪比。