mirror of
https://github.com/overte-org/overte.git
synced 2025-05-07 14:39:15 +02:00
213 lines
7.4 KiB
C++
213 lines
7.4 KiB
C++
//
|
|
// MovingMinMaxAvg.h
|
|
// libraries/shared/src
|
|
//
|
|
// Created by Yixin Wang on 7/8/2014
|
|
// Copyright 2013 High Fidelity, Inc.
|
|
//
|
|
// Distributed under the Apache License, Version 2.0.
|
|
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
|
|
//
|
|
|
|
#ifndef hifi_MovingMinMaxAvg_h
|
|
#define hifi_MovingMinMaxAvg_h
|
|
|
|
#include <cassert>
|
|
#include <limits>
|
|
|
|
#include "RingBufferHistory.h"
|
|
|
|
template <typename T>
|
|
class MinMaxAvg {
|
|
public:
|
|
MinMaxAvg()
|
|
: _min(std::numeric_limits<T>::max()),
|
|
_max(std::numeric_limits<T>::min()),
|
|
_average(0.0),
|
|
_samples(0),
|
|
_last(0)
|
|
{}
|
|
|
|
void reset() {
|
|
_min = std::numeric_limits<T>::max();
|
|
_max = std::numeric_limits<T>::min();
|
|
_average = 0.0;
|
|
_samples = 0;
|
|
_last = 0;
|
|
}
|
|
|
|
void update(T sample) {
|
|
if (sample < _min) {
|
|
_min = sample;
|
|
}
|
|
if (sample > _max) {
|
|
_max = sample;
|
|
}
|
|
double totalSamples = _samples + 1;
|
|
_average = _average * ((double)_samples / totalSamples)
|
|
+ (double)sample / totalSamples;
|
|
_samples++;
|
|
|
|
_last = sample;
|
|
}
|
|
|
|
void update(const MinMaxAvg<T>& other) {
|
|
if (other._min < _min) {
|
|
_min = other._min;
|
|
}
|
|
if (other._max > _max) {
|
|
_max = other._max;
|
|
}
|
|
double totalSamples = _samples + other._samples;
|
|
if (totalSamples > 0) {
|
|
_average = _average * ((double)_samples / totalSamples)
|
|
+ other._average * ((double)other._samples / totalSamples);
|
|
} else {
|
|
_average = 0.0f;
|
|
}
|
|
_samples += other._samples;
|
|
}
|
|
|
|
T getMin() const { return _min; }
|
|
T getMax() const { return _max; }
|
|
double getAverage() const { return _average; }
|
|
int getSamples() const { return _samples; }
|
|
double getSum() const { return _samples * _average; }
|
|
T getLast() const { return _last; }
|
|
|
|
private:
|
|
T _min;
|
|
T _max;
|
|
double _average;
|
|
int _samples;
|
|
T _last;
|
|
};
|
|
|
|
template <typename T>
|
|
class MovingMinMaxAvg {
|
|
public:
|
|
// This class collects 3 stats (min, max, avg) over a moving window of samples.
|
|
// The moving window contains _windowIntervals * _intervalLength samples.
|
|
// Those stats are updated every _intervalLength samples collected. When that happens, _newStatsAvaialble is set
|
|
// to true and it's up to the user to clear that flag.
|
|
// For example, if you want a moving avg of the past 5000 samples updated every 100 samples, you would instantiate
|
|
// this class with MovingMinMaxAvg(100, 50). If you want a moving min of the past 100 samples updated on every
|
|
// new sample, instantiate this class with MovingMinMaxAvg(1, 100).
|
|
|
|
|
|
/// use intervalLength = 0 to use in manual mode, where the currentIntervalComplete() function must
|
|
/// be called to complete an interval
|
|
MovingMinMaxAvg(int intervalLength, int windowIntervals)
|
|
: _intervalLength(intervalLength),
|
|
_windowIntervals(windowIntervals),
|
|
_overallStats(),
|
|
_windowStats(),
|
|
_currentIntervalStats(),
|
|
_intervalStats(windowIntervals),
|
|
_newStatsAvailable(false)
|
|
{}
|
|
|
|
void reset() {
|
|
_overallStats.reset();
|
|
_windowStats.reset();
|
|
_currentIntervalStats.reset();
|
|
_intervalStats.clear();
|
|
_newStatsAvailable = false;
|
|
}
|
|
|
|
void setWindowIntervals(int windowIntervals) {
|
|
_windowIntervals = windowIntervals;
|
|
_overallStats.reset();
|
|
_windowStats.reset();
|
|
_currentIntervalStats.reset();
|
|
_intervalStats.setCapacity(_windowIntervals);
|
|
_newStatsAvailable = false;
|
|
}
|
|
|
|
void update(T newSample) {
|
|
// update overall stats
|
|
_overallStats.update(newSample);
|
|
|
|
// update the current interval stats
|
|
_currentIntervalStats.update(newSample);
|
|
|
|
// if the current interval of samples is now full, record its stats into our past intervals' stats
|
|
// NOTE: if _intervalLength is 0 (manual mode), currentIntervalComplete() will not be called here.
|
|
if (_currentIntervalStats.getSamples() == _intervalLength) {
|
|
currentIntervalComplete();
|
|
}
|
|
}
|
|
|
|
/// This function can be called to manually control when each interval ends. For example, if each interval
|
|
/// needs to last T seconds as opposed to N samples, this function should be called every T seconds.
|
|
void currentIntervalComplete() {
|
|
// record current interval's stats, then reset them
|
|
_intervalStats.insert(_currentIntervalStats);
|
|
_currentIntervalStats.reset();
|
|
|
|
// update the window's stats by combining the intervals' stats
|
|
typename RingBufferHistory< MinMaxAvg<T> >::Iterator i = _intervalStats.begin();
|
|
typename RingBufferHistory< MinMaxAvg<T> >::Iterator end = _intervalStats.end();
|
|
_windowStats.reset();
|
|
while (i != end) {
|
|
_windowStats.update(*i);
|
|
++i;
|
|
}
|
|
|
|
_newStatsAvailable = true;
|
|
}
|
|
|
|
bool getNewStatsAvailableFlag() const { return _newStatsAvailable; }
|
|
void clearNewStatsAvailableFlag() { _newStatsAvailable = false; }
|
|
|
|
T getMin() const { return _overallStats.getMin(); }
|
|
T getMax() const { return _overallStats.getMax(); }
|
|
double getAverage() const { return _overallStats.getAverage(); }
|
|
int getSamples() const { return _overallStats.getSamples(); }
|
|
double getSum() const { return _overallStats.getSum(); }
|
|
|
|
T getWindowMin() const { return _windowStats.getMin(); }
|
|
T getWindowMax() const { return _windowStats.getMax(); }
|
|
double getWindowAverage() const { return _windowStats.getAverage(); }
|
|
int getWindowSamples() const { return _windowStats.getSamples(); }
|
|
double getWindowSum() const { return _windowStats.getSum(); }
|
|
|
|
int getWindowIntervals() const { return _windowIntervals; }
|
|
T getCurrentIntervalMin() const { return _currentIntervalStats.getMin(); }
|
|
T getCurrentIntervalMax() const { return _currentIntervalStats.getMax(); }
|
|
double getCurrentIntervalAverage() const { return _currentIntervalStats.getAverage(); }
|
|
int getCurrentIntervalSamples() const { return _currentIntervalStats.getSamples(); }
|
|
double getCurrentIntervalSum() const { return _currentIntervalStats.getSum(); }
|
|
T getCurrentIntervalLastSample() const { return _currentIntervalStats.getLast(); }
|
|
|
|
const MinMaxAvg<T>& getOverallStats() const{ return _overallStats; }
|
|
const MinMaxAvg<T>& getWindowStats() const{ return _windowStats; }
|
|
const MinMaxAvg<T>& getCurrentIntervalStats() const { return _currentIntervalStats; }
|
|
|
|
MinMaxAvg<T> getLastCompleteIntervalStats() const {
|
|
const MinMaxAvg<T>* stats = _intervalStats.getNewestEntry();
|
|
return stats == NULL ? MinMaxAvg<T>() : *stats;
|
|
}
|
|
|
|
bool isWindowFilled() const { return _intervalStats.isFilled(); }
|
|
|
|
private:
|
|
int _intervalLength;
|
|
int _windowIntervals;
|
|
|
|
// these are min/max/avg stats for all samples collected.
|
|
MinMaxAvg<T> _overallStats;
|
|
|
|
// these are the min/max/avg stats for the samples in the moving window
|
|
MinMaxAvg<T> _windowStats;
|
|
|
|
// these are the min/max/avg stats for the samples in the current interval
|
|
MinMaxAvg<T> _currentIntervalStats;
|
|
|
|
// these are stored stats for the past intervals in the window
|
|
RingBufferHistory< MinMaxAvg<T> > _intervalStats;
|
|
|
|
bool _newStatsAvailable;
|
|
};
|
|
|
|
#endif // hifi_MovingMinMaxAvg_h
|