/* * 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 #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::infinity(), average.GetVariance()); EXPECT_EQ(std::numeric_limits::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::infinity(), average.GetVariance()); EXPECT_EQ(std::numeric_limits::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::infinity(), average.GetVariance()); EXPECT_EQ(std::numeric_limits::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::infinity(), average.GetVariance()); EXPECT_EQ(std::numeric_limits::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::infinity(), average.GetVariance()); EXPECT_EQ(std::numeric_limits::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