主要内容

声回波消除(AEC)

本例展示了如何将自适应滤波器应用于声学回波消除(AEC)。

简介

当需要语音的同步通信(或全双工传输)时,声学回波消除对于音频电话会议非常重要。在声学回波消除技术中,测量的麦克风信号d (n)美元包含两个信号:

  • 近端语音信号v (n)美元

  • 远端回声语音信号美元$ \ widehat {d} (n)

目标是从麦克风信号中去除远端回声语音信号,以便仅传输近端语音信号。这个例子有一些声音剪辑,所以你现在可能想要调整你的电脑的音量。

房间脉冲响应

首先需要对扬声器所在位置的扬声器到麦克风信号路径的声学建模。使用长有限脉冲响应滤波器来描述房间的特性。下面的代码生成一个随机的脉冲响应,它与会议室所展示的没有什么不同。假设系统采样率为16000 Hz。

Fs = 16000;M = fs/2 + 1;frameSize = 2048;[B,A] = cheby2(4,20,[0.1 0.7]);impulse esponsegenerator = dsp。IIRFilter (“分子”, (0 (1,6) B),...“分母”,);FVT = fvtool(impulse esponsegenerator);%分析过滤器

roomimpulse esponsegenerator (...(日志兰德(1米)+(0.99 * 0.01)。*标志(randn(1米)。* exp (-0.002 * (1: M))) ');roomimpulse esponse = roomimpulse esponse/norm(roomimpulse esponse)*4;房间= dsp。FIRFilter (“分子”roomImpulseResponse ');图;情节(0:1 / fs: 0.5, roomImpulseResponse);包含(“时间(s)”);ylabel (“振幅”);标题(“房间冲动反应”);fig.Color = [1 1 1];

近端语音信号

电话会议系统的用户通常位于系统麦克风附近。下面是男性在麦克风前演讲的声音。

负载nearspeech播放器= audioDeviceWriter(“金宝appSupportVariableSizeInput”,真的,...“BufferSize”, 512,“SampleRate”fs);nearSpeechSrc = dsp。SignalSource (“信号”v,“SamplesPerFrame”, frameSize);nearSpeechScope = timescope(“SampleRate”fs,“TimeSpanSource”“属性”...“时间间隔”, 35岁,“TimeSpanOverrunAction”“滚动”...“YLimits”, [-1.5 1.5],...“BufferLength”长度(v),...“标题”“近端语音信号”...“ShowGrid”,真正的);%流处理循环(~结束(nearSpeechSrc))从输入信号中提取语音样本nearSpeech = nearSpeechSrc();将语音样本发送到输出音频设备球员(nearSpeech);绘制信号nearSpeechScope (nearSpeech);结束释放(nearSpeechScope);

远端语音信号

在电话会议系统中,声音从扬声器传出,在房间里来回跳动,然后被系统的麦克风接收。如果演讲是在没有临近尾声的演讲的情况下通过麦克风录下来的,听听它听起来是什么样的。

负载farspeechfarSpeechSrc = dsp。SignalSource (“信号”, x,“SamplesPerFrame”, frameSize);farspeechink = dsp.SignalSink;farSpeechScope = timescope(“SampleRate”fs,“TimeSpanSource”“属性”...“时间间隔”, 35岁,“TimeSpanOverrunAction”“滚动”...“YLimits”, [-0.5 0.5],...“BufferLength”长度(x),...“标题”“远端语音信号”...“ShowGrid”,真正的);%流处理循环(~结束(farSpeechSrc))从输入信号中提取语音样本farSpeech = farSpeechSrc();为远端语音信号添加房间效果farSpeech hecho =房间(farSpeech);将语音样本发送到输出音频设备球员(farSpeechEcho);绘制信号farSpeechScope (farSpeech);记录信号以便进一步处理farSpeechSink (farSpeechEcho);结束释放(farSpeechScope);

麦克风信号

麦克风上的信号包含在整个房间中回响的近端语音和远端语音。声学回声消除器的目标是消除远端语音,这样只有近端语音被传输回远端侦听器。

重置(nearSpeechSrc);farSpeechEchoSrc = dsp。SignalSource (“信号”, farSpeechSink。缓冲区,...“SamplesPerFrame”, frameSize);micSink = dsp.SignalSink;显微镜=时间镜(“SampleRate”fs,“TimeSpanSource”“属性”...“时间间隔”, 35岁,“TimeSpanOverrunAction”“滚动”...“YLimits”, [-1 1],...“BufferLength”长度(x),...“标题”“麦克风信号”...“ShowGrid”,真正的);%流处理循环(~结束(farSpeechEchoSrc))%麦克风信号=回声远端+回声近端+噪声micSignal = farSpeechEchoSrc() + nearSpeechSrc() +...0.001 * randn (frameSize, 1);将语音样本发送到输出音频设备球员(micSignal);绘制信号micScope (micSignal);%记录信号micSink (micSignal);结束释放(micScope);

频域自适应滤波器(FDAF)

本例中的算法为频域自适应滤波器.当待辨识系统的脉冲响应较长时,该算法非常有用。FDAF使用快速卷积技术来计算输出信号和滤波器更新。此计算在MATLAB®中快速执行。通过频仓步长归一化,该算法具有较快的收敛性能。为滤波器选择一些初始参数,看看远端语音在错误信号中被抵消的情况如何。

构造频域自适应滤波器echoCanceller = dsp。FrequencyDomainAdaptiveFilter (“长度”, 2048,...“StepSize”, 0.025,...“InitialPower”, 0.01,...“AveragingFactor”, 0.98,...“方法”“无约束FDAF”);AECScope1 = timescope(4, fs,...“LayoutDimensions”(4,1),“TimeSpanSource”“属性”...“时间间隔”, 35岁,“TimeSpanOverrunAction”“滚动”...“BufferLength”长度(x));AECScope1。ActiveDisplay = 1;AECScope1。ShowGrid = true;AECScope1。YLimits = [-1.5 1.5];AECScope1。Title =“近端语音信号”;AECScope1。ActiveDisplay = 2;AECScope1。ShowGrid = true;AECScope1。YLimits = [-1.5 1.5];AECScope1。Title =“麦克风信号”;AECScope1。ActiveDisplay = 3;AECScope1。ShowGrid = true;AECScope1。YLimits = [-1.5 1.5];AECScope1。Title ='回声消除器输出mu=0.025';AECScope1。ActiveDisplay = 4;AECScope1。ShowGrid = true;AECScope1。YLimits = [0 50];AECScope1。YLabel =“ERLE (dB)”;AECScope1。Title =回波回波损失增强mu=0.025%近端语音信号释放(nearSpeechSrc);nearSpeechSrc。SamplesPerFrame = frameSize;远端语音信号释放(farSpeechSrc);farSpeechSrc。SamplesPerFrame = frameSize;房间回声远端语音信号释放(farSpeechEchoSrc);farSpeechEchoSrc。SamplesPerFrame = frameSize;

回波回波损耗增强

由于您可以同时访问近端和远端语音信号,因此可以计算回波回波损失增强,这是一个平滑的测量回波被衰减的量(以dB为单位)。从图中可以看到,在收敛期结束时实现了约35 dB的ERLE。

diffAverager = dsp。FIRFilter (“分子”的(1024));farEchoAverager =克隆(diffAverager);setfilter (FVT diffAverager);micSrc = dsp。SignalSource (“信号”, micSink。缓冲区,...“SamplesPerFrame”, frameSize);%流处理循环-自适应过滤器步长= 0.025(~isDone(nearSpeechSrc)) nearSpeech = nearSpeechSrc();farSpeech = farSpeechSrc();farSpeechEcho = farSpeechEchoSrc();micSignal = micSrc();%应用FDAF[y,e] = echoCanceller(farSpeech, micSignal);将语音样本发送到输出音频设备球员(e);计算ERLEerle = diffAverager((e-nearSpeech).^2)。/ farEchoAverager (farSpeechEcho。^ 2);erledB = -10*log10(erle);绘制近端、远端、麦克风、AEC输出和ERLEAECScope1(nearSpeech, micSignal, e, erledB);结束释放(AECScope1);

不同步长值的影响

要获得更快的收敛,可以尝试使用更大的步长值。然而,这种增加导致了另一种影响:当近端扬声器说话时,自适应滤波器被“错调”。听听当你选择比以前大60%的步长时会发生什么。

更改FDAF中的步长值重置(echoCanceller);echoCanceller。StepSize = 0.04;AECScope2 =克隆(AECScope1);AECScope2。ActiveDisplay = 3;AECScope2。Title =回波消除器输出mu=0.04;AECScope2。ActiveDisplay = 4;AECScope2。Title =回波回波损失增强mu=0.04;重置(nearSpeechSrc);重置(farSpeechSrc);重置(farSpeechEchoSrc);重置(micSrc);重置(diffAverager);重置(farEchoAverager);%流处理循环-自适应滤波器步长= 0.04(~isDone(nearSpeechSrc)) nearSpeech = nearSpeechSrc();farSpeech = farSpeechSrc();farSpeechEcho = farSpeechEchoSrc();micSignal = micSrc();%应用FDAF[y,e] = echoCanceller(farSpeech, micSignal);将语音样本发送到输出音频设备球员(e);计算ERLEerle = diffAverager((e-nearSpeech).^2)。/ farEchoAverager (farSpeechEcho。^ 2);erledB = -10*log10(erle);绘制近端、远端、麦克风、AEC输出和ERLEAECScope2(nearSpeech, micSignal, e, erledB);结束释放(nearSpeechSrc);释放(farSpeechSrc);释放(farSpeechEchoSrc);释放(micSrc);释放(diffAverager);释放(farEchoAverager);释放(echoCanceller);释放(AECScope2);

回波回波损耗增强比较

在步长较大的情况下,由于近端语音引入的误调整,ERLE性能不佳。为了解决这一性能难题,声学回波消除器包括一种检测方案,用于判断何时出现近端语音,并在这些时间段内降低步长值。如果没有这样的检测方案,从ERLE图可以看出,步长较大的系统性能不如前者。

使用分区降低延迟

对于长脉冲响应,传统的FDAF在数值上比时域自适应滤波更有效,但由于输入帧大小必须是指定滤波器长度的倍数,因此会产生较高的延迟。这对于许多实际应用程序来说是不可接受的。通过使用分区FDAF可以降低延迟,它将滤波器脉冲响应划分为更短的段,对每个段应用FDAF,然后结合中间结果。在这种情况下,帧大小必须是分区(块)长度的倍数,从而大大减少了长脉冲响应的延迟。

将帧大小从2048减小到256frameSize = 256;nearSpeechSrc。SamplesPerFrame = frameSize;farSpeechSrc。SamplesPerFrame = frameSize;farSpeechEchoSrc。SamplesPerFrame = frameSize;micSrc。SamplesPerFrame = frameSize;将回声消除器切换为分区约束FDAFechoCanceller。方法=“分区约束FDAF”设置块长度为frameSizeechoCanceller。BlockLength = frameSize;%流处理循环(~isDone(nearSpeechSrc)) nearSpeech = nearSpeechSrc();farSpeech = farSpeechSrc();farSpeechEcho = farSpeechEchoSrc();micSignal = micSrc();%应用FDAF[y,e] = echoCanceller(farSpeech, micSignal);将语音样本发送到输出音频设备球员(e);计算ERLEerle = diffAverager((e-nearSpeech).^2)。/ farEchoAverager (farSpeechEcho。^ 2);erledB = -10*log10(erle);绘制近端、远端、麦克风、AEC输出和ERLEAECScope2(nearSpeech, micSignal, e, erledB);结束