Pages: 1 [2]   Go Down
Author Topic: RunningAverage Class on playground (updated)  (Read 6032 times)
0 Members and 1 Guest are viewing this topic.
Brasil
Offline Offline
Full Member
***
Karma: 4
Posts: 125
View Profile
WWW
 Bigger Bigger  Smaller Smaller  Reset Reset

Take a look at my Library, that works perfecly for a moving average...

https://github.com/ivanseidel/Gaussian
Logged


Mid-Atlantic, USA
Offline Offline
God Member
*****
Karma: 30
Posts: 514
"Remember kids, the only difference between Science and screwing around is writing it down." - Adam Savage
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

[... snipped ...]
The results of these measurements can be found in the attached pdf file "Diff_Pressure_averaged_median.pdf". Now there is something strange about the averaging value. The buffer size seems not to change.  even the 200 value buffer size ("RunningMedian diff_p_RA(200); ") looks more like the 25 or even 10. The RunningMedian Code I used is from your (Rob Tillaart) github repository. Furthermore, I expected something else from the RunningMedian. Let me know what you think.

Best regards,
Jan

P.S.: I now added the raw data of these measurements.


If you look in RunningMedian.h you will see
Code:
#define MEDIAN_MAX_SIZE     19          // adjust if needed

If you don't change that, requesting a median array size of anything larger than 19 will only give you a 19 element array to run your medians and averages against. Did you change that line before compiling your sketch that requests a 200 element array?
Logged


Offline Offline
Jr. Member
**
Karma: 1
Posts: 61
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

Hi there,

thank you  Sembazuru for pointing that out.  I guess that means I should have set "MEDIAN_MAX_SIZE" to somewhat around 200 and then define a
Code:
RunningMedian samples = RunningMedian(50);
Well, as I learned yesterday the RunningMedian takes more processing time as it needs to sort the array. As I´m taking my measurements each 50ms I guess that would not be an option - especially not with a large array size (which seem absolutley logical now to limit the array size). I´m now using the RunningAverage-library as I found my optimum array size for my setup via the tests I did. So everything is fine now. But I still wonder if the array size can be made user configurable during runtime.

@ivanseidel: Thank you for pointing me to your library. But I allready implemented the RunningAverage-library by Rob Tillaart and only needed some fine tuning (and understanding on whats going on behind the scenes). The last results I got were  suficiently constant. I just needed to adjust the array size to get the timing right (because a large array size means smoother data but more timeleg  on steep gradients ).

Best regards,
Jan 
Logged

Global Moderator
Netherlands
Offline Offline
Shannon Member
*****
Karma: 211
Posts: 13478
In theory there is no difference between theory and practice, however in practice there are many...
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

I have tried to reproduce the getMedian() error but I could not. Using the [partial] data from your zip file I got no errors.

A possible cause I cannot verify is how much free RAM you have as it might be a problem during allocating the internal arrays as the lib uses dynamic memory. That could explain the behaviour seen.
Logged

Rob Tillaart

Nederlandse sectie - http://arduino.cc/forum/index.php/board,77.0.html -
(Please do not PM for private consultancy)

Global Moderator
Netherlands
Offline Offline
Shannon Member
*****
Karma: 211
Posts: 13478
In theory there is no difference between theory and practice, however in practice there are many...
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

Quote
But I still wonder if the array size can be made user configurable during runtime.
The lib could be rewritten to use dynamic memory and you could reallocate the memory. However as an Arduino has very limited RAM this gives fragmented (useless) memory quite fast.

that said, you might try with largest allocation first and gradually decrease the size to an optimum. Then the reallocation should less fragment the memory in theory ...


Logged

Rob Tillaart

Nederlandse sectie - http://arduino.cc/forum/index.php/board,77.0.html -
(Please do not PM for private consultancy)

Brasil
Offline Offline
Full Member
***
Karma: 4
Posts: 125
View Profile
WWW
 Bigger Bigger  Smaller Smaller  Reset Reset

Quote
But I still wonder if the array size can be made user configurable during runtime.
The lib could be rewritten to use dynamic memory and you could reallocate the memory. However as an Arduino has very limited RAM this gives fragmented (useless) memory quite fast.

that said, you might try with largest allocation first and gradually decrease the size to an optimum. Then the reallocation should less fragment the memory in theory ...


That's true, but it's already implemented with my library (I use a self made LinkedList). Worth a try =)

You can change the size whenever you want, and it will not crash the code.

Also, you can use it with basic numbers 10 = Gaussian(10); or with numbers with variance: Gaussian(10,variance);, witch gives you much more flexibility on the average...

Just a tip... take a look at the documentation.

https://github.com/ivanseidel/Gaussian
Logged


Offline Offline
Newbie
*
Karma: 0
Posts: 8
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

What is the easiest way to modify RunningAverage Class to calculate 4 average variables simultaneously?

 smiley-eek-blue
Logged

Brasil
Offline Offline
Full Member
***
Karma: 4
Posts: 125
View Profile
WWW
 Bigger Bigger  Smaller Smaller  Reset Reset

Code:
GaussianAverage avg1(NUM_AVGS);
GaussianAverage avg2(NUM_AVGS);
GaussianAverage avg3(NUM_AVGS);
GaussianAverage avg4(NUM_AVGS);

//In code to add values to the moving average
avg1 += 10;
avg2 += xx...;

// Then process and get the result
float reault1 = avg1.process().mean;

Library: http://github.com/ivanseidel/Gaussian
Logged


Global Moderator
Netherlands
Offline Offline
Shannon Member
*****
Karma: 211
Posts: 13478
In theory there is no difference between theory and practice, however in practice there are many...
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

Create multiple separate objects

Code: (not tested)
//
//    FILE: runningAverageTest.ino
//  AUTHOR: Rob Tillaart
//    DATE: 2014-05-07
//
// PUPROSE: show working of runningAverage
//

#include "RunningAverage.h"

RunningAverage RA0(15);
RunningAverage RA1(13);
RunningAverage RA2(11);
RunningAverage RA3(9);
RunningAverage RA4(7);
RunningAverage RA5(5);

int samples = 0;

void setup(void)
{
  Serial.begin(115200);
  Serial.println("Demo RunningAverage lib");
  Serial.print("Version: ");
  Serial.println(RUNNINGAVERAGE_LIB_VERSION);

  clearAll();
}

void loop(void)
{
  RA0.addValue(analogRead(A0));
  RA1.addValue(analogRead(A1));
  RA2.addValue(analogRead(A2));
  RA3.addValue(analogRead(A3));
  RA4.addValue(analogRead(A4));
  RA5.addValue(analogRead(A5));

  Serial.print(RA0.getAverage(), 3);
  Serial.print(",");
  Serial.print(RA1.getAverage(), 3);
  Serial.print(",");
  Serial.print(RA2.getAverage(), 3);
  Serial.print(",");
  Serial.print(RA3.getAverage(), 3);
  Serial.print(",");
  Serial.print(RA4.getAverage(), 3);
  Serial.print(",");
  Serial.println(RA5.getAverage(), 3);

  samples++;

  if (samples == 300)
  {
    samples = 0;
    clearAll();
  }
  delay(100);
}

void clearAll()
{
  RA0.clear();  
  RA1.clear();  
  RA2.clear();  
  RA3.clear();  
  RA4.clear();  
  RA5.clear();  
}
running this program should generate output you can graph in a spreadsheet giving insight in the effects of the internal buffer.
Logged

Rob Tillaart

Nederlandse sectie - http://arduino.cc/forum/index.php/board,77.0.html -
(Please do not PM for private consultancy)

Global Moderator
Netherlands
Offline Offline
Shannon Member
*****
Karma: 211
Posts: 13478
In theory there is no difference between theory and practice, however in practice there are many...
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset


Or use an array of objects.  Note the allocation is somewhat different

(note not tested, highly experimental)

Code:
//
//    FILE: runningAverageTest.ino
//  AUTHOR: Rob Tillaart
//    DATE: 2014-05-07
//
// PUPROSE: show working of runningAverage
//

#include "RunningAverage.h"

RunningAverage *RA[6];  // 6 pointers to RA objects
int pin[6] = {
  A0, A1, A2, A3, A4, A5 };
int size[6] = { 15, 13, 11, 9, 7, 5 };

int samples = 0;

void setup(void)
{
  Serial.begin(115200);
  Serial.println("Demo RunningAverage lib");
  Serial.print("Version: ");
  Serial.println(RUNNINGAVERAGE_LIB_VERSION);

  for (int i=0;i<6; i++)
  {
    RA[i] = new RunningAverage( size[i] );
    RA[i]->clear();
  }
}

void loop(void)
{
  for (int i=0; i<6; i++)
  {
    RA[i]->addValue(analogRead(pin[i]));
  }

  for (int i=0; i<6; i++)
  {
    Serial.print(RA[i]->getAverage(), 3);
    Serial.print(",");
  }
  Serial.println();

  samples++;
  if (samples == 300)
  {
    samples = 0;
    for (int i=0;i<6; i++)
    {
      RA[i]->clear();
    }
  }
  delay(100);
}
Logged

Rob Tillaart

Nederlandse sectie - http://arduino.cc/forum/index.php/board,77.0.html -
(Please do not PM for private consultancy)

Offline Offline
Newbie
*
Karma: 0
Posts: 2
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

I am having overflow errors in visual micro debugger in ms visual studio.

I have 15 instances of RunningAverage sized from 24 to 60.

I am getting random ovf errors on calls to getAverage().

S = savg.getAverage() generates an ovf error at random times.
Logged

Offline Offline
Newbie
*
Karma: 0
Posts: 2
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

I am having overflow errors in visual micro debugger in ms visual studio.

I have 15 instances of RunningAverage sized from 24 to 60.

I am getting random ovf errors on calls to getAverage().

S = savg.getAverage() generates an ovf error at random times.

here is the code

Code:
/*
 This code creates a schedule for events every second, minute & hour
 */

#include <Metro.h> //Include Metro library

// Create metro objects and set intervals to one second, minute & hour
Metro Second = Metro(1000); //one second
Metro Minute = Metro(2000); //one minute
Metro Hour = Metro(4000); //one hour

#include "RunningAverage.h"

//Create running average objects
RunningAverage Sensor1Seconds(60);
RunningAverage Sensor1Minutes(60);
RunningAverage Sensor1Hours(24);
RunningAverage Sensor2Seconds(60);
RunningAverage Sensor2Minutes(60);
RunningAverage Sensor2Hours(24);
RunningAverage Sensor3Seconds(60);
RunningAverage Sensor3Minutes(60);
RunningAverage Sensor3Hours(24);
RunningAverage Sensor4Seconds(60);
RunningAverage Sensor4Minutes(60);
RunningAverage Sensor4Hours(24);
RunningAverage Sensor5Seconds(60);
RunningAverage Sensor5Minutes(60);
RunningAverage Sensor5Hours(24);


//variables to track time elapsed
int seconds = 0;
int minutes = 0;
int hours = 0;
int led = 13;

void blink()
{
digitalWrite(led,1);
int m = millis();
while(millis() < m+500);
//for(int n=1;n<100000;n=++n);
digitalWrite(led,0);
}

void setup()
{
    pinMode(led,OUTPUT);
blink();
Sensor1Seconds.clear();
Sensor1Minutes.clear();
Sensor1Hours.clear();
Sensor2Seconds.clear();
Sensor2Minutes.clear();
Sensor2Hours.clear();
Sensor3Seconds.clear();
Sensor3Minutes.clear();
Sensor3Hours.clear();
Sensor4Seconds.clear();
Sensor4Minutes.clear();
Sensor4Hours.clear();
Sensor5Seconds.clear();
Sensor5Minutes.clear();
Sensor5Hours.clear();
}

float s1=0;
float s2=0;
float s3=0;
float s4=0;
float s5=0;
float m1=0;
float m2=0;
float m3=0;
float m4=0;
float m5=0;
float h1=0;
float h2=0;
float h3=0;
float h4=0;
float h5=0;
float rn;

void SensorSecondUpdate() {
rn = random(0, 1000);
        Sensor1Seconds.addValue(rn);
s1 = Sensor1Seconds.getAverage();
rn = random(0, 1000);
        Sensor2Seconds.addValue(rn);
s2 = Sensor2Seconds.getAverage();
rn = random(0, 1000);
        Sensor3Seconds.addValue(rn);
s3 = Sensor3Seconds.getAverage();
rn = random(0, 1000);
        Sensor4Seconds.addValue(rn);
s4 = Sensor4Seconds.getAverage();
rn = random(0, 1000);
        Sensor5Seconds.addValue(rn);
s5 = Sensor5Seconds.getAverage();

}

void SensorMinuteUpdate() {
float x = Sensor1Seconds.getAverage();
Sensor1Minutes.addValue(x);
m1 = Sensor1Minutes.getAverage();
Sensor1Seconds.clear();
x = Sensor2Seconds.getAverage();
Sensor2Minutes.addValue(x);
m2 = Sensor2Minutes.getAverage();
Sensor2Seconds.clear();
x=Sensor3Seconds.getAverage();
Sensor3Minutes.addValue(x);
m3 = Sensor3Minutes.getAverage();
Sensor3Seconds.clear();
x = Sensor4Seconds.getAverage();
Sensor4Minutes.addValue(x);
m4 = Sensor4Minutes.getAverage();
Sensor4Seconds.clear();
x=Sensor5Seconds.getAverage();
Sensor5Minutes.addValue(x);
m5 = Sensor5Minutes.getAverage();
Sensor5Seconds.clear();
}

void SensorHourUpdate() {
float x=Sensor1Minutes.getAverage();
Sensor1Hours.addValue(x);
h1 = Sensor1Hours.getAverage();
x=Sensor2Minutes.getAverage();
Sensor2Hours.addValue(x);
h2 = Sensor2Hours.getAverage();
x=Sensor3Minutes.getAverage();
Sensor3Hours.addValue(x);
h3 = Sensor3Hours.getAverage();
x=Sensor4Minutes.getAverage();
Sensor4Hours.addValue(x);
h4 = Sensor4Hours.getAverage();
x=Sensor5Minutes.getAverage();
Sensor5Hours.addValue(x);
h5 = Sensor5Hours.getAverage();
}


void loop()
{

  if (Second.check() == 1) { // check if its been a second
seconds = ++seconds;
SensorSecondUpdate();
blink();
//put stuff here to do every second
  }

    if (Minute.check() == 1) { // check if its been a minute
minutes = ++minutes;
SensorMinuteUpdate();
//put stuff here to do every minute
  }

if (Hour.check() == 1) { // check if its been an hour
hours = ++hours;
SensorHourUpdate();

//put stuff here to do every hour
  }

}
moderatore: added code tags - # button above smileys
« Last Edit: July 02, 2014, 12:06:51 pm by robtillaart » Logged

Global Moderator
Netherlands
Offline Offline
Shannon Member
*****
Karma: 211
Posts: 13478
In theory there is no difference between theory and practice, however in practice there are many...
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

you have 10 RA objects of size 60 and 5 RA objects of size 24, that is a lot of memory (at least for an UNO)

Every object has 10 bytes local vars and 4 bytes per element.

15 objects = 150 bytes
10 x 60 x 4 = 2400 bytes
5 x 24 x 4 = 480 bytes
--------------------
roughly 3000+ bytes of SRAM

What board are you using?
If it is an UNO, it does not have that much memory, ==> Get a MEGA.

Learning point for me: The RA class has no error handling or state to see its "health".
Analysis:
The class does not check if the allocation of the needed "arrays" succeed, but the code behaves as if it does so.
That means that only the first RA object are healthy and the others have internal pointers pointing to (probably) NULL.

To make it more robust the interface of the Class could change to have a method
Code:
bool begin(uint8_t size) ;
that returns true is size elements could be allocated.
The allocation should be removed from the constructor.
// this is a breaking interface change

Another alternative is to have a method
Code:
uint8_t internalSize();

That returns the size of the internal size. This returns zero if allocation had failed and the internal size otherwise.
// this would not break the existing interface and would increase footprint not much.
« Last Edit: July 02, 2014, 12:24:10 pm by robtillaart » Logged

Rob Tillaart

Nederlandse sectie - http://arduino.cc/forum/index.php/board,77.0.html -
(Please do not PM for private consultancy)

Global Moderator
Netherlands
Offline Offline
Shannon Member
*****
Karma: 211
Posts: 13478
In theory there is no difference between theory and practice, however in practice there are many...
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

Updated the library to version 0.2.04 ( 0.2.03 was skipped - dev only version)

To solve the problem of Chrismolloy above I added code to check if the internal array could be allocated. The previous 0.2.02 version was really opportunistic smiley-wink
If the array cannot be allocated the size of the array is set to 0, the new method getSize() can be used to check if the allocation worked. Having an internal size of zero the Class cannot accept new values and the average will be NAN as it cannot be calculated.

The size of the lib increased about 20 bytes, which is imho acceptable for this "safety net".

As always remarks and comments are welcome.

- http://playground.arduino.cc/Main/RunningAverage -
- https://github.com/RobTillaart/Arduino/tree/master/libraries/RunningAverage -
« Last Edit: July 03, 2014, 03:21:03 pm by robtillaart » Logged

Rob Tillaart

Nederlandse sectie - http://arduino.cc/forum/index.php/board,77.0.html -
(Please do not PM for private consultancy)

Pages: 1 [2]   Go Up
Jump to: