Separated the AEC3 adaptive filter parameters into sub-structs
Bug: webrtc:8671 Change-Id: I02bceceb85da6db65f65c1a2366a2d5021f148ef Reviewed-on: https://webrtc-review.googlesource.com/39502 Reviewed-by: Gustaf Ullberg <gustaf@webrtc.org> Commit-Queue: Per Åhgren <peah@webrtc.org> Cr-Commit-Position: refs/heads/master@{#21617}
This commit is contained in:
@ -307,15 +307,15 @@ TEST(AdaptiveFirFilter, FilterAndAdapt) {
|
||||
constexpr size_t kNumBlocksToProcess = 1000;
|
||||
ApmDataDumper data_dumper(42);
|
||||
EchoCanceller3Config config;
|
||||
AdaptiveFirFilter filter(config.filter.length_blocks, DetectOptimization(),
|
||||
&data_dumper);
|
||||
AdaptiveFirFilter filter(config.filter.main.length_blocks,
|
||||
DetectOptimization(), &data_dumper);
|
||||
Aec3Fft fft;
|
||||
config.delay.min_echo_path_delay_blocks = 0;
|
||||
config.delay.default_delay = 1;
|
||||
std::unique_ptr<RenderDelayBuffer> render_delay_buffer(
|
||||
RenderDelayBuffer::Create(config, 3));
|
||||
ShadowFilterUpdateGain gain(config.filter.shadow_rate,
|
||||
config.filter.shadow_noise_gate);
|
||||
ShadowFilterUpdateGain gain(config.filter.shadow.rate,
|
||||
config.filter.shadow.noise_gate);
|
||||
Random random_generator(42U);
|
||||
std::vector<std::vector<float>> x(3, std::vector<float>(kBlockSize, 0.f));
|
||||
std::vector<float> n(kBlockSize, 0.f);
|
||||
|
@ -56,7 +56,7 @@ AecState::AecState(const EchoCanceller3Config& config)
|
||||
new ApmDataDumper(rtc::AtomicOps::Increment(&instance_count_))),
|
||||
erle_estimator_(config.erle.min, config.erle.max_l, config.erle.max_h),
|
||||
config_(config),
|
||||
max_render_(config_.filter.length_blocks, 0.f),
|
||||
max_render_(config_.filter.main.length_blocks, 0.f),
|
||||
reverb_decay_(config_.ep_strength.default_len) {}
|
||||
|
||||
AecState::~AecState() = default;
|
||||
@ -175,7 +175,8 @@ void AecState::Update(
|
||||
|
||||
void AecState::UpdateReverb(const std::vector<float>& impulse_response) {
|
||||
if ((!(filter_delay_ && usable_linear_estimate_)) ||
|
||||
(filter_delay_ > static_cast<int>(config_.filter.length_blocks) - 4)) {
|
||||
(filter_delay_ >
|
||||
static_cast<int>(config_.filter.main.length_blocks) - 4)) {
|
||||
return;
|
||||
}
|
||||
|
||||
@ -183,11 +184,11 @@ void AecState::UpdateReverb(const std::vector<float>& impulse_response) {
|
||||
// coefficients.
|
||||
std::array<float, GetTimeDomainLength(kMaxAdaptiveFilterLength)>
|
||||
matching_data_data;
|
||||
RTC_DCHECK_LE(GetTimeDomainLength(config_.filter.length_blocks),
|
||||
RTC_DCHECK_LE(GetTimeDomainLength(config_.filter.main.length_blocks),
|
||||
matching_data_data.size());
|
||||
rtc::ArrayView<float> matching_data(
|
||||
matching_data_data.data(),
|
||||
GetTimeDomainLength(config_.filter.length_blocks));
|
||||
GetTimeDomainLength(config_.filter.main.length_blocks));
|
||||
std::transform(impulse_response.begin(), impulse_response.end(),
|
||||
matching_data.begin(), [](float a) { return a * a; });
|
||||
|
||||
@ -195,7 +196,7 @@ void AecState::UpdateReverb(const std::vector<float>& impulse_response) {
|
||||
// model noise power.
|
||||
constexpr size_t kTailLength = 64;
|
||||
const size_t tail_index =
|
||||
GetTimeDomainLength(config_.filter.length_blocks) - kTailLength;
|
||||
GetTimeDomainLength(config_.filter.main.length_blocks) - kTailLength;
|
||||
const float tail_power = *std::max_element(matching_data.begin() + tail_index,
|
||||
matching_data.end());
|
||||
std::for_each(matching_data.begin(), matching_data.begin() + tail_index,
|
||||
|
@ -44,7 +44,7 @@ TEST(AecState, NormalUsage) {
|
||||
converged_filter_frequency_response[2][0] = 1.f;
|
||||
|
||||
std::vector<float> impulse_response(
|
||||
GetTimeDomainLength(config.filter.length_blocks), 0.f);
|
||||
GetTimeDomainLength(config.filter.main.length_blocks), 0.f);
|
||||
|
||||
// Verify that linear AEC usability is false when the filter is diverged.
|
||||
state.Update(diverged_filter_frequency_response, impulse_response, true,
|
||||
@ -190,7 +190,7 @@ TEST(AecState, ConvergedFilterDelay) {
|
||||
kFilterLength);
|
||||
|
||||
std::vector<float> impulse_response(
|
||||
GetTimeDomainLength(config.filter.length_blocks), 0.f);
|
||||
GetTimeDomainLength(config.filter.main.length_blocks), 0.f);
|
||||
|
||||
// Verify that the filter delay for a converged filter is properly identified.
|
||||
for (int k = 0; k < kFilterLength; ++k) {
|
||||
|
@ -42,19 +42,20 @@ void RunFilterUpdateTest(int num_blocks_to_process,
|
||||
FftData* G_last_block) {
|
||||
ApmDataDumper data_dumper(42);
|
||||
EchoCanceller3Config config;
|
||||
config.filter.length_blocks = filter_length_blocks;
|
||||
AdaptiveFirFilter main_filter(config.filter.length_blocks,
|
||||
config.filter.main.length_blocks = filter_length_blocks;
|
||||
config.filter.shadow.length_blocks = filter_length_blocks;
|
||||
AdaptiveFirFilter main_filter(config.filter.main.length_blocks,
|
||||
DetectOptimization(), &data_dumper);
|
||||
AdaptiveFirFilter shadow_filter(config.filter.length_blocks,
|
||||
AdaptiveFirFilter shadow_filter(config.filter.shadow.length_blocks,
|
||||
DetectOptimization(), &data_dumper);
|
||||
Aec3Fft fft;
|
||||
std::array<float, kBlockSize> x_old;
|
||||
x_old.fill(0.f);
|
||||
ShadowFilterUpdateGain shadow_gain(config.filter.shadow_rate,
|
||||
config.filter.shadow_noise_gate);
|
||||
ShadowFilterUpdateGain shadow_gain(config.filter.shadow.rate,
|
||||
config.filter.shadow.noise_gate);
|
||||
MainFilterUpdateGain main_gain(
|
||||
config.filter.leakage_converged, config.filter.leakage_diverged,
|
||||
config.filter.main_noise_gate, config.filter.error_floor);
|
||||
config.filter.main.leakage_converged, config.filter.main.leakage_diverged,
|
||||
config.filter.main.noise_gate, config.filter.main.error_floor);
|
||||
Random random_generator(42U);
|
||||
std::vector<std::vector<float>> x(3, std::vector<float>(kBlockSize, 0.f));
|
||||
std::vector<float> y(kBlockSize, 0.f);
|
||||
@ -189,13 +190,13 @@ std::string ProduceDebugText(size_t delay, int filter_length_blocks) {
|
||||
TEST(MainFilterUpdateGain, NullDataOutputGain) {
|
||||
ApmDataDumper data_dumper(42);
|
||||
EchoCanceller3Config config;
|
||||
AdaptiveFirFilter filter(config.filter.length_blocks, DetectOptimization(),
|
||||
&data_dumper);
|
||||
AdaptiveFirFilter filter(config.filter.main.length_blocks,
|
||||
DetectOptimization(), &data_dumper);
|
||||
RenderSignalAnalyzer analyzer;
|
||||
SubtractorOutput output;
|
||||
MainFilterUpdateGain gain(
|
||||
config.filter.leakage_converged, config.filter.leakage_diverged,
|
||||
config.filter.main_noise_gate, config.filter.error_floor);
|
||||
config.filter.main.leakage_converged, config.filter.main.leakage_diverged,
|
||||
config.filter.main.noise_gate, config.filter.main.error_floor);
|
||||
std::array<float, kFftLengthBy2Plus1> render_power;
|
||||
render_power.fill(0.f);
|
||||
EXPECT_DEATH(
|
||||
|
@ -158,7 +158,7 @@ RenderDelayBufferImpl::RenderDelayBufferImpl(const EchoCanceller3Config& config,
|
||||
: kBlockSize)),
|
||||
blocks_(GetRenderDelayBufferSize(config.delay.down_sampling_factor,
|
||||
config.delay.num_filters,
|
||||
config.filter.length_blocks),
|
||||
config.filter.main.length_blocks),
|
||||
num_bands,
|
||||
kBlockSize),
|
||||
spectra_(blocks_.buffer.size(), kFftLengthBy2Plus1),
|
||||
@ -171,7 +171,7 @@ RenderDelayBufferImpl::RenderDelayBufferImpl(const EchoCanceller3Config& config,
|
||||
zero_block_(num_bands, std::vector<float>(kBlockSize, 0.f)),
|
||||
fft_(),
|
||||
render_ds_(sub_block_size_, 0.f),
|
||||
buffer_headroom_(config.filter.length_blocks) {
|
||||
buffer_headroom_(config.filter.main.length_blocks) {
|
||||
RTC_DCHECK_EQ(blocks_.buffer.size(), ffts_.buffer.size());
|
||||
RTC_DCHECK_EQ(spectra_.buffer.size(), ffts_.buffer.size());
|
||||
|
||||
|
@ -77,7 +77,7 @@ void RenderNoisePower(
|
||||
} // namespace
|
||||
|
||||
ResidualEchoEstimator::ResidualEchoEstimator(const EchoCanceller3Config& config)
|
||||
: config_(config), S2_old_(config_.filter.length_blocks) {
|
||||
: config_(config), S2_old_(config_.filter.main.length_blocks) {
|
||||
Reset();
|
||||
}
|
||||
|
||||
@ -131,7 +131,8 @@ void ResidualEchoEstimator::Estimate(
|
||||
if (aec_state.SaturatedEcho()) {
|
||||
// TODO(peah): Modify to make sense theoretically.
|
||||
AddEchoReverb(*R2, aec_state.SaturatedEcho(),
|
||||
config_.filter.length_blocks, aec_state.ReverbDecay(), R2);
|
||||
config_.filter.main.length_blocks, aec_state.ReverbDecay(),
|
||||
R2);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -70,7 +70,8 @@ TEST(ResidualEchoEstimator, DISABLED_BasicTest) {
|
||||
H2[2].fill(10.f);
|
||||
H2[2][0] = 0.1f;
|
||||
|
||||
std::vector<float> h(GetTimeDomainLength(config.filter.length_blocks), 0.f);
|
||||
std::vector<float> h(GetTimeDomainLength(config.filter.main.length_blocks),
|
||||
0.f);
|
||||
|
||||
s.fill(100.f);
|
||||
|
||||
|
@ -38,10 +38,10 @@ void RunFilterUpdateTest(int num_blocks_to_process,
|
||||
FftData* G_last_block) {
|
||||
ApmDataDumper data_dumper(42);
|
||||
EchoCanceller3Config config;
|
||||
config.filter.length_blocks = filter_length_blocks;
|
||||
AdaptiveFirFilter main_filter(config.filter.length_blocks,
|
||||
config.filter.main.length_blocks = filter_length_blocks;
|
||||
AdaptiveFirFilter main_filter(config.filter.main.length_blocks,
|
||||
DetectOptimization(), &data_dumper);
|
||||
AdaptiveFirFilter shadow_filter(config.filter.length_blocks,
|
||||
AdaptiveFirFilter shadow_filter(config.filter.shadow.length_blocks,
|
||||
DetectOptimization(), &data_dumper);
|
||||
Aec3Fft fft;
|
||||
|
||||
@ -52,8 +52,8 @@ void RunFilterUpdateTest(int num_blocks_to_process,
|
||||
|
||||
std::array<float, kBlockSize> x_old;
|
||||
x_old.fill(0.f);
|
||||
ShadowFilterUpdateGain shadow_gain(config.filter.shadow_rate,
|
||||
config.filter.shadow_noise_gate);
|
||||
ShadowFilterUpdateGain shadow_gain(config.filter.shadow.rate,
|
||||
config.filter.shadow.noise_gate);
|
||||
Random random_generator(42U);
|
||||
std::vector<std::vector<float>> x(3, std::vector<float>(kBlockSize, 0.f));
|
||||
std::vector<float> y(kBlockSize, 0.f);
|
||||
|
@ -51,14 +51,22 @@ Subtractor::Subtractor(const EchoCanceller3Config& config,
|
||||
: fft_(),
|
||||
data_dumper_(data_dumper),
|
||||
optimization_(optimization),
|
||||
main_filter_(config.filter.length_blocks, optimization, data_dumper_),
|
||||
shadow_filter_(config.filter.length_blocks, optimization, data_dumper_),
|
||||
G_main_(config.filter.leakage_converged,
|
||||
config.filter.leakage_diverged,
|
||||
config.filter.main_noise_gate,
|
||||
config.filter.error_floor),
|
||||
G_shadow_(config.filter.shadow_rate, config.filter.shadow_noise_gate) {
|
||||
main_filter_(config.filter.main.length_blocks,
|
||||
optimization,
|
||||
data_dumper_),
|
||||
shadow_filter_(config.filter.shadow.length_blocks,
|
||||
optimization,
|
||||
data_dumper_),
|
||||
G_main_(config.filter.main.leakage_converged,
|
||||
config.filter.main.leakage_diverged,
|
||||
config.filter.main.noise_gate,
|
||||
config.filter.main.error_floor),
|
||||
G_shadow_(config.filter.shadow.rate, config.filter.shadow.noise_gate) {
|
||||
RTC_DCHECK(data_dumper_);
|
||||
// Currently, the rest of AEC3 requires the main and shadow filter lengths to
|
||||
// be identical.
|
||||
RTC_DCHECK_EQ(config.filter.main.length_blocks,
|
||||
config.filter.shadow.length_blocks);
|
||||
}
|
||||
|
||||
Subtractor::~Subtractor() = default;
|
||||
|
@ -30,7 +30,8 @@ float RunSubtractorTest(int num_blocks_to_process,
|
||||
const std::vector<int>& blocks_with_echo_path_changes) {
|
||||
ApmDataDumper data_dumper(42);
|
||||
EchoCanceller3Config config;
|
||||
config.filter.length_blocks = filter_length_blocks;
|
||||
config.filter.main.length_blocks = config.filter.shadow.length_blocks =
|
||||
filter_length_blocks;
|
||||
Subtractor subtractor(config, &data_dumper, DetectOptimization());
|
||||
std::vector<std::vector<float>> x(3, std::vector<float>(kBlockSize, 0.f));
|
||||
std::vector<float> y(kBlockSize, 0.f);
|
||||
|
@ -1244,13 +1244,22 @@ struct EchoCanceller3Config {
|
||||
} delay;
|
||||
|
||||
struct Filter {
|
||||
size_t length_blocks = 12;
|
||||
float shadow_rate = 0.1f;
|
||||
float leakage_converged = 0.005f;
|
||||
float leakage_diverged = 0.05f;
|
||||
float error_floor = 0.001f;
|
||||
float main_noise_gate = 20075344.f;
|
||||
float shadow_noise_gate = 20075344.f;
|
||||
struct MainConfiguration {
|
||||
size_t length_blocks;
|
||||
float leakage_converged;
|
||||
float leakage_diverged;
|
||||
float error_floor;
|
||||
float noise_gate;
|
||||
};
|
||||
|
||||
struct ShadowConfiguration {
|
||||
size_t length_blocks;
|
||||
float rate;
|
||||
float noise_gate;
|
||||
};
|
||||
|
||||
MainConfiguration main = {12, 0.005f, 0.05f, 0.001f, 20075344.f};
|
||||
ShadowConfiguration shadow = {12, 0.1f, 20075344.f};
|
||||
} filter;
|
||||
|
||||
struct Erle {
|
||||
|
Reference in New Issue
Block a user