Advertisement
Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- /*\
- |*| This code demonstrates how to calculate averages over an
- |*| incoming series of values without requiring an array of
- |*| any previous values and it also starts producing the average
- |*| immdiately for an N-sample-size window before N samples
- |*| have arrived.
- |*|
- |*| It also contains functions and methods to perform the same operations
- |*| using an N member array the old-fashioned way in order to be able to
- |*| compare the results of the two approaches.
- |*|
- |*| Original code (c) Trent M. Wyatt (ripred)
- \*/
- #include <stdlib.h>
- #include <memory.h>
- #include <math.h>
- // ========================================================================================
- // runtime parameters and test array data for comparison
- // set to true to randomly drift the samples up and down
- // set to false to select purely random sample values
- bool drift = true;
- // running average set size
- size_t const set_size = 101;
- // number of samples to test
- size_t const test_size = 100;
- // amount to scale up/down when drifting
- long scale = 1;
- // variables and functions used for brute force averaging comparison
- double val_set[set_size];
- double val_total;
- double val_avg;
- size_t val_num;
- size_t head;
- size_t tail;
- // ========================================================================================
- // variables used for array-less averaging
- volatile double avg;
- size_t count;
- // standard deviation
- double deviation;
- // ==============================================================
- #ifndef UNUSED
- #define UNUSED(A) do{(void)(A);}while(false);
- #endif
- inline long min(const long &a, const long &b) {
- if (a < b) return a;
- return b;
- }
- inline long max(const long &a, const long &b) {
- if (a > b) return a;
- return b;
- }
- /// Fake Serial port methods for use on a PC when writing,
- /// testing, and using this code.
- #ifndef ARDUINO
- #include <iostream>
- struct Serial {
- static void print(double r, int prec=2) {
- char buff[32];
- sprintf(buff, "%.*f", prec, r);
- std::cout << buff;
- }
- static void println(double r, int prec=2) {
- char buff[32];
- sprintf(buff, "%.*f\n", prec, r);
- std::cout << buff;
- }
- static void print(const char *s) {
- std::cout << s;
- }
- static void println(const char *s="") {
- std::cout << s << "\n";
- }
- static void print(char *s) {
- std::cout << s;
- }
- static void println(char *s) {
- std::cout << s << "\n";
- }
- } Serial;
- long random(unsigned long min, unsigned long max) {
- return min + (rand() % max);
- }
- long random(unsigned long max) {
- return rand() % max;
- }
- void randomSeed(unsigned long seed) {
- srand(seed);
- }
- #endif // end of fake PC-side proxy functions, classes, and methods
- // ========================================================================================
- // This is code for the inefficient way of calculating an average for
- // the last N samples of a series of incoming values.
- // functions used for brute force averaging
- // add a new value to the sample array
- double val_add(double val) {
- val_total += val;
- val_set[head++] = val;
- head %= set_size;
- if (++val_num >= set_size) {
- val_total -= val_set[tail++];
- tail %= set_size;
- }
- val_avg = val_total / ((val_num >= set_size) ? set_size : val_num);
- return val_avg;
- }
- // calculate the average value for the sample array
- double val_calc() {
- return val_avg;
- }
- // add a new value to the array-less smoothing
- double val_add_smooth(double val) {
- size_t num = ++count;
- if (num > set_size) {
- num = set_size;
- }
- double run_coef = double(num - 1) / num;
- double val_coef = 1.0 / num;
- avg = (avg * run_coef) + (val * val_coef);
- return avg;
- }
- double val_calc_smooth() {
- return avg;
- }
- void restart(uint32_t seed) {
- // initialize the brute force variables
- for (size_t i=0; i < set_size; i++) {
- val_set[i] = drift ? 50.0 : 0.0;
- }
- val_avg = drift ? 50.0 : 0.0;
- val_num = 0;
- head = 0;
- tail = 0;
- // initialize the array-less variables
- avg = drift ? 50.0 : 0.0;
- count = 0;
- randomSeed(seed);
- }
- double rnd_sample() {
- long val = 0;
- if (drift) {
- long incr = random(3) - 1; // -1 / 0 / +1
- val = val_avg + (incr * scale);
- val = (val < 0) ? 0 : val;
- val = (val > 99) ? 99 : val;
- }
- else {
- val = random(100);
- }
- return val;
- }
- void run_test(uint32_t seed) {
- char buff[64];
- Serial.println("Value, Array, NoArray");
- restart(seed);
- for (size_t i=0; i < test_size; i++) {
- double val = rnd_sample();
- val_add(val);
- val_add_smooth(val);
- sprintf(buff, "%6.2f %6.2f %6.2f", val, val_avg, avg);
- Serial.println(buff);
- }
- // Calculate the standard deviation:
- // 1) get mean average
- double meanAvg = val_total / test_size;
- // 2) get squared average
- double meanSqr = 0.0;
- randomSeed(seed);
- for (size_t i=0; i < test_size; i++) {
- double val = rnd_sample() - meanAvg;
- meanSqr += val * val;
- }
- // 3) get mean of the squared differences
- meanSqr /= test_size;
- // 4) get the square root
- deviation = sqrt(meanSqr);
- }
- int main(int argc, char *argv[]) {
- UNUSED(argc);
- UNUSED(argv);
- run_test(time(nullptr));
- Serial.println();
- Serial.print(" Brute Force Avg: ");
- Serial.println(val_avg, 5);
- Serial.print(" Smooth Avg: ");
- Serial.println( avg, 5);
- Serial.print("Standard Deviation: ");
- Serial.println(deviation, 5);
- return 0;
- }
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement