blob: b6ff09db3f7375144179d797f124f592f3865048 [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;
Philipp Schrader29d54f22016-04-02 22:14:48 +000022 // Adds one data point to the set of data points to be averaged.
James Kuszmauld3f9eb22020-01-12 15:02:07 -080023 // If more than "num_samples" samples are added, they will start overwriting
Philipp Schrader29d54f22016-04-02 22:14:48 +000024 // the oldest ones.
James Kuszmauld3f9eb22020-01-12 15:02:07 -080025 void AddData(Scalar data) {
26 CHECK_EQ(1, rows_per_sample);
27 AddData(Vector(data));
28 }
29 void AddData(const Vector &data) {
Philipp Schrader29d54f22016-04-02 22:14:48 +000030 data_[data_point_index_] = data;
James Kuszmauld3f9eb22020-01-12 15:02:07 -080031 num_data_points_ = std::min(num_samples, num_data_points_ + 1);
32 data_point_index_ = (data_point_index_ + 1) % num_samples;
Philipp Schrader29d54f22016-04-02 22:14:48 +000033 }
34
35 // Returns the average of the data points.
James Kuszmauld3f9eb22020-01-12 15:02:07 -080036 Vector GetAverage() const {
Philipp Schrader29d54f22016-04-02 22:14:48 +000037 if (num_data_points_ == 0) {
James Kuszmauld3f9eb22020-01-12 15:02:07 -080038 return Vector::Zero();
Philipp Schrader29d54f22016-04-02 22:14:48 +000039 }
40
James Kuszmauld3f9eb22020-01-12 15:02:07 -080041 Vector average;
42 average.setZero();
43 for (const Vector &data : data_) {
Philipp Schrader29d54f22016-04-02 22:14:48 +000044 average += data;
45 }
46 return average / num_data_points_;
47 }
48
James Kuszmauld3f9eb22020-01-12 15:02:07 -080049 // Return the difference between the min and max values in the data buffer.
50 Scalar GetRange() const {
51 if (num_data_points_ == 0) {
52 return 0.0;
53 }
54 Vector min_value;
55 min_value.setConstant(std::numeric_limits<Scalar>::max());
56 Vector max_value;
57 max_value.setConstant(std::numeric_limits<Scalar>::lowest());
58 // The array will always fill up starting at zero, so we can iterate from
59 // zero safely.
60 for (size_t ii = 0; ii < num_data_points_; ++ii) {
61 const Vector &value = data_[ii];
62 min_value = min_value.cwiseMin(value);
63 max_value = max_value.cwiseMax(value);
64 }
65 return (max_value - min_value).maxCoeff();
66 }
Philipp Schrader29d54f22016-04-02 22:14:48 +000067
James Kuszmauld3f9eb22020-01-12 15:02:07 -080068 void Reset() {
69 num_data_points_ = 0;
70 data_point_index_ = 0;
71 }
72
73 // Returns true when we've gathered num_samples data points.
74 bool full() const { return num_data_points_ >= num_samples; };
75
76 size_t size() const { return num_samples; }
Philipp Schrader29d54f22016-04-02 22:14:48 +000077
78 private:
79 // Data points to be averaged.
James Kuszmauld3f9eb22020-01-12 15:02:07 -080080 std::array<Vector, num_samples> data_;
Philipp Schrader29d54f22016-04-02 22:14:48 +000081 // Which data point in "data_" will be filled in next.
82 size_t data_point_index_ = 0;
83 // Number of data points added via AddData().
84 size_t num_data_points_ = 0;
85};
86
87} // namespace zeroing
88} // namespace frc971
89
90#endif // FRC971_ZEROING_AVERAGER_H_