blob: 8b311d1498a8bc791efe186b6ef4dc1de124bc38 [file] [log] [blame]
minyue35483572016-09-20 23:13:08 -07001/*
2 * Copyright (c) 2016 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
Jonas Olssona4d87372019-07-05 19:08:33 +020011#include "common_audio/smoothing_filter.h"
12
minyue301fc4a2016-12-13 06:52:56 -080013#include <cmath>
minyue35483572016-09-20 23:13:08 -070014#include <memory>
15
Steve Anton10542f22019-01-11 09:11:00 -080016#include "rtc_base/fake_clock.h"
Mirko Bonadei92ea95e2017-09-15 06:47:31 +020017#include "test/gtest.h"
minyue35483572016-09-20 23:13:08 -070018
19namespace webrtc {
20
21namespace {
22
minyue301fc4a2016-12-13 06:52:56 -080023constexpr float kMaxAbsError = 1e-5f;
minyue35483572016-09-20 23:13:08 -070024constexpr int64_t kClockInitialTime = 123456;
25
26struct SmoothingFilterStates {
michaelt92aef172017-04-18 00:11:48 -070027 explicit SmoothingFilterStates(int init_time_ms)
28 : smoothing_filter(init_time_ms) {
Sebastian Jansson5f83cf02018-05-08 14:52:22 +020029 fake_clock.AdvanceTime(TimeDelta::ms(kClockInitialTime));
michaelt92aef172017-04-18 00:11:48 -070030 }
31 rtc::ScopedFakeClock fake_clock;
32 SmoothingFilterImpl smoothing_filter;
minyue35483572016-09-20 23:13:08 -070033};
34
minyue301fc4a2016-12-13 06:52:56 -080035// This function does the following:
36// 1. Add a sample to filter at current clock,
37// 2. Advance the clock by |advance_time_ms|,
38// 3. Get the output of both SmoothingFilter and verify that it equals to an
39// expected value.
minyue35483572016-09-20 23:13:08 -070040void CheckOutput(SmoothingFilterStates* states,
minyue35483572016-09-20 23:13:08 -070041 float sample,
minyue301fc4a2016-12-13 06:52:56 -080042 int advance_time_ms,
minyue35483572016-09-20 23:13:08 -070043 float expected_ouput) {
michaelt92aef172017-04-18 00:11:48 -070044 states->smoothing_filter.AddSample(sample);
Sebastian Jansson5f83cf02018-05-08 14:52:22 +020045 states->fake_clock.AdvanceTime(TimeDelta::ms(advance_time_ms));
michaelt92aef172017-04-18 00:11:48 -070046 auto output = states->smoothing_filter.GetAverage();
minyue35483572016-09-20 23:13:08 -070047 EXPECT_TRUE(output);
48 EXPECT_NEAR(expected_ouput, *output, kMaxAbsError);
49}
50
51} // namespace
52
53TEST(SmoothingFilterTest, NoOutputWhenNoSampleAdded) {
minyue7667db42016-12-28 02:57:50 -080054 constexpr int kInitTimeMs = 100;
michaelt92aef172017-04-18 00:11:48 -070055 SmoothingFilterStates states(kInitTimeMs);
56 EXPECT_FALSE(states.smoothing_filter.GetAverage());
minyue35483572016-09-20 23:13:08 -070057}
58
59// Python script to calculate the reference values used in this test.
minyue301fc4a2016-12-13 06:52:56 -080060// import math
minyue35483572016-09-20 23:13:08 -070061//
minyue301fc4a2016-12-13 06:52:56 -080062// class ExpFilter:
63// def add_sample(self, new_value):
64// self.state = self.state * self.alpha + (1.0 - self.alpha) * new_value
minyue35483572016-09-20 23:13:08 -070065//
minyue301fc4a2016-12-13 06:52:56 -080066// filter = ExpFilter()
67// init_time = 795
68// init_factor = (1.0 / init_time) ** (1.0 / init_time)
69//
70// filter.state = 1.0
71//
72// for time_now in range(1, 500):
73// filter.alpha = math.exp(-init_factor ** time_now)
74// filter.add_sample(1.0)
75// print filter.state
76//
77// for time_now in range(500, 600):
78// filter.alpha = math.exp(-init_factor ** time_now)
79// filter.add_sample(0.5)
80// print filter.state
81//
82// for time_now in range(600, 700):
83// filter.alpha = math.exp(-init_factor ** time_now)
84// filter.add_sample(1.0)
85// print filter.state
86//
87// for time_now in range(700, init_time):
88// filter.alpha = math.exp(-init_factor ** time_now)
89// filter.add_sample(1.0)
90//
91// filter.alpha = math.exp(-1.0 / init_time)
92// for time_now in range(init_time, 800):
93// filter.add_sample(1.0)
94// print filter.state
95//
96// for i in range(800, 900):
97// filter.add_sample(0.5)
98// print filter.state
99//
100// for i in range(900, 1000):
101// filter.add_sample(1.0)
102// print filter.state
103TEST(SmoothingFilterTest, CheckBehaviorAroundInitTime) {
minyue7667db42016-12-28 02:57:50 -0800104 constexpr int kInitTimeMs = 795;
michaelt92aef172017-04-18 00:11:48 -0700105 SmoothingFilterStates states(kInitTimeMs);
minyue301fc4a2016-12-13 06:52:56 -0800106 CheckOutput(&states, 1.0f, 500, 1.0f);
107 CheckOutput(&states, 0.5f, 100, 0.680562264029f);
108 CheckOutput(&states, 1.0f, 100, 0.794207139813f);
109 // Next step will go across initialization time.
110 CheckOutput(&states, 1.0f, 100, 0.829803409752f);
111 CheckOutput(&states, 0.5f, 100, 0.790821764210f);
112 CheckOutput(&states, 1.0f, 100, 0.815545922911f);
minyue35483572016-09-20 23:13:08 -0700113}
114
minyue7667db42016-12-28 02:57:50 -0800115TEST(SmoothingFilterTest, InitTimeEqualsZero) {
116 constexpr int kInitTimeMs = 0;
michaelt92aef172017-04-18 00:11:48 -0700117 SmoothingFilterStates states(kInitTimeMs);
minyue7667db42016-12-28 02:57:50 -0800118 CheckOutput(&states, 1.0f, 1, 1.0f);
119 CheckOutput(&states, 0.5f, 1, 0.5f);
120}
121
122TEST(SmoothingFilterTest, InitTimeEqualsOne) {
123 constexpr int kInitTimeMs = 1;
michaelt92aef172017-04-18 00:11:48 -0700124 SmoothingFilterStates states(kInitTimeMs);
minyue7667db42016-12-28 02:57:50 -0800125 CheckOutput(&states, 1.0f, 1, 1.0f);
Mirko Bonadeib00dec52019-03-25 09:31:06 +0100126 CheckOutput(&states, 0.5f, 1,
127 1.0f * std::exp(-1.0f) + (1.0f - std::exp(-1.0f)) * 0.5f);
minyue7667db42016-12-28 02:57:50 -0800128}
129
minyue301fc4a2016-12-13 06:52:56 -0800130TEST(SmoothingFilterTest, GetAverageOutputsEmptyBeforeFirstSample) {
minyue7667db42016-12-28 02:57:50 -0800131 constexpr int kInitTimeMs = 100;
michaelt92aef172017-04-18 00:11:48 -0700132 SmoothingFilterStates states(kInitTimeMs);
133 EXPECT_FALSE(states.smoothing_filter.GetAverage());
minyue301fc4a2016-12-13 06:52:56 -0800134 constexpr float kFirstSample = 1.2345f;
michaelt92aef172017-04-18 00:11:48 -0700135 states.smoothing_filter.AddSample(kFirstSample);
Oskar Sundbom5e1a7492017-11-16 10:57:19 +0100136 EXPECT_EQ(kFirstSample, states.smoothing_filter.GetAverage());
minyue301fc4a2016-12-13 06:52:56 -0800137}
138
139TEST(SmoothingFilterTest, CannotChangeTimeConstantDuringInitialization) {
minyue7667db42016-12-28 02:57:50 -0800140 constexpr int kInitTimeMs = 100;
michaelt92aef172017-04-18 00:11:48 -0700141 SmoothingFilterStates states(kInitTimeMs);
142 states.smoothing_filter.AddSample(0.0);
minyue301fc4a2016-12-13 06:52:56 -0800143
144 // During initialization, |SetTimeConstantMs| does not take effect.
Sebastian Jansson5f83cf02018-05-08 14:52:22 +0200145 states.fake_clock.AdvanceTime(TimeDelta::ms(kInitTimeMs - 1));
michaelt92aef172017-04-18 00:11:48 -0700146 states.smoothing_filter.AddSample(0.0);
minyue301fc4a2016-12-13 06:52:56 -0800147
michaelt92aef172017-04-18 00:11:48 -0700148 EXPECT_FALSE(states.smoothing_filter.SetTimeConstantMs(kInitTimeMs * 2));
Mirko Bonadeib00dec52019-03-25 09:31:06 +0100149 EXPECT_NE(std::exp(-1.0f / (kInitTimeMs * 2)),
150 states.smoothing_filter.alpha());
minyue301fc4a2016-12-13 06:52:56 -0800151
Sebastian Jansson5f83cf02018-05-08 14:52:22 +0200152 states.fake_clock.AdvanceTime(TimeDelta::ms(1));
michaelt92aef172017-04-18 00:11:48 -0700153 states.smoothing_filter.AddSample(0.0);
minyue301fc4a2016-12-13 06:52:56 -0800154 // When initialization finishes, the time constant should be come
155 // |kInitTimeConstantMs|.
Mirko Bonadeib00dec52019-03-25 09:31:06 +0100156 EXPECT_FLOAT_EQ(std::exp(-1.0f / kInitTimeMs),
157 states.smoothing_filter.alpha());
minyue301fc4a2016-12-13 06:52:56 -0800158
159 // After initialization, |SetTimeConstantMs| takes effect.
michaelt92aef172017-04-18 00:11:48 -0700160 EXPECT_TRUE(states.smoothing_filter.SetTimeConstantMs(kInitTimeMs * 2));
Mirko Bonadeib00dec52019-03-25 09:31:06 +0100161 EXPECT_FLOAT_EQ(std::exp(-1.0f / (kInitTimeMs * 2)),
michaelt92aef172017-04-18 00:11:48 -0700162 states.smoothing_filter.alpha());
minyue35483572016-09-20 23:13:08 -0700163}
164
165} // namespace webrtc