Mozzi  version v2.0
sound synthesis library for Arduino
RollingAverage.h
1 /*
2  * RollingAverage.h
3  *
4  Draws on Arduino Smoothing example,
5  Created 22 April 2007
6  By David A. Mellis <dam@mellis.org>
7  modified 9 Apr 2012
8  by Tom Igoe
9  http://www.arduino.cc/en/Tutorial/Smoothing
10 
11  * This file is part of Mozzi.
12  *
13  * Copyright 2013-2024 Tim Barrass and the Mozzi Team
14  *
15  * Mozzi is licensed under the GNU Lesser General Public Licence (LGPL) Version 2.1 or later.
16  *
17  */
18 
19 #ifndef ROLLINGAVERAGE_H
20 #define ROLLINGAVERAGE_H
21 
22 #include "mozzi_utils.h" // for trailingZeros()
23 
24 
25 /** @ingroup sensortools
26  Calculates a running average over a
27  specified number of the most recent readings.
28  Like Smooth(), this is good for smoothing analog inputs in updateControl().
29  @tparam WINDOW_LENGTH the number of readings to include in the rolling average.
30  It must be a power of two (unless you're averaging floats). The higher the
31  number, the more the readings will be smoothed, but the slower the output
32  will respond to the input.
33 */
34 
35 template <class T, int WINDOW_LENGTH>
36 class
38 
39 public:
40 
41  /** Constructor.
42  @tparam T the type of numbers to average, eg. int, unsigned int, float etc. It will be relatively slow with
43  floating point numbers, as it will use a divide operation for the averaging.
44  Nevertheless, there might be a time when it's useful.
45  @tparam WINDOW_LENGTH the number of readings to keep track of. It must be a power of two (unless
46  you're averaging floats). The higher the number, the more the readings will be
47  smoothed, but the slower the output will respond to the input.
48  @note Watch out for overflows!
49  */
51  {
52  // initialize all the readings to 0:
53  for (int thisReading = 0; thisReading < WINDOW_LENGTH; thisReading++)
54  readings[thisReading] = 0;
55  }
56 
57 
58  /** Give the average of the last WINDOW_LENGTH.
59  @param input a control signal such as an analog input which needs smoothing.
60  @return the smoothed result.
61  @note unsigned int timing 5.7us
62  */
63  T next(T input)
64  {
65  return add(input)>>WINDOW_LENGTH_AS_RSHIFT;
66  }
67 
68 
69 protected:
70 
71  inline
72  T add(T input){
73  // out with the old
74  total -= readings[index];
75  // in with the new
76  total += input;
77  readings[index] = input;
78 
79  // advance and wrap index
80  ++index &= WINDOW_LENGTH -1;
81  return total;
82  }
83 
84 
85 private:
86  T readings[WINDOW_LENGTH]; // the readings from the analog input
87  unsigned int index; // the index of the current reading
88  long total; // the running total
89  const uint8_t WINDOW_LENGTH_AS_RSHIFT;
90 
91 };
92 
93 // no need to show the specialisations
94 /** @cond */
95 
96 /** unsigned int partial specialisation of RollingAverage template.
97 This is needed because unsigned types need to remind (unsigned) for rshift.
98 */
99 template <int WINDOW_LENGTH>
100 class RollingAverage <unsigned int, WINDOW_LENGTH>
101 {
102 public:
103  /** Constructor.
104  @tparam WINDOW_LENGTH A power of two, the number of readings to keep track of.
105  The higher the number, the more the readings will be smoothed, but the slower the output will
106  respond to the input.
107  @note The internal total of all the values being averaged is held in a long (4 uint8_t) integer, to avoid overflowing.
108  However, watch out for overflows if you are averaging a long number types!
109  */
110  RollingAverage():index(0),total(0), WINDOW_LENGTH_AS_RSHIFT(trailingZerosConst(WINDOW_LENGTH))
111  {
112  // initialize all the readings to 0:
113  for (int thisReading = 0; thisReading < WINDOW_LENGTH; thisReading++)
114  readings[thisReading] = 0;
115  }
116 
117  /** Give the average of the last WINDOW_LENGTH.
118  @param a control signal such as an analog input which needs smoothing.
119  @return the smoothed result.
120  @note timing for int 6us
121  */
122  unsigned int next(unsigned int input)
123  {
124  // calculate the average:
125  // this unsigned cast is the only difference between the int and unsigned int specialisations
126  // it tells the shift not to sign extend in from the left
127  return (unsigned)add(input)>>WINDOW_LENGTH_AS_RSHIFT;
128  }
129 
130 protected:
131 
132 
133  inline
134  unsigned int add(unsigned int input){
135  // out with the old
136  total -= readings[index];
137  // in with the new
138  total += input;
139  readings[index] = input;
140 
141  // advance and wrap index
142  ++index &= WINDOW_LENGTH -1;
143  return total;
144  }
145 
146 
147 private:
148  unsigned int readings[WINDOW_LENGTH]; // the readings from the analog input
149  unsigned int index; // the index of the current reading
150  long total; // the running total
151  const uint8_t WINDOW_LENGTH_AS_RSHIFT;
152 
153 };
154 
155 
156 
157 /** float partial specialisation of RollingAverage template*/
158 template <int WINDOW_LENGTH>
159 class RollingAverage <float, WINDOW_LENGTH>
160 {
161 public:
162  /** Constructor.
163  @tparam WINDOW_LENGTH A power of two, the number of readings to keep track of.
164  The higher the number, the more the readings will be smoothed, but the slower the output will
165  respond to the input.
166  @note The internal total of all the values being averaged is held in a long (4 uint8_t) integer, to avoid overflowing.
167  However, watch out for overflows if you are averaging a long number types!
168  */
169  RollingAverage():index(0),total(0.0)
170  {
171  // initialize all the readings to 0:
172  for (int thisReading = 0; thisReading < WINDOW_LENGTH; thisReading++)
173  readings[thisReading] = 0.0;
174  }
175 
176  /** Give the average of the last WINDOW_LENGTH.
177  @param a control signal such as an analog input which needs smoothing.
178  @return the smoothed result.
179  @note timing for float 37us
180  */
181  float next(float input)
182  {
183  // out with the old
184  total -= readings[index];
185  // in with the new
186  total += input;
187  readings[index] = input;
188 
189  // advance and wrap index
190  ++index &= WINDOW_LENGTH -1;
191 
192  // calculate the average:
193  return total/WINDOW_LENGTH;
194  }
195 
196 private:
197  float readings[WINDOW_LENGTH]; // the readings from the analog input
198  unsigned int index; // the index of the current reading
199  float total; // the running total
200 
201 };
202 
203 
204 // no need to show the specialisations
205 /** @endcond
206 */
207 
208 /**
209 @example 03.Sensors/Knob_LDR_x2_WavePacket/Knob_LDR_x2_WavePacket.ino
210 This example demonstrates the RollingAverage class.
211 */
212 
213 #endif // #ifndef ROLLINGAVERAGE_H