1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
media / gpu / exponential_moving_average.h [blame]
// Copyright 2023 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#ifndef MEDIA_GPU_EXPONENTIAL_MOVING_AVERAGE_H_
#define MEDIA_GPU_EXPONENTIAL_MOVING_AVERAGE_H_
#include <algorithm>
#include <memory>
#include "base/time/time.h"
#include "media/gpu/media_gpu_export.h"
namespace media {
// An Exponential Moving Average filter.
// It is an implementation of exponential moving average filter with a time
// constant. The effective window size equals to the time elapsed since the
// first sample was added, until the maximum window size is reached. This makes
// a difference to the standard exponential moving average filter
// implementation. Alpha, the time constant, is calculated as a ratio between
// the time period passed from the last added sample and the effective window
// size.
// mean += alpha * (value - mean)
// mean_square += alpha * (value^2 - mean_square)
// std_dev = sqrt(mean_square - mean^2)
// alpha = elapsed_time / curr_window_size
class MEDIA_GPU_EXPORT ExponentialMovingAverage {
public:
explicit ExponentialMovingAverage(base::TimeDelta max_window_size);
~ExponentialMovingAverage();
ExponentialMovingAverage(const ExponentialMovingAverage& other) = delete;
ExponentialMovingAverage& operator=(const ExponentialMovingAverage& other) =
delete;
base::TimeDelta curr_window_size() const { return curr_window_size_; }
base::TimeDelta max_window_size() const { return max_window_size_; }
float mean() const { return mean_; }
void update_max_window_size(base::TimeDelta max_window_size) {
max_window_size_ = max_window_size;
}
// Adds a new value to the filter. The T type is casted to the float value.
// Elapsed time is the period between the current and previous sample.
template <typename T>
void AddValue(T value, base::TimeDelta elapsed_time) {
float float_value = static_cast<float>(value);
// The minimum window size is 1ms. This is to avoid division by zero.
curr_window_size_ = std::clamp(curr_window_size_ + elapsed_time,
base::Milliseconds(1), max_window_size_);
float alpha = static_cast<float>(std::min(
elapsed_time.InMillisecondsF() / curr_window_size_.InMillisecondsF(),
1.0));
mean_ += alpha * (float_value - mean_);
mean_square_ += alpha * (float_value * float_value - mean_square_);
}
float GetStdDeviation() const;
private:
// Mean of values.
float mean_ = 0.0f;
// Mean of squared values.
float mean_square_ = 0.0f;
// Effective window size.
base::TimeDelta curr_window_size_;
// Max window size.
base::TimeDelta max_window_size_;
};
} // namespace media
#endif // MEDIA_GPU_EXPONENTIAL_MOVING_AVERAGE_H_