| /* |
| * 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 { |
| |
| constexpr int kHalfTime = 500; |
| constexpr double kError = 0.1; |
| |
| } // namespace |
| |
| namespace rtc { |
| |
| 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 rtc |