fullband_erle_estimator.cc (6715B)
1 /* 2 * Copyright (c) 2018 The WebRTC project authors. All Rights Reserved. 3 * 4 * Use of this source code is governed by a BSD-style license 5 * that can be found in the LICENSE file in the root of the source 6 * tree. An additional intellectual property rights grant can be found 7 * in the file PATENTS. All contributing project authors may 8 * be found in the AUTHORS file in the root of the source tree. 9 */ 10 11 #include "modules/audio_processing/aec3/fullband_erle_estimator.h" 12 13 #include <algorithm> 14 #include <array> 15 #include <cstddef> 16 #include <memory> 17 #include <numeric> 18 #include <optional> 19 #include <vector> 20 21 #include "api/array_view.h" 22 #include "api/audio/echo_canceller3_config.h" 23 #include "modules/audio_processing/aec3/aec3_common.h" 24 #include "modules/audio_processing/logging/apm_data_dumper.h" 25 #include "rtc_base/checks.h" 26 27 namespace webrtc { 28 29 namespace { 30 constexpr float kEpsilon = 1e-3f; 31 constexpr float kX2BandEnergyThreshold = 44015068.0f; 32 constexpr int kBlocksToHoldErle = 100; 33 constexpr int kPointsToAccumulate = 6; 34 } // namespace 35 36 FullBandErleEstimator::FullBandErleEstimator( 37 const EchoCanceller3Config::Erle& config, 38 size_t num_capture_channels) 39 : min_erle_log2_(FastApproxLog2f(config.min + kEpsilon)), 40 max_erle_lf_log2_(FastApproxLog2f(config.max_l + kEpsilon)), 41 hold_counters_instantaneous_erle_(num_capture_channels, 0), 42 erle_time_domain_log2_(num_capture_channels, min_erle_log2_), 43 instantaneous_erle_(num_capture_channels, ErleInstantaneous(config)), 44 linear_filters_qualities_(num_capture_channels) { 45 Reset(); 46 } 47 48 FullBandErleEstimator::~FullBandErleEstimator() = default; 49 50 void FullBandErleEstimator::Reset() { 51 for (auto& instantaneous_erle_ch : instantaneous_erle_) { 52 instantaneous_erle_ch.Reset(); 53 } 54 55 UpdateQualityEstimates(); 56 std::fill(erle_time_domain_log2_.begin(), erle_time_domain_log2_.end(), 57 min_erle_log2_); 58 std::fill(hold_counters_instantaneous_erle_.begin(), 59 hold_counters_instantaneous_erle_.end(), 0); 60 } 61 62 void FullBandErleEstimator::Update( 63 ArrayView<const float> X2, 64 ArrayView<const std::array<float, kFftLengthBy2Plus1>> Y2, 65 ArrayView<const std::array<float, kFftLengthBy2Plus1>> E2, 66 const std::vector<bool>& converged_filters) { 67 for (size_t ch = 0; ch < Y2.size(); ++ch) { 68 if (converged_filters[ch]) { 69 // Computes the fullband ERLE. 70 const float X2_sum = std::accumulate(X2.begin(), X2.end(), 0.0f); 71 if (X2_sum > kX2BandEnergyThreshold * X2.size()) { 72 const float Y2_sum = 73 std::accumulate(Y2[ch].begin(), Y2[ch].end(), 0.0f); 74 const float E2_sum = 75 std::accumulate(E2[ch].begin(), E2[ch].end(), 0.0f); 76 if (instantaneous_erle_[ch].Update(Y2_sum, E2_sum)) { 77 hold_counters_instantaneous_erle_[ch] = kBlocksToHoldErle; 78 erle_time_domain_log2_[ch] += 79 0.05f * ((instantaneous_erle_[ch].GetInstErleLog2().value()) - 80 erle_time_domain_log2_[ch]); 81 erle_time_domain_log2_[ch] = 82 std::max(erle_time_domain_log2_[ch], min_erle_log2_); 83 } 84 } 85 } 86 --hold_counters_instantaneous_erle_[ch]; 87 if (hold_counters_instantaneous_erle_[ch] == 0) { 88 instantaneous_erle_[ch].ResetAccumulators(); 89 } 90 } 91 92 UpdateQualityEstimates(); 93 } 94 95 void FullBandErleEstimator::Dump( 96 const std::unique_ptr<ApmDataDumper>& data_dumper) const { 97 data_dumper->DumpRaw("aec3_fullband_erle_log2", FullbandErleLog2()); 98 instantaneous_erle_[0].Dump(data_dumper); 99 } 100 101 void FullBandErleEstimator::UpdateQualityEstimates() { 102 for (size_t ch = 0; ch < instantaneous_erle_.size(); ++ch) { 103 linear_filters_qualities_[ch] = 104 instantaneous_erle_[ch].GetQualityEstimate(); 105 } 106 } 107 108 FullBandErleEstimator::ErleInstantaneous::ErleInstantaneous( 109 const EchoCanceller3Config::Erle& config) 110 : clamp_inst_quality_to_zero_(config.clamp_quality_estimate_to_zero), 111 clamp_inst_quality_to_one_(config.clamp_quality_estimate_to_one) { 112 Reset(); 113 } 114 115 FullBandErleEstimator::ErleInstantaneous::~ErleInstantaneous() = default; 116 117 bool FullBandErleEstimator::ErleInstantaneous::Update(const float Y2_sum, 118 const float E2_sum) { 119 bool update_estimates = false; 120 E2_acum_ += E2_sum; 121 Y2_acum_ += Y2_sum; 122 num_points_++; 123 if (num_points_ == kPointsToAccumulate) { 124 if (E2_acum_ > 0.f) { 125 update_estimates = true; 126 erle_log2_ = FastApproxLog2f(Y2_acum_ / E2_acum_ + kEpsilon); 127 } 128 num_points_ = 0; 129 E2_acum_ = 0.f; 130 Y2_acum_ = 0.f; 131 } 132 133 if (update_estimates) { 134 UpdateMaxMin(); 135 UpdateQualityEstimate(); 136 } 137 return update_estimates; 138 } 139 140 void FullBandErleEstimator::ErleInstantaneous::Reset() { 141 ResetAccumulators(); 142 max_erle_log2_ = -10.f; // -30 dB. 143 min_erle_log2_ = 33.f; // 100 dB. 144 inst_quality_estimate_ = 0.f; 145 } 146 147 void FullBandErleEstimator::ErleInstantaneous::ResetAccumulators() { 148 erle_log2_ = std::nullopt; 149 inst_quality_estimate_ = 0.f; 150 num_points_ = 0; 151 E2_acum_ = 0.f; 152 Y2_acum_ = 0.f; 153 } 154 155 void FullBandErleEstimator::ErleInstantaneous::Dump( 156 const std::unique_ptr<ApmDataDumper>& data_dumper) const { 157 data_dumper->DumpRaw("aec3_fullband_erle_inst_log2", 158 erle_log2_ ? *erle_log2_ : -10.f); 159 data_dumper->DumpRaw( 160 "aec3_erle_instantaneous_quality", 161 GetQualityEstimate() ? GetQualityEstimate().value() : 0.f); 162 data_dumper->DumpRaw("aec3_fullband_erle_max_log2", max_erle_log2_); 163 data_dumper->DumpRaw("aec3_fullband_erle_min_log2", min_erle_log2_); 164 } 165 166 void FullBandErleEstimator::ErleInstantaneous::UpdateMaxMin() { 167 RTC_DCHECK(erle_log2_); 168 // Adding the forgetting factors for the maximum and minimum and capping the 169 // result to the incoming value. 170 max_erle_log2_ -= 0.0004f; // Forget factor, approx 1dB every 3 sec. 171 max_erle_log2_ = std::max(max_erle_log2_, erle_log2_.value()); 172 min_erle_log2_ += 0.0004f; // Forget factor, approx 1dB every 3 sec. 173 min_erle_log2_ = std::min(min_erle_log2_, erle_log2_.value()); 174 } 175 176 void FullBandErleEstimator::ErleInstantaneous::UpdateQualityEstimate() { 177 const float alpha = 0.07f; 178 float quality_estimate = 0.f; 179 RTC_DCHECK(erle_log2_); 180 // TODO(peah): Currently, the estimate can become be less than 0; this should 181 // be corrected. 182 if (max_erle_log2_ > min_erle_log2_) { 183 quality_estimate = (erle_log2_.value() - min_erle_log2_) / 184 (max_erle_log2_ - min_erle_log2_); 185 } 186 if (quality_estimate > inst_quality_estimate_) { 187 inst_quality_estimate_ = quality_estimate; 188 } else { 189 inst_quality_estimate_ += 190 alpha * (quality_estimate - inst_quality_estimate_); 191 } 192 } 193 194 } // namespace webrtc