AEC3: Multi channel ERL estimator

The estimator will simply compute the worst value of all combinations
of render and capture signal.

This has the drawback that low-volume or silent render channels may
severely misestimate the ERL.

The changes have been shown to be bitexact over a large dataset.

Bug: webrtc:10913
Change-Id: Id53c3ab81646ac0fab303edafc5e38892d285d8e
Reviewed-on: https://webrtc-review.googlesource.com/c/src/+/157308
Commit-Queue: Sam Zackrisson <saza@webrtc.org>
Reviewed-by: Per Åhgren <peah@webrtc.org>
Cr-Commit-Position: refs/heads/master@{#29542}
This commit is contained in:
Sam Zackrisson
2019-10-18 16:49:13 +02:00
committed by Commit Bot
parent 33ed88287f
commit 6e5433c4d4
5 changed files with 134 additions and 52 deletions

View File

@ -10,11 +10,19 @@
#include "modules/audio_processing/aec3/erl_estimator.h"
#include "rtc_base/strings/string_builder.h"
#include "test/gtest.h"
namespace webrtc {
namespace {
std::string ProduceDebugText(size_t num_render_channels,
size_t num_capture_channels) {
rtc::StringBuilder ss;
ss << "Render channels: " << num_render_channels;
ss << ", Capture channels: " << num_capture_channels;
return ss.Release();
}
void VerifyErl(const std::array<float, kFftLengthBy2Plus1>& erl,
float erl_time_domain,
@ -28,45 +36,65 @@ void VerifyErl(const std::array<float, kFftLengthBy2Plus1>& erl,
// Verifies that the correct ERL estimates are achieved.
TEST(ErlEstimator, Estimates) {
std::array<float, kFftLengthBy2Plus1> X2;
std::array<float, kFftLengthBy2Plus1> Y2;
for (size_t num_render_channels : {1, 2, 8}) {
for (size_t num_capture_channels : {1, 2, 8}) {
SCOPED_TRACE(ProduceDebugText(num_render_channels, num_capture_channels));
std::vector<std::array<float, kFftLengthBy2Plus1>> X2(
num_render_channels);
for (auto& X2_ch : X2) {
X2_ch.fill(0.f);
}
std::vector<std::array<float, kFftLengthBy2Plus1>> Y2(
num_capture_channels);
for (auto& Y2_ch : Y2) {
Y2_ch.fill(0.f);
}
std::vector<bool> converged_filters(num_capture_channels, false);
const size_t converged_idx = num_capture_channels - 1;
converged_filters[converged_idx] = true;
ErlEstimator estimator(0);
ErlEstimator estimator(0);
// Verifies that the ERL estimate is properly reduced to lower values.
X2.fill(500 * 1000.f * 1000.f);
Y2.fill(10 * X2[0]);
for (size_t k = 0; k < 200; ++k) {
estimator.Update(true, X2, Y2);
// Verifies that the ERL estimate is properly reduced to lower values.
for (auto& X2_ch : X2) {
X2_ch.fill(500 * 1000.f * 1000.f);
}
Y2[converged_idx].fill(10 * X2[0][0]);
for (size_t k = 0; k < 200; ++k) {
estimator.Update(converged_filters, X2, Y2);
}
VerifyErl(estimator.Erl(), estimator.ErlTimeDomain(), 10.f);
// Verifies that the ERL is not immediately increased when the ERL in the
// data increases.
Y2[converged_idx].fill(10000 * X2[0][0]);
for (size_t k = 0; k < 998; ++k) {
estimator.Update(converged_filters, X2, Y2);
}
VerifyErl(estimator.Erl(), estimator.ErlTimeDomain(), 10.f);
// Verifies that the rate of increase is 3 dB.
estimator.Update(converged_filters, X2, Y2);
VerifyErl(estimator.Erl(), estimator.ErlTimeDomain(), 20.f);
// Verifies that the maximum ERL is achieved when there are no low RLE
// estimates.
for (size_t k = 0; k < 1000; ++k) {
estimator.Update(converged_filters, X2, Y2);
}
VerifyErl(estimator.Erl(), estimator.ErlTimeDomain(), 1000.f);
// Verifies that the ERL estimate is is not updated for low-level signals
for (auto& X2_ch : X2) {
X2_ch.fill(1000.f * 1000.f);
}
Y2[converged_idx].fill(10 * X2[0][0]);
for (size_t k = 0; k < 200; ++k) {
estimator.Update(converged_filters, X2, Y2);
}
VerifyErl(estimator.Erl(), estimator.ErlTimeDomain(), 1000.f);
}
}
VerifyErl(estimator.Erl(), estimator.ErlTimeDomain(), 10.f);
// Verifies that the ERL is not immediately increased when the ERL in the data
// increases.
Y2.fill(10000 * X2[0]);
for (size_t k = 0; k < 998; ++k) {
estimator.Update(true, X2, Y2);
}
VerifyErl(estimator.Erl(), estimator.ErlTimeDomain(), 10.f);
// Verifies that the rate of increase is 3 dB.
estimator.Update(true, X2, Y2);
VerifyErl(estimator.Erl(), estimator.ErlTimeDomain(), 20.f);
// Verifies that the maximum ERL is achieved when there are no low RLE
// estimates.
for (size_t k = 0; k < 1000; ++k) {
estimator.Update(true, X2, Y2);
}
VerifyErl(estimator.Erl(), estimator.ErlTimeDomain(), 1000.f);
// Verifies that the ERL estimate is is not updated for low-level signals
X2.fill(1000.f * 1000.f);
Y2.fill(10 * X2[0]);
for (size_t k = 0; k < 200; ++k) {
estimator.Update(true, X2, Y2);
}
VerifyErl(estimator.Erl(), estimator.ErlTimeDomain(), 1000.f);
}
} // namespace webrtc