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_