LMS算法的参数更新,得到每个样本点,权重便更新一次,一次更新的频率过快,收敛速度慢并且不稳定。
BLMS算法的参数更新,类似于神经网络中的batch,收集一组数据(L个采样点),计算误差的均值,再进行更新,及每过L个样本点后,w更新一次。理想情况下,随着迭代次数的增加,w的值会越来越接近真实回声路径的值,误差e的值也会逐渐趋于近端语音。但在实际应用中,由于受通信设备所使用的扬声器和麦克风等电子元器件的失真影响,回声路径会表现出一定的非线性特征。而在AEC中使用的往往都是线性结构的自适应滤波器,回声中的非线性部分是无法通过线性自适应滤波消除的,这就导致AEC线性滤波之后仍然残留有一定的回声。也就是说,e(n)的值很难趋于近端语音,这部分回声残留需运用非线性处理技术(NonlinearProcessing,NLP)做进一步抑制,才能较完美地消除回声。
代码如下:
import numpy as np
import librosa
import soundfile as sf
import pyroomacoustics as pra
from scipy.linalg import hankel
def blms(x, d, N=4, L=4, mu = 0.1):
nIters = min(len(x),len(d))//L
u = np.zeros(L+N-1)
w = np.zeros(N)
e = np.zeros(nIters*L)
for n in range(nIters):
u[:-L] = u[L:]
u[-L:] = x[n*L:(n+1)*L]
d_n = d[n*L:(n+1)*L]
A = hankel(u[:L],u[-N:])
e_n = d_n - np.dot(A,w)
w = w + mu*np.dot(A.T,e_n)/L
e[n*L:(n+1)*L] = e_n
return e
# x 原始参考信号
# v 理想mic信号
# 生成模拟的mic信号和参考信号
def creat_sim_sound(x,v):
rt60_tgt = 0.08
room_dim = [2, 2, 2]
e_absorption, max_order = pra.inverse_sabine(rt60_tgt, room_dim)
room = pra.ShoeBox(room_dim, fs=sr, materials=pra.Material(e_absorption), max_order=max_order)
room.add_source([1.5, 1.5, 1.5])
room.add_microphone([0.1, 0.5, 0.1])
room.compute_rir()
rir = room.rir[0][0]
rir = rir[np.argmax(rir):]
# x 经过房间反射得到 y
y = np.convolve(x,rir)
scale = np.sqrt(np.mean(x**2)) / np.sqrt(np.mean(y**2))
# y 为经过反射后到达麦克风的声音
y = y*scale
L = max(len(y),len(v))
y = np.pad(y,[0,L-len(y)])
v = np.pad(v,[L-len(v),0])
x = np.pad(x,[0,L-len(x)])
d = v + y
return x,d
if __name__ == "__main__":
x_org, sr = librosa.load('female.wav',sr=8000)
v_org, sr = librosa.load('male.wav',sr=8000)
x,d = creat_sim_sound(x_org,v_org)
e = blms(x, d,N=256,L=4,mu=0.2)
sf.write('x.wav', x, sr, subtype='PCM_16')
sf.write('d.wav', d, sr, subtype='PCM_16')
sf.write('blms.wav', e, sr, subtype='PCM_16')
参考资料: