| Index: webrtc/common_audio/smoothing_filter_unittest.cc
|
| diff --git a/webrtc/common_audio/smoothing_filter_unittest.cc b/webrtc/common_audio/smoothing_filter_unittest.cc
|
| index c80ffb672cb71b3286e3408d3aaec38fe77b6006..3abea2845ab261c9cdaa35faa3a9a37f282535dd 100644
|
| --- a/webrtc/common_audio/smoothing_filter_unittest.cc
|
| +++ b/webrtc/common_audio/smoothing_filter_unittest.cc
|
| @@ -8,6 +8,7 @@
|
| * be found in the AUTHORS file in the root of the source tree.
|
| */
|
|
|
| +#include <cmath>
|
| #include <memory>
|
|
|
| #include "webrtc/common_audio/smoothing_filter.h"
|
| @@ -17,29 +18,34 @@ namespace webrtc {
|
|
|
| namespace {
|
|
|
| -constexpr int kTimeConstantMs = 1000;
|
| -constexpr float kMaxAbsError = 0.0001f;
|
| +constexpr int kInitTimeConstantMs = 1000;
|
| +constexpr float kMaxAbsError = 1e-5f;
|
| constexpr int64_t kClockInitialTime = 123456;
|
|
|
| struct SmoothingFilterStates {
|
| std::unique_ptr<SimulatedClock> simulated_clock;
|
| - std::unique_ptr<SmoothingFilter> smoothing_filter;
|
| + std::unique_ptr<SmoothingFilterImpl> smoothing_filter;
|
| };
|
|
|
| SmoothingFilterStates CreateSmoothingFilter() {
|
| SmoothingFilterStates states;
|
| states.simulated_clock.reset(new SimulatedClock(kClockInitialTime));
|
| - states.smoothing_filter.reset(
|
| - new SmoothingFilterImpl(kTimeConstantMs, states.simulated_clock.get()));
|
| + states.smoothing_filter.reset(new SmoothingFilterImpl(
|
| + kInitTimeConstantMs, states.simulated_clock.get()));
|
| return states;
|
| }
|
|
|
| +// This function does the following:
|
| +// 1. Add a sample to filter at current clock,
|
| +// 2. Advance the clock by |advance_time_ms|,
|
| +// 3. Get the output of both SmoothingFilter and verify that it equals to an
|
| +// expected value.
|
| void CheckOutput(SmoothingFilterStates* states,
|
| - int advance_time_ms,
|
| float sample,
|
| + int advance_time_ms,
|
| float expected_ouput) {
|
| - states->simulated_clock->AdvanceTimeMilliseconds(advance_time_ms);
|
| states->smoothing_filter->AddSample(sample);
|
| + states->simulated_clock->AdvanceTimeMilliseconds(advance_time_ms);
|
| auto output = states->smoothing_filter->GetAverage();
|
| EXPECT_TRUE(output);
|
| EXPECT_NEAR(expected_ouput, *output, kMaxAbsError);
|
| @@ -53,56 +59,90 @@ TEST(SmoothingFilterTest, NoOutputWhenNoSampleAdded) {
|
| }
|
|
|
| // Python script to calculate the reference values used in this test.
|
| -// import math
|
| -//
|
| -// class ExpFilter:
|
| -// alpha = 0.0
|
| -// old_value = 0.0
|
| -// def calc(self, new_value):
|
| -// self.old_value = self.old_value * self.alpha
|
| -// + (1.0 - self.alpha) * new_value
|
| -// return self.old_value
|
| +// import math
|
| +// class ExpFilter:
|
| +// def add_sample(self, new_value):
|
| +// self.old_value =
|
| +// self.old_value * self.alpha + (1.0 - self.alpha) * new_value
|
| +// return self.old_value
|
| +// def add_samples(self, new_value, times):
|
| +// for i in range(times):
|
| +// self.add_sample(new_value)
|
| +// return self.old_value
|
| //
|
| -// delta_t = 100.0
|
| -// filter = ExpFilter()
|
| -// total_t = 100.0
|
| -// filter.alpha = math.exp(-delta_t/ total_t)
|
| -// print filter.calc(1.0)
|
| -// total_t = 200.0
|
| -// filter.alpha = math.exp(-delta_t/ total_t)
|
| -// print filter.calc(0.0)
|
| -// total_t = 300.0
|
| -// filter.alpha = math.exp(-delta_t/ total_t)
|
| -// print filter.calc(1.0)
|
| +// filter = ExpFilter()
|
| +// filter.alpha = 0.0
|
| +// filter.old_value = 1.0
|
| +// delta_t = 100
|
| +// print filter.add_samples(1.0, delta_t)
|
| +
|
| +// time_constant = delta_t
|
| +// filter.alpha = math.exp(-1.0 / time_constant)
|
| +// print filter.add_samples(0.0, delta_t)
|
| +
|
| +// time_constant += delta_t
|
| +// filter.alpha = math.exp(-1.0 / time_constant)
|
| +// print filter.add_samples(1.0, delta_t)
|
| TEST(SmoothingFilterTest, CheckBehaviorBeforeInitialized) {
|
| // Adding three samples, all added before |kTimeConstantMs| is reached.
|
| constexpr int kTimeIntervalMs = 100;
|
| auto states = CreateSmoothingFilter();
|
| - states.smoothing_filter->AddSample(0.0);
|
| - CheckOutput(&states, kTimeIntervalMs, 1.0, 0.63212f);
|
| - CheckOutput(&states, kTimeIntervalMs, 0.0, 0.38340f);
|
| - CheckOutput(&states, kTimeIntervalMs, 1.0, 0.55818f);
|
| + CheckOutput(&states, 1.0, kTimeIntervalMs, 1.0);
|
| + CheckOutput(&states, 0.0, kTimeIntervalMs, 0.367879441171);
|
| + CheckOutput(&states, 1.0, kTimeIntervalMs, 0.616599500436);
|
| }
|
|
|
| // Python script to calculate the reference value used in this test.
|
| -// (after defining ExpFilter as for CheckBehaviorBeforeInitialized)
|
| -// time_constant_ms = 1000.0
|
| -// filter = ExpFilter()
|
| -// delta_t = 1100.0
|
| -// filter.alpha = math.exp(-delta_t/ time_constant_ms)
|
| -// print filter.calc(1.0)
|
| -// delta_t = 100.0
|
| -// filter.alpha = math.exp(-delta_t/ time_constant_ms)
|
| -// print filter.calc(0.0)
|
| -// print filter.calc(1.0)
|
| +// (with ExpFilter defined as in the comment to CheckBehaviorBeforeInitialized)
|
| +// filter = ExpFilter()
|
| +// filter.old_value = 0.0
|
| +// time_constant_ms = 1000.0
|
| +// filter.alpha = math.exp(-1.0 / time_constant_ms)
|
| +// delta_t = 100
|
| +// print filter.add_samples(1.0, delta_t)
|
| +// print filter.add_samples(0.0, delta_t)
|
| +// print filter.add_samples(1.0, delta_t)
|
| TEST(SmoothingFilterTest, CheckBehaviorAfterInitialized) {
|
| constexpr int kTimeIntervalMs = 100;
|
| auto states = CreateSmoothingFilter();
|
| states.smoothing_filter->AddSample(0.0);
|
| - states.simulated_clock->AdvanceTimeMilliseconds(kTimeConstantMs);
|
| - CheckOutput(&states, kTimeIntervalMs, 1.0, 0.66713f);
|
| - CheckOutput(&states, kTimeIntervalMs, 0.0, 0.60364f);
|
| - CheckOutput(&states, kTimeIntervalMs, 1.0, 0.64136f);
|
| + states.simulated_clock->AdvanceTimeMilliseconds(kInitTimeConstantMs);
|
| + CheckOutput(&states, 1.0, kTimeIntervalMs, 0.095162581964);
|
| + CheckOutput(&states, 0.0, kTimeIntervalMs, 0.086106664958);
|
| + CheckOutput(&states, 1.0, kTimeIntervalMs, 0.17307511436);
|
| +}
|
| +
|
| +TEST(SmoothingFilterTest, GetAverageOutputsEmptyBeforeFirstSample) {
|
| + auto states = CreateSmoothingFilter();
|
| + EXPECT_FALSE(states.smoothing_filter->GetAverage());
|
| + constexpr float kFirstSample = 1.2345f;
|
| + states.smoothing_filter->AddSample(kFirstSample);
|
| + EXPECT_EQ(rtc::Optional<float>(kFirstSample),
|
| + states.smoothing_filter->GetAverage());
|
| +}
|
| +
|
| +TEST(SmoothingFilterTest, CannotChangeTimeConstantDuringInitialization) {
|
| + auto states = CreateSmoothingFilter();
|
| + states.smoothing_filter->AddSample(0.0);
|
| +
|
| + // During initialization, |SetTimeConstantMs| does not take effect.
|
| + states.simulated_clock->AdvanceTimeMilliseconds(kInitTimeConstantMs - 1);
|
| + states.smoothing_filter->AddSample(0.0);
|
| +
|
| + states.smoothing_filter->SetTimeConstantMs(kInitTimeConstantMs * 2);
|
| + EXPECT_NE(exp(-1.0f / (kInitTimeConstantMs * 2)),
|
| + states.smoothing_filter->alpha());
|
| +
|
| + states.simulated_clock->AdvanceTimeMilliseconds(1);
|
| + states.smoothing_filter->AddSample(0.0);
|
| + // When initialization finishes, the time constant should be come
|
| + // |kInitTimeConstantMs|.
|
| + EXPECT_EQ(exp(-1.0f / kInitTimeConstantMs), states.smoothing_filter->alpha());
|
| +
|
| + // After initialization, |SetTimeConstantMs| takes effect.
|
| + states.smoothing_filter->SetTimeConstantMs(kInitTimeConstantMs * 2);
|
| + EXPECT_EQ(exp(-1.0f / (kInitTimeConstantMs * 2)),
|
| + states.smoothing_filter->alpha());
|
| }
|
|
|
| } // namespace webrtc
|
|
|