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 |