AEC3: Computation of comfort noise gains from suppression gains

This change corrects the computation of the comfort noise gains.

Previously the comfort noise gain of band k, CG_k, was computed
from suppression gain of band k, SG_k, as:
CG_k = 1 - SG_k

But since the two signals are uncorrelated (the comfort noise
is randomly generated), the correct gain to maintain power is:
CG_k = sqrt(1 - SG_k^2).

Bug: webrtc:9967,chromium:902262
Change-Id: I393495742163d5e658bca4ab2f7a5067ab15af01
Reviewed-on: https://webrtc-review.googlesource.com/c/109580
Commit-Queue: Gustaf Ullberg <gustaf@webrtc.org>
Reviewed-by: Per Åhgren <peah@webrtc.org>
Cr-Commit-Position: refs/heads/master@{#25525}
This commit is contained in:
Gustaf Ullberg 2018-11-06 16:25:37 +01:00 committed by Commit Bot
parent 34fc346a0c
commit 83b00f020e
4 changed files with 27 additions and 23 deletions

View File

@ -178,7 +178,7 @@ EchoRemoverImpl::EchoRemoverImpl(const EchoCanceller3Config& config,
subtractor_(config, data_dumper_.get(), optimization_),
suppression_gain_(config_, optimization_, sample_rate_hz),
cng_(optimization_),
suppression_filter_(sample_rate_hz_),
suppression_filter_(optimization_, sample_rate_hz_),
render_signal_analyzer_(config_),
residual_echo_estimator_(config_),
aec_state_(config_) {

View File

@ -11,10 +11,12 @@
#include "modules/audio_processing/aec3/suppression_filter.h"
#include <algorithm>
#include <cmath>
#include <cstring>
#include <functional>
#include <iterator>
#include "modules/audio_processing/aec3/vector_math.h"
#include "rtc_base/checks.h"
#include "rtc_base/numerics/safe_minmax.h"
@ -58,8 +60,10 @@ const float kSqrtHanning[kFftLength] = {
} // namespace
SuppressionFilter::SuppressionFilter(int sample_rate_hz)
: sample_rate_hz_(sample_rate_hz),
SuppressionFilter::SuppressionFilter(Aec3Optimization optimization,
int sample_rate_hz)
: optimization_(optimization),
sample_rate_hz_(sample_rate_hz),
fft_(),
e_output_old_(NumBandsForRate(sample_rate_hz_)) {
RTC_DCHECK(ValidFullBandRate(sample_rate_hz_));
@ -89,18 +93,17 @@ void SuppressionFilter::ApplyGain(
std::transform(suppression_gain.begin(), suppression_gain.end(), E.im.begin(),
E.im.begin(), std::multiplies<float>());
// Compute and add the comfort noise.
std::array<float, kFftLengthBy2Plus1> scaled_comfort_noise;
// Comfort noise gain is sqrt(1-g^2), where g is the suppression gain.
std::array<float, kFftLengthBy2Plus1> noise_gain;
std::transform(suppression_gain.begin(), suppression_gain.end(),
comfort_noise.re.begin(), scaled_comfort_noise.begin(),
[](float a, float b) { return std::max(1.f - a, 0.f) * b; });
std::transform(scaled_comfort_noise.begin(), scaled_comfort_noise.end(),
E.re.begin(), E.re.begin(), std::plus<float>());
std::transform(suppression_gain.begin(), suppression_gain.end(),
comfort_noise.im.begin(), scaled_comfort_noise.begin(),
[](float a, float b) { return std::max(1.f - a, 0.f) * b; });
std::transform(scaled_comfort_noise.begin(), scaled_comfort_noise.end(),
E.im.begin(), E.im.begin(), std::plus<float>());
noise_gain.begin(), [](float g) { return 1.f - g * g; });
aec3::VectorMath(optimization_).Sqrt(noise_gain);
// Scale and add the comfort noise.
for (size_t k = 0; k < kFftLengthBy2Plus1; k++) {
E.re[k] += noise_gain[k] * comfort_noise.re[k];
E.im[k] += noise_gain[k] * comfort_noise.im[k];
}
// Synthesis filterbank.
std::array<float, kFftLength> e_extended;
@ -134,7 +137,7 @@ void SuppressionFilter::ApplyGain(
// Scale and apply the noise to the signals.
const float high_bands_noise_scaling =
0.4f * std::max(1.f - high_bands_gain, 0.f);
0.4f * std::sqrt(1.f - high_bands_gain * high_bands_gain);
std::transform(
(*e)[1].begin(), (*e)[1].end(), time_domain_high_band_noise.begin(),

View File

@ -24,7 +24,7 @@ namespace webrtc {
class SuppressionFilter {
public:
explicit SuppressionFilter(int sample_rate_hz);
SuppressionFilter(Aec3Optimization optimization, int sample_rate_hz);
~SuppressionFilter();
void ApplyGain(const FftData& comfort_noise,
const FftData& comfort_noise_high_bands,
@ -34,6 +34,7 @@ class SuppressionFilter {
std::vector<std::vector<float>>* e);
private:
const Aec3Optimization optimization_;
const int sample_rate_hz_;
const OouraFft ooura_fft_;
const Aec3Fft fft_;

View File

@ -45,21 +45,21 @@ TEST(SuppressionFilter, NullOutput) {
FftData E;
std::array<float, kFftLengthBy2Plus1> gain;
EXPECT_DEATH(SuppressionFilter(16000).ApplyGain(cn, cn_high_bands, gain, 1.0f,
E, nullptr),
EXPECT_DEATH(SuppressionFilter(Aec3Optimization::kNone, 16000)
.ApplyGain(cn, cn_high_bands, gain, 1.0f, E, nullptr),
"");
}
// Verifies the check for allowed sample rate.
TEST(SuppressionFilter, ProperSampleRate) {
EXPECT_DEATH(SuppressionFilter(16001), "");
EXPECT_DEATH(SuppressionFilter(Aec3Optimization::kNone, 16001), "");
}
#endif
// Verifies that no comfort noise is added when the gain is 1.
TEST(SuppressionFilter, ComfortNoiseInUnityGain) {
SuppressionFilter filter(48000);
SuppressionFilter filter(Aec3Optimization::kNone, 48000);
FftData cn;
FftData cn_high_bands;
std::array<float, kFftLengthBy2Plus1> gain;
@ -89,7 +89,7 @@ TEST(SuppressionFilter, ComfortNoiseInUnityGain) {
// Verifies that the suppressor is able to suppress a signal.
TEST(SuppressionFilter, SignalSuppression) {
SuppressionFilter filter(48000);
SuppressionFilter filter(Aec3Optimization::kNone, 48000);
FftData cn;
FftData cn_high_bands;
std::array<float, kFftLengthBy2> e_old_;
@ -131,7 +131,7 @@ TEST(SuppressionFilter, SignalSuppression) {
// Verifies that the suppressor is able to pass through a desired signal while
// applying suppressing for some frequencies.
TEST(SuppressionFilter, SignalTransparency) {
SuppressionFilter filter(48000);
SuppressionFilter filter(Aec3Optimization::kNone, 48000);
FftData cn;
std::array<float, kFftLengthBy2> e_old_;
Aec3Fft fft;
@ -171,7 +171,7 @@ TEST(SuppressionFilter, SignalTransparency) {
// Verifies that the suppressor delay.
TEST(SuppressionFilter, Delay) {
SuppressionFilter filter(48000);
SuppressionFilter filter(Aec3Optimization::kNone, 48000);
FftData cn;
FftData cn_high_bands;
std::array<float, kFftLengthBy2> e_old_;