blob: 23a1b06d70103dab3dc9796e2668a13e674940bf [file] [log] [blame]
Philipp Schrader29d54f22016-04-02 22:14:48 +00001#ifndef FRC971_ZEROING_AVERAGER_H_
2#define FRC971_ZEROING_AVERAGER_H_
3
4#include <algorithm>
5#include <array>
6#include <stdint.h>
7
James Kuszmauld3f9eb22020-01-12 15:02:07 -08008#include "Eigen/Dense"
9#include "glog/logging.h"
10
Philipp Schrader29d54f22016-04-02 22:14:48 +000011namespace frc971 {
12namespace zeroing {
13
14// Averages a set of given numbers. Numbers are given one at a time. Once full
15// the average may be requested.
James Kuszmauld3f9eb22020-01-12 15:02:07 -080016// TODO(james): Look at deduplicating this with some of the work in the
17// MoveDetector.
18template <typename Scalar, size_t num_samples, int rows_per_sample = 1>
Philipp Schrader29d54f22016-04-02 22:14:48 +000019class Averager {
20 public:
James Kuszmauld3f9eb22020-01-12 15:02:07 -080021 typedef Eigen::Matrix<Scalar, rows_per_sample, 1> Vector;
James Kuszmaulb1e29372020-02-11 16:55:36 -080022 Averager() {
23 for (Vector &datum : data_) {
24 datum.setZero();
25 }
26 }
Philipp Schrader29d54f22016-04-02 22:14:48 +000027 // Adds one data point to the set of data points to be averaged.
James Kuszmauld3f9eb22020-01-12 15:02:07 -080028 // If more than "num_samples" samples are added, they will start overwriting
Philipp Schrader29d54f22016-04-02 22:14:48 +000029 // the oldest ones.
James Kuszmauld3f9eb22020-01-12 15:02:07 -080030 void AddData(Scalar data) {
31 CHECK_EQ(1, rows_per_sample);
32 AddData(Vector(data));
33 }
34 void AddData(const Vector &data) {
Philipp Schrader29d54f22016-04-02 22:14:48 +000035 data_[data_point_index_] = data;
James Kuszmauld3f9eb22020-01-12 15:02:07 -080036 num_data_points_ = std::min(num_samples, num_data_points_ + 1);
37 data_point_index_ = (data_point_index_ + 1) % num_samples;
Philipp Schrader29d54f22016-04-02 22:14:48 +000038 }
39
40 // Returns the average of the data points.
James Kuszmauld3f9eb22020-01-12 15:02:07 -080041 Vector GetAverage() const {
Philipp Schrader29d54f22016-04-02 22:14:48 +000042 if (num_data_points_ == 0) {
James Kuszmauld3f9eb22020-01-12 15:02:07 -080043 return Vector::Zero();
Philipp Schrader29d54f22016-04-02 22:14:48 +000044 }
45
James Kuszmauld3f9eb22020-01-12 15:02:07 -080046 Vector average;
47 average.setZero();
48 for (const Vector &data : data_) {
Philipp Schrader29d54f22016-04-02 22:14:48 +000049 average += data;
50 }
51 return average / num_data_points_;
52 }
53
James Kuszmauld3f9eb22020-01-12 15:02:07 -080054 // Return the difference between the min and max values in the data buffer.
55 Scalar GetRange() const {
56 if (num_data_points_ == 0) {
57 return 0.0;
58 }
59 Vector min_value;
60 min_value.setConstant(std::numeric_limits<Scalar>::max());
61 Vector max_value;
62 max_value.setConstant(std::numeric_limits<Scalar>::lowest());
63 // The array will always fill up starting at zero, so we can iterate from
64 // zero safely.
65 for (size_t ii = 0; ii < num_data_points_; ++ii) {
66 const Vector &value = data_[ii];
67 min_value = min_value.cwiseMin(value);
68 max_value = max_value.cwiseMax(value);
69 }
70 return (max_value - min_value).maxCoeff();
71 }
Philipp Schrader29d54f22016-04-02 22:14:48 +000072
James Kuszmauld3f9eb22020-01-12 15:02:07 -080073 void Reset() {
74 num_data_points_ = 0;
75 data_point_index_ = 0;
76 }
77
78 // Returns true when we've gathered num_samples data points.
79 bool full() const { return num_data_points_ >= num_samples; };
80
81 size_t size() const { return num_samples; }
Philipp Schrader29d54f22016-04-02 22:14:48 +000082
83 private:
84 // Data points to be averaged.
James Kuszmauld3f9eb22020-01-12 15:02:07 -080085 std::array<Vector, num_samples> data_;
Philipp Schrader29d54f22016-04-02 22:14:48 +000086 // Which data point in "data_" will be filled in next.
87 size_t data_point_index_ = 0;
88 // Number of data points added via AddData().
89 size_t num_data_points_ = 0;
90};
91
92} // namespace zeroing
93} // namespace frc971
94
95#endif // FRC971_ZEROING_AVERAGER_H_