Added support in the AEC for refined filter adaptation.
The following algorithmic functionality was added: -Add support for an exact regressor power to be computed which avoids the issue with the updating of the filter sometimes being unstable. -Lowered the fixed step size of the adaptive filter to 0.05 which significantly reduces the sensitivity of the adaptive filter to near-end noise, nonlinearities, doubletalk and the unmodelled echo path tail. It also reduces the tracking speed of the adaptive filter but the chosen value proved to give a sufficient tradeoff for the requirements on the adaptive filter. To allow the new functionality to be selectively applied the following was done: -A new Config was added for selectively activating the functionality. -Functionality was added in the audioprocessing and echocancellationimpl classes for passing the activation of the functionality down to the AEC algorithms. To make the code for the introduction of the functionality clean, the following refactoring was done: -The selection of the step size was moved to a single place. -The constant for the step size of the adaptive filter in extended filter mode was made local. -The state variable storing the step-size was renamed to a more describing name. When the new functionality is not activated, the changes have been tested for bitexactness on Linux. TBR=minyue@webrtc.org BUG=webrtc:5778, webrtc:5777 Review URL: https://codereview.webrtc.org/1887003002 Cr-Commit-Position: refs/heads/master@{#12384}
This commit is contained in:
@ -25,6 +25,7 @@
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "webrtc/base/checks.h"
|
||||
extern "C" {
|
||||
#include "webrtc/common_audio/ring_buffer.h"
|
||||
}
|
||||
@ -238,15 +239,10 @@ static void FilterFar(int num_partitions,
|
||||
}
|
||||
}
|
||||
|
||||
static void ScaleErrorSignal(int extended_filter_enabled,
|
||||
float normal_mu,
|
||||
float normal_error_threshold,
|
||||
static void ScaleErrorSignal(float mu,
|
||||
float error_threshold,
|
||||
float x_pow[PART_LEN1],
|
||||
float ef[2][PART_LEN1]) {
|
||||
const float mu = extended_filter_enabled ? kExtendedMu : normal_mu;
|
||||
const float error_threshold = extended_filter_enabled
|
||||
? kExtendedErrorThreshold
|
||||
: normal_error_threshold;
|
||||
int i;
|
||||
float abs_ef;
|
||||
for (i = 0; i < (PART_LEN1); i++) {
|
||||
@ -936,11 +932,38 @@ static int SignalBasedDelayCorrection(AecCore* self) {
|
||||
return delay_correction;
|
||||
}
|
||||
|
||||
static void RegressorPower(int num_partitions,
|
||||
int latest_added_partition,
|
||||
float x_fft_buf[2]
|
||||
[kExtendedNumPartitions * PART_LEN1],
|
||||
float x_pow[PART_LEN1]) {
|
||||
RTC_DCHECK_LT(latest_added_partition, num_partitions);
|
||||
memset(x_pow, 0, PART_LEN1 * sizeof(x_pow[0]));
|
||||
|
||||
int partition = latest_added_partition;
|
||||
int x_fft_buf_position = partition * PART_LEN1;
|
||||
for (int i = 0; i < num_partitions; ++i) {
|
||||
for (int bin = 0; bin < PART_LEN1; ++bin) {
|
||||
float re = x_fft_buf[0][x_fft_buf_position];
|
||||
float im = x_fft_buf[1][x_fft_buf_position];
|
||||
x_pow[bin] += re * re + im * im;
|
||||
++x_fft_buf_position;
|
||||
}
|
||||
|
||||
++partition;
|
||||
if (partition == num_partitions) {
|
||||
partition = 0;
|
||||
RTC_DCHECK_EQ(num_partitions * PART_LEN1, x_fft_buf_position);
|
||||
x_fft_buf_position = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void EchoSubtraction(AecCore* aec,
|
||||
int num_partitions,
|
||||
int extended_filter_enabled,
|
||||
float normal_mu,
|
||||
float normal_error_threshold,
|
||||
float filter_step_size,
|
||||
float error_threshold,
|
||||
float* x_fft,
|
||||
int* x_fft_buf_block_pos,
|
||||
float x_fft_buf[2]
|
||||
@ -1001,8 +1024,7 @@ static void EchoSubtraction(AecCore* aec,
|
||||
sizeof(e_fft[0][0]) * PART_LEN1 * 2);
|
||||
|
||||
// Scale error signal inversely with far power.
|
||||
WebRtcAec_ScaleErrorSignal(extended_filter_enabled, normal_mu,
|
||||
normal_error_threshold, x_pow, e_fft);
|
||||
WebRtcAec_ScaleErrorSignal(filter_step_size, error_threshold, x_pow, e_fft);
|
||||
WebRtcAec_FilterAdaptation(num_partitions, *x_fft_buf_block_pos, x_fft_buf,
|
||||
e_fft, h_fft_buf);
|
||||
memcpy(echo_subtractor_output, e, sizeof(float) * PART_LEN);
|
||||
@ -1315,18 +1337,31 @@ static void ProcessBlock(AecCore* aec) {
|
||||
memcpy(fft, aec->dBuf, sizeof(float) * PART_LEN2);
|
||||
Fft(fft, df);
|
||||
|
||||
// Power smoothing
|
||||
for (i = 0; i < PART_LEN1; i++) {
|
||||
far_spectrum = (x_fft_ptr[i] * x_fft_ptr[i]) +
|
||||
(x_fft_ptr[PART_LEN1 + i] * x_fft_ptr[PART_LEN1 + i]);
|
||||
aec->xPow[i] =
|
||||
gPow[0] * aec->xPow[i] + gPow[1] * aec->num_partitions * far_spectrum;
|
||||
// Calculate absolute spectra
|
||||
abs_far_spectrum[i] = sqrtf(far_spectrum);
|
||||
// Power smoothing.
|
||||
if (aec->refined_adaptive_filter_enabled) {
|
||||
for (i = 0; i < PART_LEN1; ++i) {
|
||||
far_spectrum = (x_fft_ptr[i] * x_fft_ptr[i]) +
|
||||
(x_fft_ptr[PART_LEN1 + i] * x_fft_ptr[PART_LEN1 + i]);
|
||||
// Calculate the magnitude spectrum.
|
||||
abs_far_spectrum[i] = sqrtf(far_spectrum);
|
||||
}
|
||||
RegressorPower(aec->num_partitions, aec->xfBufBlockPos, aec->xfBuf,
|
||||
aec->xPow);
|
||||
} else {
|
||||
for (i = 0; i < PART_LEN1; ++i) {
|
||||
far_spectrum = (x_fft_ptr[i] * x_fft_ptr[i]) +
|
||||
(x_fft_ptr[PART_LEN1 + i] * x_fft_ptr[PART_LEN1 + i]);
|
||||
aec->xPow[i] =
|
||||
gPow[0] * aec->xPow[i] + gPow[1] * aec->num_partitions * far_spectrum;
|
||||
// Calculate the magnitude spectrum.
|
||||
abs_far_spectrum[i] = sqrtf(far_spectrum);
|
||||
}
|
||||
}
|
||||
|
||||
for (i = 0; i < PART_LEN1; ++i) {
|
||||
near_spectrum = df[0][i] * df[0][i] + df[1][i] * df[1][i];
|
||||
aec->dPow[i] = gPow[0] * aec->dPow[i] + gPow[1] * near_spectrum;
|
||||
// Calculate absolute spectra
|
||||
// Calculate the magnitude spectrum.
|
||||
abs_near_spectrum[i] = sqrtf(near_spectrum);
|
||||
}
|
||||
|
||||
@ -1379,7 +1414,7 @@ static void ProcessBlock(AecCore* aec) {
|
||||
|
||||
// Perform echo subtraction.
|
||||
EchoSubtraction(aec, aec->num_partitions, aec->extended_filter_enabled,
|
||||
aec->normal_mu, aec->normal_error_threshold, &x_fft[0][0],
|
||||
aec->filter_step_size, aec->error_threshold, &x_fft[0][0],
|
||||
&aec->xfBufBlockPos, aec->xfBuf, nearend_ptr, aec->xPow,
|
||||
aec->wfBuf, echo_subtractor_output);
|
||||
|
||||
@ -1485,6 +1520,7 @@ AecCore* WebRtcAec_CreateAec() {
|
||||
#endif
|
||||
aec->extended_filter_enabled = 0;
|
||||
aec->aec3_enabled = 0;
|
||||
aec->refined_adaptive_filter_enabled = false;
|
||||
|
||||
// Assembly optimization
|
||||
WebRtcAec_FilterFar = FilterFar;
|
||||
@ -1548,18 +1584,53 @@ void WebRtcAec_FreeAec(AecCore* aec) {
|
||||
delete aec;
|
||||
}
|
||||
|
||||
static void SetAdaptiveFilterStepSize(AecCore* aec) {
|
||||
// Extended filter adaptation parameter.
|
||||
// TODO(ajm): No narrowband tuning yet.
|
||||
const float kExtendedMu = 0.4f;
|
||||
|
||||
if (aec->refined_adaptive_filter_enabled) {
|
||||
aec->filter_step_size = 0.05f;
|
||||
} else {
|
||||
if (aec->extended_filter_enabled) {
|
||||
aec->filter_step_size = kExtendedMu;
|
||||
} else {
|
||||
if (aec->sampFreq == 8000) {
|
||||
aec->filter_step_size = 0.6f;
|
||||
} else {
|
||||
aec->filter_step_size = 0.5f;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void SetErrorThreshold(AecCore* aec) {
|
||||
// Extended filter adaptation parameter.
|
||||
// TODO(ajm): No narrowband tuning yet.
|
||||
static const float kExtendedErrorThreshold = 1.0e-6f;
|
||||
|
||||
if (aec->extended_filter_enabled) {
|
||||
aec->error_threshold = kExtendedErrorThreshold;
|
||||
} else {
|
||||
if (aec->sampFreq == 8000) {
|
||||
aec->error_threshold = 2e-6f;
|
||||
} else {
|
||||
aec->error_threshold = 1.5e-6f;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
int WebRtcAec_InitAec(AecCore* aec, int sampFreq) {
|
||||
int i;
|
||||
|
||||
aec->sampFreq = sampFreq;
|
||||
|
||||
SetAdaptiveFilterStepSize(aec);
|
||||
SetErrorThreshold(aec);
|
||||
|
||||
if (sampFreq == 8000) {
|
||||
aec->normal_mu = 0.6f;
|
||||
aec->normal_error_threshold = 2e-6f;
|
||||
aec->num_bands = 1;
|
||||
} else {
|
||||
aec->normal_mu = 0.5f;
|
||||
aec->normal_error_threshold = 1.5e-6f;
|
||||
aec->num_bands = (size_t)(sampFreq / 16000);
|
||||
}
|
||||
|
||||
@ -1930,9 +2001,20 @@ int WebRtcAec_aec3_enabled(AecCore* self) {
|
||||
return self->aec3_enabled;
|
||||
}
|
||||
|
||||
void WebRtcAec_enable_refined_adaptive_filter(AecCore* self, bool enable) {
|
||||
self->refined_adaptive_filter_enabled = enable;
|
||||
SetAdaptiveFilterStepSize(self);
|
||||
SetErrorThreshold(self);
|
||||
}
|
||||
|
||||
bool WebRtcAec_refined_adaptive_filter_enabled(const AecCore* self) {
|
||||
return self->refined_adaptive_filter_enabled;
|
||||
}
|
||||
|
||||
void WebRtcAec_enable_extended_filter(AecCore* self, int enable) {
|
||||
self->extended_filter_enabled = enable;
|
||||
SetAdaptiveFilterStepSize(self);
|
||||
SetErrorThreshold(self);
|
||||
self->num_partitions = enable ? kExtendedNumPartitions : kNormalNumPartitions;
|
||||
// Update the delay estimator with filter length. See InitAEC() for details.
|
||||
WebRtc_set_allowed_offset(self->delay_estimator, self->num_partitions / 2);
|
||||
|
||||
@ -120,6 +120,12 @@ void WebRtcAec_enable_aec3(AecCore* self, int enable);
|
||||
// Returns 1 if the next generation aec is enabled and zero if disabled.
|
||||
int WebRtcAec_aec3_enabled(AecCore* self);
|
||||
|
||||
// Turns on/off the refined adaptive filter feature.
|
||||
void WebRtcAec_enable_refined_adaptive_filter(AecCore* self, bool enable);
|
||||
|
||||
// Returns whether the refined adaptive filter is enabled.
|
||||
bool WebRtcAec_refined_adaptive_filter(const AecCore* self);
|
||||
|
||||
// Enables or disables extended filter mode. Non-zero enables, zero disables.
|
||||
void WebRtcAec_enable_extended_filter(AecCore* self, int enable);
|
||||
|
||||
|
||||
@ -35,11 +35,6 @@ enum {
|
||||
kHistorySizeBlocks = 125
|
||||
};
|
||||
|
||||
// Extended filter adaptation parameters.
|
||||
// TODO(ajm): No narrowband tuning yet.
|
||||
static const float kExtendedMu = 0.4f;
|
||||
static const float kExtendedErrorThreshold = 1.0e-6f;
|
||||
|
||||
typedef struct PowerLevel {
|
||||
PowerLevel();
|
||||
|
||||
@ -126,12 +121,12 @@ struct AecCore {
|
||||
int system_delay; // Current system delay buffered in AEC.
|
||||
|
||||
int mult; // sampling frequency multiple
|
||||
int sampFreq;
|
||||
int sampFreq = 16000;
|
||||
size_t num_bands;
|
||||
uint32_t seed;
|
||||
|
||||
float normal_mu; // stepsize
|
||||
float normal_error_threshold; // error threshold
|
||||
float filter_step_size; // stepsize
|
||||
float error_threshold; // error threshold
|
||||
|
||||
int noiseEstCtr;
|
||||
|
||||
@ -178,6 +173,7 @@ struct AecCore {
|
||||
int extended_filter_enabled;
|
||||
// 1 = next generation aec mode enabled, 0 = disabled.
|
||||
int aec3_enabled;
|
||||
bool refined_adaptive_filter_enabled;
|
||||
|
||||
// Runtime selection of number of filter partitions.
|
||||
int num_partitions;
|
||||
@ -210,9 +206,8 @@ typedef void (*WebRtcAecFilterFar)(
|
||||
float h_fft_buf[2][kExtendedNumPartitions * PART_LEN1],
|
||||
float y_fft[2][PART_LEN1]);
|
||||
extern WebRtcAecFilterFar WebRtcAec_FilterFar;
|
||||
typedef void (*WebRtcAecScaleErrorSignal)(int extended_filter_enabled,
|
||||
float normal_mu,
|
||||
float normal_error_threshold,
|
||||
typedef void (*WebRtcAecScaleErrorSignal)(float mu,
|
||||
float error_threshold,
|
||||
float x_pow[PART_LEN1],
|
||||
float ef[2][PART_LEN1]);
|
||||
extern WebRtcAecScaleErrorSignal WebRtcAec_ScaleErrorSignal;
|
||||
|
||||
@ -707,15 +707,10 @@ void WebRtcAec_OverdriveAndSuppress_mips(AecCore* aec,
|
||||
}
|
||||
}
|
||||
|
||||
void WebRtcAec_ScaleErrorSignal_mips(int extended_filter_enabled,
|
||||
float normal_mu,
|
||||
float normal_error_threshold,
|
||||
void WebRtcAec_ScaleErrorSignal_mips(float mu,
|
||||
float error_threshold,
|
||||
float x_pow[PART_LEN1],
|
||||
float ef[2][PART_LEN1]) {
|
||||
const float mu = extended_filter_enabled ? kExtendedMu : normal_mu;
|
||||
const float error_threshold = extended_filter_enabled
|
||||
? kExtendedErrorThreshold
|
||||
: normal_error_threshold;
|
||||
int len = (PART_LEN1);
|
||||
float* ef0 = ef[0];
|
||||
float* ef1 = ef[1];
|
||||
|
||||
@ -127,15 +127,10 @@ static float32x4_t vsqrtq_f32(float32x4_t s) {
|
||||
}
|
||||
#endif // WEBRTC_ARCH_ARM64
|
||||
|
||||
static void ScaleErrorSignalNEON(int extended_filter_enabled,
|
||||
float normal_mu,
|
||||
float normal_error_threshold,
|
||||
static void ScaleErrorSignalNEON(float mu,
|
||||
float error_threshold,
|
||||
float x_pow[PART_LEN1],
|
||||
float ef[2][PART_LEN1]) {
|
||||
const float mu = extended_filter_enabled ? kExtendedMu : normal_mu;
|
||||
const float error_threshold = extended_filter_enabled
|
||||
? kExtendedErrorThreshold
|
||||
: normal_error_threshold;
|
||||
const float32x4_t k1e_10f = vdupq_n_f32(1e-10f);
|
||||
const float32x4_t kMu = vmovq_n_f32(mu);
|
||||
const float32x4_t kThresh = vmovq_n_f32(error_threshold);
|
||||
|
||||
@ -79,17 +79,13 @@ static void FilterFarSSE2(int num_partitions,
|
||||
}
|
||||
}
|
||||
|
||||
static void ScaleErrorSignalSSE2(int extended_filter_enabled,
|
||||
float normal_mu,
|
||||
float normal_error_threshold,
|
||||
static void ScaleErrorSignalSSE2(float mu,
|
||||
float error_threshold,
|
||||
float x_pow[PART_LEN1],
|
||||
float ef[2][PART_LEN1]) {
|
||||
const __m128 k1e_10f = _mm_set1_ps(1e-10f);
|
||||
const __m128 kMu = extended_filter_enabled ? _mm_set1_ps(kExtendedMu)
|
||||
: _mm_set1_ps(normal_mu);
|
||||
const __m128 kThresh = extended_filter_enabled
|
||||
? _mm_set1_ps(kExtendedErrorThreshold)
|
||||
: _mm_set1_ps(normal_error_threshold);
|
||||
const __m128 kMu = _mm_set1_ps(mu);
|
||||
const __m128 kThresh = _mm_set1_ps(error_threshold);
|
||||
|
||||
int i;
|
||||
// vectorized code (four at once)
|
||||
@ -124,10 +120,6 @@ static void ScaleErrorSignalSSE2(int extended_filter_enabled,
|
||||
}
|
||||
// scalar code for the remaining items.
|
||||
{
|
||||
const float mu = extended_filter_enabled ? kExtendedMu : normal_mu;
|
||||
const float error_threshold = extended_filter_enabled
|
||||
? kExtendedErrorThreshold
|
||||
: normal_error_threshold;
|
||||
for (; i < (PART_LEN1); i++) {
|
||||
float abs_ef;
|
||||
ef[0][i] /= (x_pow[i] + 1e-10f);
|
||||
|
||||
Reference in New Issue
Block a user