MovingAverage lib v3.2.0 - The Partials Concept
Change Log
The MovingAverage_ArduinoLibrary was born as a side project to solve a problem I had on a school project. As a consequence of the initial purpose, this library suffered from several problems that were tolerable for the project scope. But the moment I decided to publish the library open to anyone on the internet, I perceived how many usability details needed attention to make it usable for a wider range of purposes. So, I see this new version as a milestone. I pretend to repair the holes, clear unnecessary code and add a new feature built from the beginning with the performance and usability principles.
- ✨ Now the average is divided by the number of data points added until the moment. It doesn't start the calculation on the maximum array size anymore. —Due to this change, some methods became obsolete and, therefore, will be removed—
- Reset method is deprecated.
- Using a single number to initialize all array positions is also deprecated.
- Resize method is updated to work in the new paradigm.
- Clear method is updated to reset all array positions to 0, and bring the data points added counter back to 0.
- Documentation is all updated.
The Partials Concept
The Partials are a new way to efficiently calculate a partial average of data.
The get_by_brute method calculates the average of the values requested at each call and returns it immediately, without storing any data in memory.
This solution has linear complexity(O(n)) for the number of requested values in the average(passed as a parameter of the method).
Considering the infinite loop in which the algorithms are executed naturally by the practical use of microcontrollers (eg Arduino), the complexity will always grow in a polynomial way (O(n * m)).
In line with the concept of Dynamic Programming, memory usage can improve the time-consuming efficiency of algorithms because,
by storing your previous results it is possible to avoid wasting iterations spent to recalculate the old results.
Following this idea, the library's moving average uses a variable to hold the sum of all values,
only adding the new value and subtracting the oldest value, so to request the result it is only necessary to compute a division,
that otherwise, would be necessary to add every time the average was requested.
In this sense, the cost exchange becomes:
-
Brute Sum
Add new data - O(1) to write in the array
Average - O(n) to calculate the entire array per call -
Dynamic Sum
Add new data - O(2) = O(1) to write to array and add to sum
Calculate the mean - O(1) to calculate the division between sum and n_points
The idea of the new feature, therefore, is to recreate this behavior for the sums of partial sizes of the array, without creating the need to double the memory spent,
in the case of creating multiple copies of the same Moving Average structure, and without doubling the time spent adding these duplicates to the arrays.
The Partials concept was designed and reviewed by @AlexandreHiroyuki and implemented by @Amorim33