1 /*
2 * Copyright 2019 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 "rtc_base/numerics/event_based_exponential_moving_average.h"
12
13 #include <cmath>
14
15 #include "test/gtest.h"
16
17 namespace {
18
19 constexpr int kHalfTime = 500;
20 constexpr double kError = 0.1;
21
22 } // namespace
23
24 namespace rtc {
25
TEST(EventBasedExponentialMovingAverageTest,NoValue)26 TEST(EventBasedExponentialMovingAverageTest, NoValue) {
27 EventBasedExponentialMovingAverage average(kHalfTime);
28
29 EXPECT_TRUE(std::isnan(average.GetAverage()));
30 EXPECT_EQ(std::numeric_limits<double>::infinity(), average.GetVariance());
31 EXPECT_EQ(std::numeric_limits<double>::infinity(),
32 average.GetConfidenceInterval());
33 }
34
TEST(EventBasedExponentialMovingAverageTest,FirstValue)35 TEST(EventBasedExponentialMovingAverageTest, FirstValue) {
36 EventBasedExponentialMovingAverage average(kHalfTime);
37
38 int64_t time = 23;
39 constexpr int value = 1000;
40 average.AddSample(time, value);
41 EXPECT_NEAR(value, average.GetAverage(), kError);
42 EXPECT_EQ(std::numeric_limits<double>::infinity(), average.GetVariance());
43 EXPECT_EQ(std::numeric_limits<double>::infinity(),
44 average.GetConfidenceInterval());
45 }
46
TEST(EventBasedExponentialMovingAverageTest,Half)47 TEST(EventBasedExponentialMovingAverageTest, Half) {
48 EventBasedExponentialMovingAverage average(kHalfTime);
49
50 int64_t time = 23;
51 constexpr int value = 1000;
52 average.AddSample(time, value);
53 average.AddSample(time + kHalfTime, 0);
54 EXPECT_NEAR(666.7, average.GetAverage(), kError);
55 EXPECT_NEAR(1000000, average.GetVariance(), kError);
56 EXPECT_NEAR(1460.9, average.GetConfidenceInterval(), kError);
57 }
58
TEST(EventBasedExponentialMovingAverageTest,Same)59 TEST(EventBasedExponentialMovingAverageTest, Same) {
60 EventBasedExponentialMovingAverage average(kHalfTime);
61
62 int64_t time = 23;
63 constexpr int value = 1000;
64 average.AddSample(time, value);
65 average.AddSample(time + kHalfTime, value);
66 EXPECT_NEAR(value, average.GetAverage(), kError);
67 EXPECT_NEAR(0, average.GetVariance(), kError);
68 EXPECT_NEAR(0, average.GetConfidenceInterval(), kError);
69 }
70
TEST(EventBasedExponentialMovingAverageTest,Almost100)71 TEST(EventBasedExponentialMovingAverageTest, Almost100) {
72 EventBasedExponentialMovingAverage average(kHalfTime);
73
74 int64_t time = 23;
75 constexpr int value = 100;
76 average.AddSample(time + 0 * kHalfTime, value - 10);
77 average.AddSample(time + 1 * kHalfTime, value + 10);
78 average.AddSample(time + 2 * kHalfTime, value - 15);
79 average.AddSample(time + 3 * kHalfTime, value + 15);
80 EXPECT_NEAR(100.2, average.GetAverage(), kError);
81 EXPECT_NEAR(372.6, average.GetVariance(), kError);
82 EXPECT_NEAR(19.7, average.GetConfidenceInterval(), kError); // 100 +/- 20
83
84 average.AddSample(time + 4 * kHalfTime, value);
85 average.AddSample(time + 5 * kHalfTime, value);
86 average.AddSample(time + 6 * kHalfTime, value);
87 average.AddSample(time + 7 * kHalfTime, value);
88 EXPECT_NEAR(100.0, average.GetAverage(), kError);
89 EXPECT_NEAR(73.6, average.GetVariance(), kError);
90 EXPECT_NEAR(7.6, average.GetConfidenceInterval(), kError); // 100 +/- 7
91 }
92
93 // Test that getting a value at X and another at X+1
94 // is almost the same as getting another at X and a value at X+1.
TEST(EventBasedExponentialMovingAverageTest,AlmostSameTime)95 TEST(EventBasedExponentialMovingAverageTest, AlmostSameTime) {
96 int64_t time = 23;
97 constexpr int value = 100;
98
99 {
100 EventBasedExponentialMovingAverage average(kHalfTime);
101 average.AddSample(time + 0, value);
102 average.AddSample(time + 1, 0);
103 EXPECT_NEAR(50, average.GetAverage(), kError);
104 EXPECT_NEAR(10000, average.GetVariance(), kError);
105 EXPECT_NEAR(138.6, average.GetConfidenceInterval(),
106 kError); // 50 +/- 138.6
107 }
108
109 {
110 EventBasedExponentialMovingAverage average(kHalfTime);
111 average.AddSample(time + 0, 0);
112 average.AddSample(time + 1, 100);
113 EXPECT_NEAR(50, average.GetAverage(), kError);
114 EXPECT_NEAR(10000, average.GetVariance(), kError);
115 EXPECT_NEAR(138.6, average.GetConfidenceInterval(),
116 kError); // 50 +/- 138.6
117 }
118 }
119
120 // This test shows behavior of estimator with a half_time of 100.
121 // It is unclear if these set of observations are representative
122 // of any real world scenarios.
TEST(EventBasedExponentialMovingAverageTest,NonUniformSamplesHalftime100)123 TEST(EventBasedExponentialMovingAverageTest, NonUniformSamplesHalftime100) {
124 int64_t time = 23;
125 constexpr int value = 100;
126
127 {
128 // The observations at 100 and 101, are significantly close in
129 // time that the estimator returns approx. the average.
130 EventBasedExponentialMovingAverage average(100);
131 average.AddSample(time + 0, value);
132 average.AddSample(time + 100, value);
133 average.AddSample(time + 101, 0);
134 EXPECT_NEAR(50.2, average.GetAverage(), kError);
135 EXPECT_NEAR(86.2, average.GetConfidenceInterval(), kError); // 50 +/- 86
136 }
137
138 {
139 EventBasedExponentialMovingAverage average(100);
140 average.AddSample(time + 0, value);
141 average.AddSample(time + 1, value);
142 average.AddSample(time + 100, 0);
143 EXPECT_NEAR(66.5, average.GetAverage(), kError);
144 EXPECT_NEAR(65.4, average.GetConfidenceInterval(), kError); // 66 +/- 65
145 }
146
147 {
148 EventBasedExponentialMovingAverage average(100);
149 for (int i = 0; i < 10; i++) {
150 average.AddSample(time + i, value);
151 }
152 average.AddSample(time + 100, 0);
153 EXPECT_NEAR(65.3, average.GetAverage(), kError);
154 EXPECT_NEAR(59.1, average.GetConfidenceInterval(), kError); // 55 +/- 59
155 }
156
157 {
158 EventBasedExponentialMovingAverage average(100);
159 average.AddSample(time + 0, 100);
160 for (int i = 90; i <= 100; i++) {
161 average.AddSample(time + i, 0);
162 }
163 EXPECT_NEAR(0.05, average.GetAverage(), kError);
164 EXPECT_NEAR(4.9, average.GetConfidenceInterval(), kError); // 0 +/- 5
165 }
166 }
167
TEST(EventBasedExponentialMovingAverageTest,Reset)168 TEST(EventBasedExponentialMovingAverageTest, Reset) {
169 constexpr int64_t time = 23;
170 constexpr int value = 100;
171
172 EventBasedExponentialMovingAverage average(100);
173 EXPECT_TRUE(std::isnan(average.GetAverage()));
174 EXPECT_EQ(std::numeric_limits<double>::infinity(), average.GetVariance());
175 EXPECT_EQ(std::numeric_limits<double>::infinity(),
176 average.GetConfidenceInterval());
177
178 average.AddSample(time + 0, value);
179 average.AddSample(time + 100, value);
180 average.AddSample(time + 101, 0);
181 EXPECT_FALSE(std::isnan(average.GetAverage()));
182
183 average.Reset();
184 EXPECT_TRUE(std::isnan(average.GetAverage()));
185 EXPECT_EQ(std::numeric_limits<double>::infinity(), average.GetVariance());
186 EXPECT_EQ(std::numeric_limits<double>::infinity(),
187 average.GetConfidenceInterval());
188 }
189
190 // Test that SetHalfTime modifies behavior and resets average.
TEST(EventBasedExponentialMovingAverageTest,SetHalfTime)191 TEST(EventBasedExponentialMovingAverageTest, SetHalfTime) {
192 constexpr int64_t time = 23;
193 constexpr int value = 100;
194
195 EventBasedExponentialMovingAverage average(100);
196
197 average.AddSample(time + 0, value);
198 average.AddSample(time + 100, 0);
199 EXPECT_NEAR(66.7, average.GetAverage(), kError);
200
201 average.SetHalfTime(1000);
202 EXPECT_TRUE(std::isnan(average.GetAverage()));
203 EXPECT_EQ(std::numeric_limits<double>::infinity(), average.GetVariance());
204 EXPECT_EQ(std::numeric_limits<double>::infinity(),
205 average.GetConfidenceInterval());
206
207 average.AddSample(time + 0, value);
208 average.AddSample(time + 100, 0);
209 EXPECT_NEAR(51.7, average.GetAverage(), kError);
210 }
211
TEST(EventBasedExponentialMovingAverageTest,SimultaneousSamples)212 TEST(EventBasedExponentialMovingAverageTest, SimultaneousSamples) {
213 constexpr int64_t time = 23;
214 constexpr int value = 100;
215
216 EventBasedExponentialMovingAverage average(100);
217
218 average.AddSample(time, value);
219 // This should really NOT be supported,
220 // i.e 2 samples with same timestamp.
221 // But there are tests running with simulated clock
222 // that produce this.
223 // TODO(webrtc:11140) : Fix those tests and remove this!
224 average.AddSample(time, value);
225 }
226
227 } // namespace rtc
228