webrtc/rtc_base/numerics/event_based_exponential_moving_average_unittest.cc
Jonas Oreland bfcb6c3f13 Add rtt estimate EventBasedExponentialMovingAverage to Connection
This patch estimates the connection RTT using
EventBasedExponentialMovingAverage. The half time is
set to 500 but can be modified using field trials.

This new metric is currently unused, but will
be used for exploration of of whether it can be used
instead of the existing metric.

Bug: webrtc:11140
Change-Id: I9db93e9b9eb932e3cd18935cd4ce0d90fc1cb293
Reviewed-on: https://webrtc-review.googlesource.com/c/src/+/161000
Commit-Queue: Jonas Oreland <jonaso@webrtc.org>
Reviewed-by: Harald Alvestrand <hta@webrtc.org>
Cr-Commit-Position: refs/heads/master@{#29944}
2019-11-28 09:24:44 +00:00

227 lines
7.6 KiB
C++

/*
* 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 "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