Updated the behavior for the filter adaptation in echo canceller 3
This CL adjusts the filter adaptation behavior to better handle reverberant environments and environments with poor SNR. It furthermore updates the unittests to handle the reduced adaptation speed. Bug: webrtc:8661 Change-Id: I5f1b5a4a34b333bd6c643ed3727899d0838dbf90 Reviewed-on: https://webrtc-review.googlesource.com/34184 Reviewed-by: Gustaf Ullberg <gustaf@webrtc.org> Commit-Queue: Per Åhgren <peah@webrtc.org> Cr-Commit-Position: refs/heads/master@{#21323}
This commit is contained in:
@ -306,7 +306,7 @@ TEST(AdaptiveFirFilter, FilterSize) {
|
|||||||
// Verifies that the filter is being able to properly filter a signal and to
|
// Verifies that the filter is being able to properly filter a signal and to
|
||||||
// adapt its coefficients.
|
// adapt its coefficients.
|
||||||
TEST(AdaptiveFirFilter, FilterAndAdapt) {
|
TEST(AdaptiveFirFilter, FilterAndAdapt) {
|
||||||
constexpr size_t kNumBlocksToProcess = 500;
|
constexpr size_t kNumBlocksToProcess = 1000;
|
||||||
ApmDataDumper data_dumper(42);
|
ApmDataDumper data_dumper(42);
|
||||||
EchoCanceller3Config config;
|
EchoCanceller3Config config;
|
||||||
AdaptiveFirFilter filter(config.filter.length_blocks, DetectOptimization(),
|
AdaptiveFirFilter filter(config.filter.length_blocks, DetectOptimization(),
|
||||||
|
@ -220,8 +220,14 @@ TEST(MainFilterUpdateGain, GainCausesFilterToConverge) {
|
|||||||
false, &e, &y, &G);
|
false, &e, &y, &G);
|
||||||
|
|
||||||
// Verify that the main filter is able to perform well.
|
// Verify that the main filter is able to perform well.
|
||||||
EXPECT_LT(1000 * std::inner_product(e.begin(), e.end(), e.begin(), 0.f),
|
// Use different criteria to take overmodelling into account.
|
||||||
std::inner_product(y.begin(), y.end(), y.begin(), 0.f));
|
if (filter_length_blocks == 12) {
|
||||||
|
EXPECT_LT(1000 * std::inner_product(e.begin(), e.end(), e.begin(), 0.f),
|
||||||
|
std::inner_product(y.begin(), y.end(), y.begin(), 0.f));
|
||||||
|
} else {
|
||||||
|
EXPECT_LT(std::inner_product(e.begin(), e.end(), e.begin(), 0.f),
|
||||||
|
std::inner_product(y.begin(), y.end(), y.begin(), 0.f));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -229,8 +235,6 @@ TEST(MainFilterUpdateGain, GainCausesFilterToConverge) {
|
|||||||
// Verifies that the magnitude of the gain on average decreases for a
|
// Verifies that the magnitude of the gain on average decreases for a
|
||||||
// persistently exciting signal.
|
// persistently exciting signal.
|
||||||
TEST(MainFilterUpdateGain, DecreasingGain) {
|
TEST(MainFilterUpdateGain, DecreasingGain) {
|
||||||
for (size_t filter_length_blocks : {12, 20, 30}) {
|
|
||||||
SCOPED_TRACE(ProduceDebugText(filter_length_blocks));
|
|
||||||
std::vector<int> blocks_with_echo_path_changes;
|
std::vector<int> blocks_with_echo_path_changes;
|
||||||
std::vector<int> blocks_with_saturation;
|
std::vector<int> blocks_with_saturation;
|
||||||
|
|
||||||
@ -243,15 +247,12 @@ TEST(MainFilterUpdateGain, DecreasingGain) {
|
|||||||
std::array<float, kFftLengthBy2Plus1> G_b_power;
|
std::array<float, kFftLengthBy2Plus1> G_b_power;
|
||||||
std::array<float, kFftLengthBy2Plus1> G_c_power;
|
std::array<float, kFftLengthBy2Plus1> G_c_power;
|
||||||
|
|
||||||
RunFilterUpdateTest(100, 65, filter_length_blocks,
|
RunFilterUpdateTest(100, 65, 12, blocks_with_echo_path_changes,
|
||||||
blocks_with_echo_path_changes, blocks_with_saturation,
|
blocks_with_saturation, false, &e, &y, &G_a);
|
||||||
false, &e, &y, &G_a);
|
RunFilterUpdateTest(300, 65, 12, blocks_with_echo_path_changes,
|
||||||
RunFilterUpdateTest(300, 65, filter_length_blocks,
|
blocks_with_saturation, false, &e, &y, &G_b);
|
||||||
blocks_with_echo_path_changes, blocks_with_saturation,
|
RunFilterUpdateTest(600, 65, 12, blocks_with_echo_path_changes,
|
||||||
false, &e, &y, &G_b);
|
blocks_with_saturation, false, &e, &y, &G_c);
|
||||||
RunFilterUpdateTest(600, 65, filter_length_blocks,
|
|
||||||
blocks_with_echo_path_changes, blocks_with_saturation,
|
|
||||||
false, &e, &y, &G_c);
|
|
||||||
|
|
||||||
G_a.Spectrum(Aec3Optimization::kNone, G_a_power);
|
G_a.Spectrum(Aec3Optimization::kNone, G_a_power);
|
||||||
G_b.Spectrum(Aec3Optimization::kNone, G_b_power);
|
G_b.Spectrum(Aec3Optimization::kNone, G_b_power);
|
||||||
@ -262,7 +263,6 @@ TEST(MainFilterUpdateGain, DecreasingGain) {
|
|||||||
|
|
||||||
EXPECT_GT(std::accumulate(G_b_power.begin(), G_b_power.end(), 0.),
|
EXPECT_GT(std::accumulate(G_b_power.begin(), G_b_power.end(), 0.),
|
||||||
std::accumulate(G_c_power.begin(), G_c_power.end(), 0.));
|
std::accumulate(G_c_power.begin(), G_c_power.end(), 0.));
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Verifies that the gain is zero when there is saturation and that the internal
|
// Verifies that the gain is zero when there is saturation and that the internal
|
||||||
|
@ -157,8 +157,14 @@ TEST(ShadowFilterUpdateGain, GainCausesFilterToConverge) {
|
|||||||
blocks_with_saturation, &e, &y, &G);
|
blocks_with_saturation, &e, &y, &G);
|
||||||
|
|
||||||
// Verify that the main filter is able to perform well.
|
// Verify that the main filter is able to perform well.
|
||||||
EXPECT_LT(1000 * std::inner_product(e.begin(), e.end(), e.begin(), 0.f),
|
// Use different criteria to take overmodelling into account.
|
||||||
std::inner_product(y.begin(), y.end(), y.begin(), 0.f));
|
if (filter_length_blocks == 12) {
|
||||||
|
EXPECT_LT(1000 * std::inner_product(e.begin(), e.end(), e.begin(), 0.f),
|
||||||
|
std::inner_product(y.begin(), y.end(), y.begin(), 0.f));
|
||||||
|
} else {
|
||||||
|
EXPECT_LT(std::inner_product(e.begin(), e.end(), e.begin(), 0.f),
|
||||||
|
std::inner_product(y.begin(), y.end(), y.begin(), 0.f));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -164,7 +164,13 @@ TEST(Subtractor, Convergence) {
|
|||||||
float echo_to_nearend_power =
|
float echo_to_nearend_power =
|
||||||
RunSubtractorTest(300, delay_samples, filter_length_blocks, false,
|
RunSubtractorTest(300, delay_samples, filter_length_blocks, false,
|
||||||
blocks_with_echo_path_changes);
|
blocks_with_echo_path_changes);
|
||||||
EXPECT_GT(0.1f, echo_to_nearend_power);
|
|
||||||
|
// Use different criteria to take overmodelling into account.
|
||||||
|
if (filter_length_blocks == 12) {
|
||||||
|
EXPECT_GT(0.1f, echo_to_nearend_power);
|
||||||
|
} else {
|
||||||
|
EXPECT_GT(1.f, echo_to_nearend_power);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -177,9 +183,9 @@ TEST(Subtractor, NonConvergenceOnUncorrelatedSignals) {
|
|||||||
SCOPED_TRACE(ProduceDebugText(delay_samples, filter_length_blocks));
|
SCOPED_TRACE(ProduceDebugText(delay_samples, filter_length_blocks));
|
||||||
|
|
||||||
float echo_to_nearend_power =
|
float echo_to_nearend_power =
|
||||||
RunSubtractorTest(100, delay_samples, filter_length_blocks, true,
|
RunSubtractorTest(300, delay_samples, filter_length_blocks, true,
|
||||||
blocks_with_echo_path_changes);
|
blocks_with_echo_path_changes);
|
||||||
EXPECT_NEAR(1.f, echo_to_nearend_power, 0.05);
|
EXPECT_NEAR(1.f, echo_to_nearend_power, 0.1);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1162,12 +1162,12 @@ struct EchoCanceller3Config {
|
|||||||
|
|
||||||
struct Filter {
|
struct Filter {
|
||||||
size_t length_blocks = 12;
|
size_t length_blocks = 12;
|
||||||
float shadow_rate = 0.5f;
|
float shadow_rate = 0.1f;
|
||||||
float leakage_converged = 0.01f;
|
float leakage_converged = 0.005f;
|
||||||
float leakage_diverged = 1.f / 60.f;
|
float leakage_diverged = 0.05f;
|
||||||
float error_floor = 0.1f;
|
float error_floor = 0.001f;
|
||||||
float main_noise_gate = 220075344.f;
|
float main_noise_gate = 20075344.f;
|
||||||
float shadow_noise_gate = 220075344.f;
|
float shadow_noise_gate = 20075344.f;
|
||||||
} filter;
|
} filter;
|
||||||
|
|
||||||
struct Erle {
|
struct Erle {
|
||||||
|
Reference in New Issue
Block a user