В этом примере показано, как применить адаптивные фильтры к акустической отмене эха (AEC).
Автор (авторы): Скотт К. Дуглас
Акустическая отмена эха важна для аудио организации телеконференций, когда одновременная коммуникация (или полнодуплексная передача) речи необходима. В акустической отмене эха измеренный сигнал микрофона содержит два сигнала:
Речевой сигнал почти конца
Дальний конец повторил речевой сигнал
Цель состоит в том, чтобы удалить отраженный речевой сигнал дальнего конца из сигнала микрофона так, чтобы только речевой сигнал почти конца был передан. Этот пример имеет некоторые файлы звукозаписи, таким образом, вы можете хотеть отрегулировать громкость своего компьютера теперь.
Сначала необходимо смоделировать акустику пути прохождения сигнала громкоговорителя к микрофону, где спикерфон расположен. Используйте длинный конечный фильтр импульсной характеристики, чтобы описать характеристики комнаты. Следующий код генерирует случайную импульсную характеристику, которая мало чем отличается от того, что показал бы конференц-зал. Примите системную частоту дискретизации 16 000 Гц.
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 использует быстрый метод свертки, чтобы вычислить обновления фильтра и выходной сигнал. Этот расчет выполняется быстро в 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 дБ в конце периода сходимости.
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);
Чтобы получить более быструю сходимость, можно попытаться использовать большее значение размера шага. Однако это увеличение вызывает другой эффект: адаптивный фильтр является "misadjusted", в то время как докладчик почти конца говорит. Слушайте то, что происходит, когда вы выбираете размер шага, который на 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