exponenta event banner

Акустическая эхоподавление (AEC)

В этом примере показано, как применять адаптивные фильтры к акустической эхо-компенсации (AD).

Автор (авторы): Скотт К. Дуглас

Введение

Акустическая эхо-компенсация важна для аудиотелеконференции, когда необходима одновременная связь (или полнодуплексная передача) речи. При акустическом эхо-подавлении измеренный микрофонный сигнал$d(n)$ содержит два сигнала:

  • Речевой сигнал ближнего конца $v(n)$

  • Эхо-речевой сигнал дальнего конца $\widehat{d}(n)$

Целью является удаление эхо-сигнала дальнего конца из сигнала микрофона так, чтобы передавался только речевой сигнал ближнего конца. В этом примере есть звуковые клипы, поэтому может потребоваться изменить громкость компьютера.

Импульсная реакция помещения

Сначала нужно смоделировать акустику тракта сигнала громкоговоритель-микрофон, где находится громкоговоритель. Используйте фильтр с длинной конечной импульсной характеристикой для описания характеристик помещения. Следующий код генерирует случайную импульсную характеристику, которая не похожа на то, что показывал бы конференц-зал. Предположим, частота дискретизации системы составляет 16000 Гц.

fs = 16000;
M = fs/2 + 1;
frameSize = 2048;

[B,A] = cheby2(4,20,[0.1 0.7]);
impulseResponseGenerator = dsp.IIRFilter('Numerator', [zeros(1,6) B], ...
    'Denominator', A);

FVT = fvtool(impulseResponseGenerator);  % Analyze the filter
FVT.Color = [1 1 1];

roomImpulseResponse = impulseResponseGenerator( ...
        (log(0.99*rand(1,M)+0.01).*sign(randn(1,M)).*exp(-0.002*(1:M)))');
roomImpulseResponse = roomImpulseResponse/norm(roomImpulseResponse)*4;
room = dsp.FIRFilter('Numerator', roomImpulseResponse');

fig = figure;
plot(0:1/fs:0.5, roomImpulseResponse);
xlabel('Time (s)');
ylabel('Amplitude');
title('Room Impulse Response');
fig.Color = [1 1 1];

Речевой сигнал ближнего конца

Пользователь системы телеконференций обычно располагается вблизи микрофона системы. Вот как звучит мужская речь у микрофона.

load nearspeech

player          = audioDeviceWriter('SupportVariableSizeInput', true, ...
                                    'BufferSize', 512, 'SampleRate', fs);
nearSpeechSrc   = dsp.SignalSource('Signal',v,'SamplesPerFrame',frameSize);
nearSpeechScope = timescope('SampleRate', fs, 'TimeSpanSource','Property',...
                    'TimeSpan', 35, 'TimeSpanOverrunAction', 'Scroll', ...
                    'YLimits', [-1.5 1.5], ...
                    'BufferLength', length(v), ...
                    'Title', 'Near-End Speech Signal', ...
                    'ShowGrid', true);

% Stream processing loop
while(~isDone(nearSpeechSrc))
    % Extract the speech samples from the input signal
    nearSpeech = nearSpeechSrc();
    % Send the speech samples to the output audio device
    player(nearSpeech);
    % Plot the signal
    nearSpeechScope(nearSpeech);
end
release(nearSpeechScope);

Речевой сигнал дальнего конца

В системе телеконференцсвязи голос выходит из громкоговорителя, отскакивает в комнате и затем забирается микрофоном системы. Слушайте, как звучит речь, если она подбирается к микрофону без присутствия речи на ближнем конце.

load farspeech
farSpeechSrc    = dsp.SignalSource('Signal',x,'SamplesPerFrame',frameSize);
farSpeechSink   = dsp.SignalSink;
farSpeechScope  = timescope('SampleRate', fs, 'TimeSpanSource','Property',...
                    'TimeSpan', 35, 'TimeSpanOverrunAction', 'Scroll', ...
                    'YLimits', [-0.5 0.5], ...
                    'BufferLength', length(x), ...
                    'Title', 'Far-End Speech Signal', ...
                    'ShowGrid', true);

% Stream processing loop
while(~isDone(farSpeechSrc))
    % Extract the speech samples from the input signal
    farSpeech = farSpeechSrc();
    % Add the room effect to the far-end speech signal
    farSpeechEcho = room(farSpeech);
    % Send the speech samples to the output audio device
    player(farSpeechEcho);
    % Plot the signal
    farSpeechScope(farSpeech);
    % Log the signal for further processing
    farSpeechSink(farSpeechEcho);
end
release(farSpeechScope);

Сигнал микрофона

Сигнал в микрофоне содержит как речь ближнего конца, так и речь дальнего конца, которая была эхолотирована по всему помещению. Целью акустического эхоподавителя является отмена речи на дальнем конце, так что только речь на ближнем конце передается обратно слушателю на дальнем конце.

reset(nearSpeechSrc);
farSpeechEchoSrc = dsp.SignalSource('Signal', farSpeechSink.Buffer, ...
                    'SamplesPerFrame', frameSize);
micSink         = dsp.SignalSink;
micScope        = timescope('SampleRate', fs,'TimeSpanSource','Property',...
                    'TimeSpan', 35, 'TimeSpanOverrunAction', 'Scroll',...
                    'YLimits', [-1 1], ...
                    'BufferLength', length(x), ...
                    'Title', 'Microphone Signal', ...
                    'ShowGrid', true);

% Stream processing loop
while(~isDone(farSpeechEchoSrc))
    % Microphone signal = echoed far-end + near-end + noise
    micSignal = farSpeechEchoSrc() + nearSpeechSrc() + ...
                0.001*randn(frameSize,1);
    % Send the speech samples to the output audio device
    player(micSignal);
    % Plot the signal
    micScope(micSignal);
    % Log the signal
    micSink(micSignal);
end
release(micScope);

Адаптивный фильтр частотной области (FDAF)

Алгоритм в этом примере - адаптивный фильтр частотной области (FDAF). Этот алгоритм очень полезен, когда импульсная характеристика идентифицируемой системы велика. FDAF использует метод быстрой свертки для вычисления выходного сигнала и обновления фильтра. Это вычисление выполняется быстро в MATLAB ®. Он также имеет быструю сходимость за счет нормализации размера шага частотного бина. Выберите некоторые начальные параметры фильтра и проверьте, насколько хорошо в сигнале ошибки отменяется речь на дальнем конце.

% Construct the Frequency-Domain Adaptive Filter
echoCanceller    = dsp.FrequencyDomainAdaptiveFilter('Length', 2048, ...
                    'StepSize', 0.025, ...
                    'InitialPower', 0.01, ...
                    'AveragingFactor', 0.98, ...
                    'Method', 'Unconstrained FDAF');

AECScope1   = timescope(4, fs, ...
                'LayoutDimensions', [4,1],'TimeSpanSource','Property', ...
                'TimeSpan', 35, 'TimeSpanOverrunAction', 'Scroll', ...
                'BufferLength', length(x));

AECScope1.ActiveDisplay = 1;
AECScope1.ShowGrid      = true;
AECScope1.YLimits       = [-1.5 1.5];
AECScope1.Title         = 'Near-End Speech Signal';

AECScope1.ActiveDisplay = 2;
AECScope1.ShowGrid      = true;
AECScope1.YLimits       = [-1.5 1.5];
AECScope1.Title         = 'Microphone Signal';

AECScope1.ActiveDisplay = 3;
AECScope1.ShowGrid      = true;
AECScope1.YLimits       = [-1.5 1.5];
AECScope1.Title         = 'Output of Acoustic Echo Canceller mu=0.025';

AECScope1.ActiveDisplay = 4;
AECScope1.ShowGrid      = true;
AECScope1.YLimits       = [0 50];
AECScope1.YLabel        = 'ERLE (dB)';
AECScope1.Title         = 'Echo Return Loss Enhancement mu=0.025';

% Near-end speech signal
release(nearSpeechSrc);
nearSpeechSrc.SamplesPerFrame = frameSize;

% Far-end speech signal
release(farSpeechSrc);
farSpeechSrc.SamplesPerFrame = frameSize;

% Far-end speech signal echoed by the room
release(farSpeechEchoSrc);
farSpeechEchoSrc.SamplesPerFrame = frameSize;

Повышение потерь при эхо-возврате (ERLE)

Так как у вас есть доступ как к речевым сигналам ближнего, так и дальнего конца, вы можете вычислить усиление обратной потери эхо-сигнала (ERLE), которое является сглаженной мерой величины (в дБ), что эхо-сигнал был ослаблен. На графике обратите внимание, что в конце периода сходимости достигнуто около 35 дБ ERLE.

diffAverager = dsp.FIRFilter('Numerator', ones(1,1024));
farEchoAverager = clone(diffAverager);
setfilter(FVT,diffAverager);

micSrc = dsp.SignalSource('Signal', micSink.Buffer, ...
    'SamplesPerFrame', frameSize);

% Stream processing loop - adaptive filter step size = 0.025
while(~isDone(nearSpeechSrc))
    nearSpeech = nearSpeechSrc();
    farSpeech = farSpeechSrc();
    farSpeechEcho = farSpeechEchoSrc();
    micSignal = micSrc();
    % Apply FDAF
    [y,e] = echoCanceller(farSpeech, micSignal);
    % Send the speech samples to the output audio device
    player(e);
    % Compute ERLE
    erle = diffAverager((e-nearSpeech).^2)./ farEchoAverager(farSpeechEcho.^2);
    erledB = -10*log10(erle);
    % Plot near-end, far-end, microphone, AEC output and ERLE
    AECScope1(nearSpeech, micSignal, e, erledB);
end
release(AECScope1);

Влияние различных значений размера шага

Для ускорения сходимости можно использовать большее значение размера шага. Однако это увеличение вызывает и другой эффект: адаптивный фильтр «неправильно настраивается», пока говорящий на ближнем конце говорит. Слушайте, что происходит, когда вы выбираете размер шага, который на 60% больше, чем раньше.

% Change the step size value in FDAF
reset(echoCanceller);
echoCanceller.StepSize = 0.04;

AECScope2 = clone(AECScope1);
AECScope2.ActiveDisplay = 3;
AECScope2.Title = 'Output of Acoustic Echo Canceller mu=0.04';
AECScope2.ActiveDisplay = 4;
AECScope2.Title = 'Echo Return Loss Enhancement mu=0.04';

reset(nearSpeechSrc);
reset(farSpeechSrc);
reset(farSpeechEchoSrc);
reset(micSrc);
reset(diffAverager);
reset(farEchoAverager);

% Stream processing loop - adaptive filter step size = 0.04
while(~isDone(nearSpeechSrc))
    nearSpeech = nearSpeechSrc();
    farSpeech = farSpeechSrc();
    farSpeechEcho = farSpeechEchoSrc();
    micSignal = micSrc();
    % Apply FDAF
    [y,e] = echoCanceller(farSpeech, micSignal);
    % Send the speech samples to the output audio device
    player(e);
    % Compute ERLE
    erle = diffAverager((e-nearSpeech).^2)./ farEchoAverager(farSpeechEcho.^2);
    erledB = -10*log10(erle);
    % Plot near-end, far-end, microphone, AEC output and ERLE
    AECScope2(nearSpeech, micSignal, e, erledB);
end

release(nearSpeechSrc);
release(farSpeechSrc);
release(farSpeechEchoSrc);
release(micSrc);
release(diffAverager);
release(farEchoAverager);
release(echoCanceller);
release(AECScope2);

Сравнение улучшения потерь при эхо-возврате

При большем размере шага производительность ERLE не так хороша из-за неправильной настройки, введенной речью ближнего конца. Чтобы справиться с этой трудностью, акустические эхоподавители включают в себя схему обнаружения, чтобы определить, когда присутствует речь ближнего конца, и снизить значение размера шага в течение этих периодов. Без таких схем обнаружения производительность системы с большим размером шага не так хороша, как первая, что видно из графиков ERLE.

Уменьшение задержек с помощью секционирования

Традиционная FDAF численно эффективнее, чем адаптивная фильтрация во временной области для длинных импульсных откликов, но она накладывает высокую задержку, поскольку размер входного кадра должен быть кратен заданной длине фильтра. Это может быть неприемлемо для многих реальных приложений. Задержка может быть уменьшена путем использования разделенного FDAF, который разделяет импульсную характеристику фильтра на более короткие сегменты, применяет FDAF к каждому сегменту, а затем объединяет промежуточные результаты. Размер кадра в этом случае должен быть кратен длине раздела (блока), тем самым значительно уменьшая задержку для длинных импульсных откликов.

% Reduce the frame size from 2048 to 256
frameSize = 256;
nearSpeechSrc.SamplesPerFrame    = frameSize;
farSpeechSrc.SamplesPerFrame     = frameSize;
farSpeechEchoSrc.SamplesPerFrame = frameSize;
micSrc.SamplesPerFrame           = frameSize;
% Switch the echo canceller to Partitioned constrained FDAF
echoCanceller.Method      = 'Partitioned constrained FDAF';
% Set the block length to frameSize
echoCanceller.BlockLength = frameSize;

% Stream processing loop
while(~isDone(nearSpeechSrc))
    nearSpeech = nearSpeechSrc();
    farSpeech = farSpeechSrc();
    farSpeechEcho = farSpeechEchoSrc();
    micSignal = micSrc();
    % Apply FDAF
    [y,e] = echoCanceller(farSpeech, micSignal);
    % Send the speech samples to the output audio device
    player(e);
    % Compute ERLE
    erle = diffAverager((e-nearSpeech).^2)./ farEchoAverager(farSpeechEcho.^2);
    erledB = -10*log10(erle);
    % Plot near-end, far-end, microphone, AEC output and ERLE
    AECScope2(nearSpeech, micSignal, e, erledB);
end