本文是音頻處理的朋友icoolmedia(QQ:314138065)的投稿。對音頻處理有興趣的朋友可以通過下面的方式與他交流:
作者:icoolmedia
QQ:314138065
音視訊算法讨論QQ群:374737122
先說明下,這裡的代碼流程是修改過的Speex流程,但與Speex代碼差異不大,應該不影響閱讀。
(1)用RemoveDCoffset函數進行去直流
(2)遠端信号預加重後放入x[i+frame_size],近端信号預加重後放入input緩沖區
(3)前M-1幀的遠端頻域信号移位,為目前幀頻域信号騰出空間
(4)用spx_fft函數進行FFT變換,變換後的系數存在X中
(5)計算目前遠端信号目前幀的方差Sxx。(去直流操作後,意味着均值可以視為零)
(6)目前遠端時域信号移位,x[i] = x[i+frame_size],50%交疊處理
(7)先用前景濾波器進行濾波
(8)将濾器後的輸出進行反變換
(9)再用近端信号(麥克風語音)減去濾波輸出得到前景濾波器的語差信号
(10)再用mdf_inner_prod計算前景濾後器的時域誤差總功率
(11)使用mdf_adjust_prop計算背景濾波器各段(每個)相同頻率的系數幅度,存放在prop( 這裡進行了歸一化處理)。
(12)用weighted_spectral_mul_conj函數計算背景濾波器頻域系數需要調整多少量,(其思想為LMS:步長乘以W*E)
power_1 最優步長因子,具體可以參考Mader算法,與prop相乘得到最化步長
prop 為歸一化後的背景濾波器各頻率的系數幅度。與power_1相乘
X 為轉換到頻域後的遠端信号
E 為轉換到頻域後的誤差信号
PHI 輸出結果:背景濾波器頻域系數需要調整的量
(13)背景濾波器頻域系數調整:W[j*N+i] = W[j*N+i]+ PHI[i]
(14)防止循環卷積處理(重疊保留法變循環卷積為線性卷積,把相關塊的FFT系數中的後半部分置為零)
(15)根據調整後的背景濾波器對遠端信号再進行頻域濾波處理
(16)濾波後的輸出進行反變換,存到y
(17)在時域計算兩次濾波之間的誤差及兩次濾波之間誤差的功率Dbf
(18)在時域計算背景濾波器濾波後的誤差和背景濾波器濾波後誤差的方差See。至此我們得到:
Sff 前景濾波後的方差
See 背景濾波後的方差
Dbf 前景濾波與背景濾波之間方差
(19)利用Sff、See、Dbf來計算是否需要更新前景濾波器(總的來說,當Dbf值比較大時需要更新前景濾波器系數)
(20)如果需要更新前景濾波器系數則把背景濾波器系數給前景濾波器,并平滑背景濾波後的時域誤差(前景濾波時域語差加上背景濾波器的時域輸出),得到總誤差,存在e[i+frame_size],這裡的總誤差,就是總的遠端信号回聲。
(21)根據總的遠端信号回聲,計算回聲消除後的語音信号,并進行預加重處理,存在out輸出緩沖區中(這個步驟是我自己調的)
(22)誤差緩沖區移動,為下一幀處理做好準備
(23)計算背景濾波器輸出與誤差的互相關Sey、背景濾波器的自相關Syy
(24)再把語差信号與輸出信号(前面都置為0)都是變換到頻域
(25)再計算變換後的E、Y、X的功率譜,對應的分别是Rf、Xf、Xf
(26)通過Xf平滑得到遠端信号功率譜power
power[j] = (ss_1*power[j]) + 1 + (ss*Xf[j]);
(27)當(前一幀的)洩露系數小于一個閥值(0.5)時,重新估算遠端信号功率譜power
(28)計算ey協方差,得到e和y的相關系數 Pey,标準差 Pyy。(Pey為相關系數:ey協方差/y标準差)
(29)計算遠端信号洩露系數
參考論文:On Adjusting the Learning Rate in Frequency Domain Echo Cancellation With Double-Talk
先計算遞歸平均系數:alpha = beta0*Syy/See; 這裡beta0為洩露估計的學習速率alpha_1 = 1-alpha;再遞歸計算相關系數Pey和标準差Pyy
最後得到洩露系數:leak_estimate = Pey/Pyy
(30)計算殘餘回聲與誤差的比率,并做上下限處理。
RER = (0.0001*Sxx + 3.0f*leak_estimate*Syy) / See;
下限:Sey*Sey/(1+See*Syy)
上限:0.5
(31)判斷收斂條件:sum_adapt > M 且leak_estimate > 0.03
如果濾波器收斂:
r = 0.7*leak_estimate*Yf + 0.3*RER*(RF+1) // 計算殘餘回聲的功率// 計算最優步長因子,具體可以參考Mader算法,或者到本文作者那裡尋求幫助power_1[i] = r / (e*(power[i]+10));
如果沒有收斂
當Sxx > N*1000時,按如下計算adapt,否則adapt_rate值為0adapt_rate = 0.25f*Sxx/See;sum_adapt += adapt_rate
(32)把殘餘回聲儲存在last_y,這是為了語音增強時去掉回聲的影響
icoolmedia聲明:
本文為原創,歡迎轉發到部落格上,轉發時第一頁的版權資訊必須保留!謝謝!