题目说明
ACE 声学回声消除
FDAF 频域自适应滤波算法
回音产生原因
声学回音
麦克风直接采集到喇叭播放的声音:直接耦合
麦克风采集到空间反射造成的回声:远端信号
直接耦合:距离很近,基本为接收信号延迟,一般设备会直接滤除。
远端信号:成分复杂,为接收信号的多次残留叠加。
线路回音
由于2-4线匹配耦合转换引入的线路回音,不做详细介绍。
系统建模
先验条件
麦克风采集信号有延迟
开始对话前有空白时间
对话过程会产生双向通话,产生混叠。
设:
接收信号的人为A A A ,发送信号到B B B
接收信号为x x x
经过空间反射的回声为y y y
近端麦克风采集信号为v v v ,
那么麦克风采集声音为d = v + y d=v+y d = v + y
x x x 和y y y 有很高的相关度
希望找到一个关系来模拟回声路径,设y ‘ = h x y‘ = hx y ‘ = h x
理想输出为v = d − y ′ v=d-y' v = d − y ′
误差e = y − y ′ = y − h x e=y-y'=y-hx e = y − y ′ = y − h x
对于一个固定场景,h h h 最终应该是一个较为稳定的场景。
假设B B B 先说话,对于A A A 短时间处有:
v = 0 v=0 v = 0 ,麦克风采集声音为y y y ,理想输出为0 0 0 ,实际为e e e 此时可以对h h h 估计;
双向通话中无法确定理想输出v v v ,此时无法对h进行估计;
反射回声y = 0 y=0 y = 0 时无法更新。
故h h h 的估计建立在对话开始很短一段时间和单项通话过程。
完整的回声消除系统
此处主要针对后两个进行建模处理。
时延估计
(线性)回声消除
双讲检测
非线性残余声学回声抑制
算法实现
FDAF算法
设x x x 分块L L L ,h h h 长度M M M ,一般取L = M L=M L = M
X k = F F T [ x k − L x k ] 2 M 点后端补 0 , H k = F F T [ h k 0 ] Y k = X k ⊙ H k ,取后 M 点 y k = I F F T ( Y k ) e k = d k − y k 2 M 点前端补 0 , E k = F F T [ 0 e k ] ∇ k = I F F T ( X K H ⊙ E k ) ,取前 M 点 H k + 1 = H k + μ F F T [ ∇ k − L 0 ] \begin{split}
&X_k=FFT\begin{bmatrix}
x_{k-L}\\
x_k
\end{bmatrix}\\
&2M点后端补0,H_k = FFT\begin{bmatrix}
h_{k}\\
0
\end{bmatrix}\\
&Y_k = X_k \odot H_k,取后M点\\
&y_k = IFFT(Y_k)\\
&e_k = d_k - y_k\\
&2M点前端补0,E_k = FFT\begin{bmatrix}
0\\
e_k
\end{bmatrix}\\
&\nabla _k = IFFT(X_K^H\odot E_k),取前M点\\
&H_{k+1} = H_k + \mu FFT\begin{bmatrix}
\nabla _{k-L}\\
0
\end{bmatrix}
\end{split}
X k = FFT [ x k − L x k ] 2 M 点后端补 0 , H k = FFT [ h k 0 ] Y k = X k ⊙ H k ,取后 M 点 y k = I FFT ( Y k ) e k = d k − y k 2 M 点前端补 0 , E k = FFT [ 0 e k ] ∇ k = I FFT ( X K H ⊙ E k ) ,取前 M 点 H k + 1 = H k + μ FFT [ ∇ k − L 0 ]
在数值上麦克风期望输出等于e k e_k e k
双讲检测&确定h更新条件
采用DTD信号相关度,余弦相似性。
当没有近处信号v v v ,
麦克风采集信号d = v + y = y d=v+y=y d = v + y = y ,和输入信号相似度很大:
x T d x T x + d T d = x T y x T x + y T y = x T h x x T x + ( h x ) T h x ≈ 1 \begin{split}
\frac{x^Td}{\sqrt{x^Tx+d^Td}}=&\frac{x^Ty}{\sqrt{x^Tx+y^Ty}}\\
=&\frac{x^Thx}{\sqrt{x^Tx+(hx)^Thx}}\\
\approx & 1
\end{split}
x T x + d T d x T d = = ≈ x T x + y T y x T y x T x + ( h x ) T h x x T h x 1
当双向通信时候麦克风采集信号d d d 和输入信号x x x 相似度很小:
x T d x T x + d T d ≈ 0 \frac{x^Td}{\sqrt{x^Tx+d^Td}}\approx 0
x T x + d T d x T d ≈ 0
设置合适阈值判断是否更新
当v v v ,y y y 均为0 0 0 ,h h h 不更新;
当v = 0 v=0 v = 0 ,y ≠ y \ne y = ,h h h 开始更新;
当v ≠ 0 v \ne 0 v = 0 ,y = 0 y=0 y = 0 ,h h h 不更新.
为了确保1.可以有效计算,修正公式,其中ϵ \epsilon ϵ 为一很小的给定常数。
x T d x T x + d T d + ϵ \frac{x^Td}{\sqrt{x^Tx+d^Td+\epsilon}}
x T x + d T d + ϵ x T d
性能分析&对比NLMS算法:
此处选择了一段5s以后开始的双讲混合音频。音频采样率16k,滤波器阶数2k。
从时域上来看还是很难看出性能,但是看时频谱图就可以看出FDAF算法还是很强的。
其实就是把NLMS的batch_size开大了。
音频对比
原始音频
Your browser does not support the video tag.
NLMS滤波
Your browser does not support the video tag.
DADF滤波
Your browser does not support the video tag.
NLMS 时域
FDAF 时域
NLMS 对数
FDAF 对数
NLMS 时谱图
FDAF 时谱图
其他应用
经过一定程度修改可用于音频中的背景音乐和人声分离。
不足
未考虑滤波器参数更新计算时间。
环境建模过于理想,实际的回声传播很复杂
代码参考
实际上并没有做双讲检测,但是效果依然不错。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 function [en, H] = FDAF (d,x,mu,mu_unconst, M, DTDbegin) x_new = zeros (M,1 ); x_old = zeros (M,1 ); AdaptStart = 2 *M; H = zeros (2 *M,1 ); d_block = zeros (M,1 ); power_alpha = 0.5 ; power = zeros (2 *M,1 ); d_length = length (d); en = []; window_save_first_M = [ones (1 ,M), zeros (1 ,M)]'; for k = 1 :d_length x_new = [x_new(2 :end ); x(k)]; d_block = [d_block(2 :end ); d(k)]; if mod (k,M)==0 x_blocks = [x_old; x_new]; x_old = x_new; if k >= AdaptStart Xk = fft(x_blocks); Yk = Xk.*H; temp = real (ifft(Yk)); yk = temp(M+1 :2 *M); error = d_block-yk; Ek = fft([zeros (1 ,M),error']'); power = (power_alpha.*power) + (1 - power_alpha).*(abs (Xk).^2 ); if k <DTDbegin gradient = real (ifft((1. /power).*conj (Xk).* Ek)); gradient = gradient.*window_save_first_M; H = H + mu.*(fft(gradient)); else gradient = conj (Xk).* Ek; H = H + mu_unconst.*gradient; end en = [en; error]; end end end
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 clear all; [x, ~] = audioread('ref.wav' ); [d, Fs] = audioread('mic_sig_spe_5.wav' ); M =2001 ; mu = 1 ; mu_unconst = 0 ; N=length (x); DTDbegin = 50000 ; [en, W] = FDAF(d,x,mu,mu_unconst, M, DTDbegin); audiowrite('output_FDAF.wav' ,en,Fs) figure (1 )subplot(3 ,1 ,1 ) plot (d)xlabel('time (samples)' ); ylabel('d(n)' ); grid on axis([0 N -1 1 ]); subplot(3 ,1 ,2 ) plot (x)xlabel('time (samples)' ); ylabel('x(n)' ); grid on axis([0 N -1 1 ]); subplot(3 ,1 ,3 ) plot (en)xlabel('time (samples)' ); ylabel('e(n)' ); grid on axis([0 N -1 1 ]); figure (2 );ee= 20 * log10 (abs (en)); figure (2 )plot (ee)xlabel('time (samples)' ); ylabel('e(n)/dB' ); grid on s = spectrogram(d, 256 ); t = linspace (0 , 4 *16000 /Fs, size (s,1 )); f = linspace (0 , Fs/2 , size (s,2 )); figure (3 );subplot(1 ,3 ,1 ) imagesc(t, f, 20 *log10 ((abs (s))));xlabel('Samples' ); ylabel('dn/Freqency' ); colorbar; s = spectrogram(d, 256 ); t = linspace (0 , 4 *16000 /Fs, size (s,1 )); f = linspace (0 , Fs/2 , size (s,2 )); subplot(1 ,3 ,2 ) imagesc(t, f, 20 *log10 ((abs (s))));xlabel('Samples' ); ylabel('xn/Freqency' ); colorbar; s = spectrogram(en, 256 ); t = linspace (0 , 4 *16000 /Fs, size (s,1 )); f = linspace (0 , Fs/2 , size (s,2 )); subplot(1 ,3 ,3 ) imagesc(t, f, 20 *log10 ((abs (s))));xlabel('Samples' ); ylabel('en/Freqency' ); colorbar;