| /* | |
| * Copyright 2019 The WebRTC Project Authors. All rights reserved. | |
| * | |
| * Use of this source code is governed by a BSD-style license | |
| * that can be found in the LICENSE file in the root of the source | |
| * tree. An additional intellectual property rights grant can be found | |
| * in the file PATENTS. All contributing project authors may | |
| * be found in the AUTHORS file in the root of the source tree. | |
| */ | |
| #include "rtc_base/numerics/event_based_exponential_moving_average.h" | |
| #include <cmath> | |
| #include <cstdint> | |
| #include <limits> | |
| #include "test/gtest.h" | |
| namespace webrtc { | |
| namespace { | |
| constexpr int kHalfTime = 500; | |
| constexpr double kError = 0.1; | |
| } // namespace | |
| TEST(EventBasedExponentialMovingAverageTest, NoValue) { | |
| EventBasedExponentialMovingAverage average(kHalfTime); | |
| EXPECT_TRUE(std::isnan(average.GetAverage())); | |
| EXPECT_EQ(std::numeric_limits<double>::infinity(), average.GetVariance()); | |
| EXPECT_EQ(std::numeric_limits<double>::infinity(), | |
| average.GetConfidenceInterval()); | |
| } | |
| TEST(EventBasedExponentialMovingAverageTest, FirstValue) { | |
| EventBasedExponentialMovingAverage average(kHalfTime); | |
| int64_t time = 23; | |
| constexpr int value = 1000; | |
| average.AddSample(time, value); | |
| EXPECT_NEAR(value, average.GetAverage(), kError); | |
| EXPECT_EQ(std::numeric_limits<double>::infinity(), average.GetVariance()); | |
| EXPECT_EQ(std::numeric_limits<double>::infinity(), | |
| average.GetConfidenceInterval()); | |
| } | |
| TEST(EventBasedExponentialMovingAverageTest, Half) { | |
| EventBasedExponentialMovingAverage average(kHalfTime); | |
| int64_t time = 23; | |
| constexpr int value = 1000; | |
| average.AddSample(time, value); | |
| average.AddSample(time + kHalfTime, 0); | |
| EXPECT_NEAR(666.7, average.GetAverage(), kError); | |
| EXPECT_NEAR(1000000, average.GetVariance(), kError); | |
| EXPECT_NEAR(1460.9, average.GetConfidenceInterval(), kError); | |
| } | |
| TEST(EventBasedExponentialMovingAverageTest, Same) { | |
| EventBasedExponentialMovingAverage average(kHalfTime); | |
| int64_t time = 23; | |
| constexpr int value = 1000; | |
| average.AddSample(time, value); | |
| average.AddSample(time + kHalfTime, value); | |
| EXPECT_NEAR(value, average.GetAverage(), kError); | |
| EXPECT_NEAR(0, average.GetVariance(), kError); | |
| EXPECT_NEAR(0, average.GetConfidenceInterval(), kError); | |
| } | |
| TEST(EventBasedExponentialMovingAverageTest, Almost100) { | |
| EventBasedExponentialMovingAverage average(kHalfTime); | |
| int64_t time = 23; | |
| constexpr int value = 100; | |
| average.AddSample(time + 0 * kHalfTime, value - 10); | |
| average.AddSample(time + 1 * kHalfTime, value + 10); | |
| average.AddSample(time + 2 * kHalfTime, value - 15); | |
| average.AddSample(time + 3 * kHalfTime, value + 15); | |
| EXPECT_NEAR(100.2, average.GetAverage(), kError); | |
| EXPECT_NEAR(372.6, average.GetVariance(), kError); | |
| EXPECT_NEAR(19.7, average.GetConfidenceInterval(), kError); // 100 +/- 20 | |
| average.AddSample(time + 4 * kHalfTime, value); | |
| average.AddSample(time + 5 * kHalfTime, value); | |
| average.AddSample(time + 6 * kHalfTime, value); | |
| average.AddSample(time + 7 * kHalfTime, value); | |
| EXPECT_NEAR(100.0, average.GetAverage(), kError); | |
| EXPECT_NEAR(73.6, average.GetVariance(), kError); | |
| EXPECT_NEAR(7.6, average.GetConfidenceInterval(), kError); // 100 +/- 7 | |
| } | |
| // Test that getting a value at X and another at X+1 | |
| // is almost the same as getting another at X and a value at X+1. | |
| TEST(EventBasedExponentialMovingAverageTest, AlmostSameTime) { | |
| int64_t time = 23; | |
| constexpr int value = 100; | |
| { | |
| EventBasedExponentialMovingAverage average(kHalfTime); | |
| average.AddSample(time + 0, value); | |
| average.AddSample(time + 1, 0); | |
| EXPECT_NEAR(50, average.GetAverage(), kError); | |
| EXPECT_NEAR(10000, average.GetVariance(), kError); | |
| EXPECT_NEAR(138.6, average.GetConfidenceInterval(), | |
| kError); // 50 +/- 138.6 | |
| } | |
| { | |
| EventBasedExponentialMovingAverage average(kHalfTime); | |
| average.AddSample(time + 0, 0); | |
| average.AddSample(time + 1, 100); | |
| EXPECT_NEAR(50, average.GetAverage(), kError); | |
| EXPECT_NEAR(10000, average.GetVariance(), kError); | |
| EXPECT_NEAR(138.6, average.GetConfidenceInterval(), | |
| kError); // 50 +/- 138.6 | |
| } | |
| } | |
| // This test shows behavior of estimator with a half_time of 100. | |
| // It is unclear if these set of observations are representative | |
| // of any real world scenarios. | |
| TEST(EventBasedExponentialMovingAverageTest, NonUniformSamplesHalftime100) { | |
| int64_t time = 23; | |
| constexpr int value = 100; | |
| { | |
| // The observations at 100 and 101, are significantly close in | |
| // time that the estimator returns approx. the average. | |
| EventBasedExponentialMovingAverage average(100); | |
| average.AddSample(time + 0, value); | |
| average.AddSample(time + 100, value); | |
| average.AddSample(time + 101, 0); | |
| EXPECT_NEAR(50.2, average.GetAverage(), kError); | |
| EXPECT_NEAR(86.2, average.GetConfidenceInterval(), kError); // 50 +/- 86 | |
| } | |
| { | |
| EventBasedExponentialMovingAverage average(100); | |
| average.AddSample(time + 0, value); | |
| average.AddSample(time + 1, value); | |
| average.AddSample(time + 100, 0); | |
| EXPECT_NEAR(66.5, average.GetAverage(), kError); | |
| EXPECT_NEAR(65.4, average.GetConfidenceInterval(), kError); // 66 +/- 65 | |
| } | |
| { | |
| EventBasedExponentialMovingAverage average(100); | |
| for (int i = 0; i < 10; i++) { | |
| average.AddSample(time + i, value); | |
| } | |
| average.AddSample(time + 100, 0); | |
| EXPECT_NEAR(65.3, average.GetAverage(), kError); | |
| EXPECT_NEAR(59.1, average.GetConfidenceInterval(), kError); // 55 +/- 59 | |
| } | |
| { | |
| EventBasedExponentialMovingAverage average(100); | |
| average.AddSample(time + 0, 100); | |
| for (int i = 90; i <= 100; i++) { | |
| average.AddSample(time + i, 0); | |
| } | |
| EXPECT_NEAR(0.05, average.GetAverage(), kError); | |
| EXPECT_NEAR(4.9, average.GetConfidenceInterval(), kError); // 0 +/- 5 | |
| } | |
| } | |
| TEST(EventBasedExponentialMovingAverageTest, Reset) { | |
| constexpr int64_t time = 23; | |
| constexpr int value = 100; | |
| EventBasedExponentialMovingAverage average(100); | |
| EXPECT_TRUE(std::isnan(average.GetAverage())); | |
| EXPECT_EQ(std::numeric_limits<double>::infinity(), average.GetVariance()); | |
| EXPECT_EQ(std::numeric_limits<double>::infinity(), | |
| average.GetConfidenceInterval()); | |
| average.AddSample(time + 0, value); | |
| average.AddSample(time + 100, value); | |
| average.AddSample(time + 101, 0); | |
| EXPECT_FALSE(std::isnan(average.GetAverage())); | |
| average.Reset(); | |
| EXPECT_TRUE(std::isnan(average.GetAverage())); | |
| EXPECT_EQ(std::numeric_limits<double>::infinity(), average.GetVariance()); | |
| EXPECT_EQ(std::numeric_limits<double>::infinity(), | |
| average.GetConfidenceInterval()); | |
| } | |
| // Test that SetHalfTime modifies behavior and resets average. | |
| TEST(EventBasedExponentialMovingAverageTest, SetHalfTime) { | |
| constexpr int64_t time = 23; | |
| constexpr int value = 100; | |
| EventBasedExponentialMovingAverage average(100); | |
| average.AddSample(time + 0, value); | |
| average.AddSample(time + 100, 0); | |
| EXPECT_NEAR(66.7, average.GetAverage(), kError); | |
| average.SetHalfTime(1000); | |
| EXPECT_TRUE(std::isnan(average.GetAverage())); | |
| EXPECT_EQ(std::numeric_limits<double>::infinity(), average.GetVariance()); | |
| EXPECT_EQ(std::numeric_limits<double>::infinity(), | |
| average.GetConfidenceInterval()); | |
| average.AddSample(time + 0, value); | |
| average.AddSample(time + 100, 0); | |
| EXPECT_NEAR(51.7, average.GetAverage(), kError); | |
| } | |
| TEST(EventBasedExponentialMovingAverageTest, SimultaneousSamples) { | |
| constexpr int64_t time = 23; | |
| constexpr int value = 100; | |
| EventBasedExponentialMovingAverage average(100); | |
| average.AddSample(time, value); | |
| // This should really NOT be supported, | |
| // i.e 2 samples with same timestamp. | |
| // But there are tests running with simulated clock | |
| // that produce this. | |
| // TODO(webrtc:11140) : Fix those tests and remove this! | |
| average.AddSample(time, value); | |
| } | |
| } // namespace webrtc |