Anemometer averaging speeds

I’ve been working on an aneometer for arduino using a Hall effect sensor, and I’ve gotten it to output current wind speeds to an LCD Display. What I’d like to add to this, is an output of average wind speed.

Heres what I have so far

#include <LiquidCrystal.h>

LiquidCrystal lcd(7, 8, 9, 10, 11, 12);

int pin = 2;
float mph; //variable for current mph
float ave; //variable for average mph
float duration; //variable for time between sensor pulses
int count = 0;

void setup(){
pinMode(pin, INPUT);
lcd.begin(16, 2);
Serial.begin(9600);
}

void loop(){
duration = pulseIn(pin, HIGH); //count how long pin is HIGH
mph = (0.00004412)/(duration/3600000000); //calculate mph
lcd.print(“Current:”);
lcd.setCursor(9, 0);
lcd.print(mph);
lcd.setCursor(13, 0);
lcd.print(“mph”);
lcd.setCursor(0, 1);
lcd.print(“Average:”);
lcd.setCursor(9, 1);
lcd.print(ave);
lcd.setCursor(13, 1);
lcd.print(“mph”);
}

Someone suggested I use an interrupt, but I’m not sure how to implement that information, either into what I have now or into a new program.

#include <LiquidCrystal.h>

LiquidCrystal lcd(7, 8, 9, 10, 11, 12);

int pin = 2;
float mph; //variable for current mph
float ave; //variable for average mph
float duration; //variable for time between sensor pulses
int count = 0;

void setup(){
  pinMode(pin, INPUT);
  lcd.begin(16, 2);
  Serial.begin(9600);
  duration = pulseIn(pin, HIGH); //count how long pin is HIGH
  mph = (0.00004412)/(duration/3600000000); //calculate mph
  ave = mph; //init to a value
}

void loop(){
  duration = pulseIn(pin, HIGH); //count how long pin is HIGH
  mph = (0.00004412)/(duration/3600000000); //calculate mph
  ave += mph;
  ave /= 2; //running average where i = 2
  lcd.print("Current:");
  lcd.setCursor(9, 0);
  lcd.print(mph);
  lcd.setCursor(13, 0);
  lcd.print("mph");
  lcd.setCursor(0, 1);
  lcd.print("Average:");
  lcd.setCursor(9, 1);
  lcd.print(ave);
  lcd.setCursor(13, 1);
  lcd.print("mph");
}

I see where you're going with this.

I tried the code you posted, along with some variations, but arduino still isn't outputting an average.

I also tried having the sensor only calculate two wind speeds to see if the issue was due to the i=2 constraint (ave /= 2), but it still wasn't working.

but arduino still isn't outputting an average.

It isn't displaying a number, or the number it displays is not the average wind speed, or the number doesn't appear to mean anything. Please be a bit clearer in just what the problem is. And, post your latest code.

First I tried just copying/pasting the code AlphaBeta posted to see if the additions to my original code would output something, but passing the magnet in front of the Hall sensor only returned current mph.
Then I tried removing the duplicate lines of code from either setup() or loop() to see if that would change anything, but still only returned current mph.

I also tried adding

ave += mph;

into the loop() to see if I could just get a running total of mph, which still only returned current mph.

void loop(){
duration = pulseIn(pin, HIGH); //count how long pin is HIGH
mph = (0.00004412)/(duration/3600000000); //calculate mph
ave += mph;
lcd.print(“Current:”);
lcd.setCursor(9, 0);
lcd.print(mph);
lcd.setCursor(13, 0);
lcd.print(“mph”);
lcd.setCursor(0, 1);
lcd.print(“Average:”);
lcd.setCursor(9, 1);
lcd.print(ave);
lcd.setCursor(13, 1);
lcd.print(“mph”);
}

The full code:

#include <LiquidCrystal.h>

LiquidCrystal lcd(7, 8, 9, 10, 11, 12);

int pin = 2;
float mph; //variable for current mph
float ave = 0.00; //variable for average mph
float duration; //variable for time between sensor pulses
int count = 0;

void setup(){
pinMode(pin, INPUT);
lcd.begin(16, 2);
Serial.begin(9600);
}

void loop(){
duration = pulseIn(pin, HIGH); //count how long pin is HIGH
mph = (0.00004412)/(duration/3600000000); //calculate mph
ave = mph;
ave += mph;
lcd.print(“Current:”);
lcd.setCursor(9, 0);
lcd.print(mph);
lcd.setCursor(13, 0);
lcd.print(“mph”);
lcd.setCursor(0, 1);
lcd.print(“Average:”);
lcd.setCursor(9, 1);
lcd.print(ave);
lcd.setCursor(13, 1);
lcd.print(“mph”);
}

Gives me current mph, but the “ave” output seems to be random numbers.

  ave = mph;
  ave += mph;

Gives me current mph, but the "ave" output seems to be random numbers.

First you set ave to mph, then you add mph again. ave should be twice mph.

If you just want some average with little need for saving values, you could calculate an exponential moving average. That sounds very scientific and the linked page will give you enough math to create a stack overflow, but it's in reality dead simple. First the code:

const float coeff = 0.1;
...
loop(){
...
mph = ....;
ave = mph * coeff + ave * (1 - coeff);
...
}

The constant coeff here is a value between 0 and 1 which controls how much weight the last value has and how little the old average has. If coeff is closer to 1, elder values will have lot less influnece on the average and the last few values will be the most important ones. If coeff is closed to 0, the current value will change the average slower and the average goes over a longer time. If you want an average where the current value amounts to 10% of the average, use 0.1 as coeff.

If you want other types of averages or moving averages, you'll need to store more old data to calculate it correctly, at minimum a count. The beauty of the exponential moving average is that you just need the old average and the new value.

Perhaps this helps.

Korman

An exponential moving average seems like it would be a better suited calculation for this application in its current state, but somehow, I’m not getting it.

I’m understanding the equation in wikipedia (http://en.wikipedia.org/wiki/Moving_average#Exponential_moving_average), but applying it in the code doesn’t seem to work.

Copying what you’ve suggested:

mph = (0.00004412)/(duration/3600000000); //calculate mph
ave = ave * coeff + ave * (1 - coeff);

doesn’t return a value. Average still reads out as 0.00.

Looking at the equation posted on the wiki site, it should look something like…

ave = coeff * Yt-1 + (1 - coeff) * St-1

Going off this, how would I get the Yt-1 and St-1 values?

Here is the full code I have now:

#include <LiquidCrystal.h>

LiquidCrystal lcd(7, 8, 9, 10, 11, 12);

int pin = 2;
float mph; //variable for current mph
float ave; //variable for average mph
float duration; //variable for time between sensor pulses
int count = 0; //not used
const float coeff = 0.10;

void setup(){
  pinMode(pin, INPUT);
  lcd.begin(16, 2);
  Serial.begin(9600);
}

void loop(){
  duration = pulseIn(pin, HIGH); //count how long pin is HIGH
  mph = (0.00004412)/(duration/3600000000); //calculate mph
  ave = ave * coeff + ave * (1 - coeff);
  lcd.print("Current:");
  lcd.setCursor(9, 0);
  lcd.print(mph);
  lcd.setCursor(13, 0);
  lcd.print("mph");
  lcd.setCursor(0, 1);
  lcd.print("Average:");
  lcd.setCursor(9, 1);
  lcd.print(ave);
  lcd.setCursor(13, 1);
  lcd.print("mph");
}

ave = ave * coeff + ave * (1 - coeff);

Aren't you supposed to add in some element of the current value?

;)

HAHA ::)

What I meant to say....

The code:

const float coeff = 0.1;

void loop(){
....
mph = (0.00004412)/(duration/3600000000); //calculate mph
  ave = mph * coeff + ave * (1 - coeff);
...
}

Doesn't return any values.

So...time for some debug prints.

ok, as much as I know about arduino debugging, is just putting in Serial.print(); commands so you can see where/how far the code gets…is this right?

If so, heres what I have:

#include <LiquidCrystal.h>

LiquidCrystal lcd(7, 8, 9, 10, 11, 12);

int pin = 2;
float mph; //variable for current mph
float ave; //variable for average mph
float time; //variable for time between sensor pulses
const float coeff = 0.10;

void setup(){
pinMode(pin, INPUT);
lcd.begin(16, 2);
Serial.begin(9600);
lcd.print(“Current:”);
lcd.setCursor(13, 0);
lcd.print(“mph”);
lcd.setCursor(0, 1);
lcd.print(“Average:”);
lcd.setCursor(13, 1);
lcd.print(“mph”);
}

void loop(){
time = pulseIn(pin, HIGH); //time how long pin is HIGH
Serial.println(“1”); //Timed sensor
delay(100);
mph = (0.00004412)/(time/3600000000); //calculate mph
Serial.println(“2”); //Calculated mph
delay(100);
ave = mph * coeff + ave * (1 - coeff);
Serial.println(“3”); //Calculated ave.
delay(100);
lcd.setCursor(9, 0);
Serial.println(“4”); //set cursor
delay(100);
lcd.print(mph);
Serial.println(“5”); //has printed mph
delay(100);
lcd.setCursor(9, 1);
Serial.println(“6”); //set cursor
delay(100);
lcd.print(ave);
Serial.println(“7”); //has printed ave
delay(100);
}

I’ve also moved the static LCD print outs to the setup so the loop runs quicker.

Now. I have 7 Serial.println() commands that will display in the serial monitor if everything runs smoothly. Which is what I’m getting. 1, 2, 3, 4, 5, 6, 7.

Is this the ‘proper’ way of debugging for arduino?

You only use that technique when you're not sure where your program is going, or at what point it is failing - I don't think that's the case here. What you're interested in is the [u]values[/u] of the variables.

So something more along the lines of this:

void loop(){
  Serial.println(coeff);
  time = pulseIn(pin, HIGH); //time how long pin is HIGH
  Serial.print(time); //Timed sensor
  delay(100);
  mph = (0.00004412)/(time/3600000000); //calculate mph
  Serial.println(mph); //Calculated mph
  delay(100);
  ave = mph * coeff + ave * (1 - coeff);
  Serial.println(ave); //Calculated ave.
  lcd.setCursor(9, 0);
  lcd.print(mph);
  lcd.setCursor(9, 1);
  lcd.print(ave);
}

Gives me these values:

0.10 = coeff
0.00 = time
0.00 = mph
0.00 = ave
0.10 = coeff
764339.00 = time
0.21 = mph
0.00 = ave
0.10
520103.00
0.31
0.00
0.10
422406.00
0.38
0.00
0.10
422067.00
0.38
0.00
0.10
358660.00
0.44
0.00
0.10
359396.00
0.44
0.00
0.10
340299.00
0.47
0.00
0.10
377574.00
0.42
0.00

I added the notes above to give you a better idea as to what the numbers mean

Where the first value is my coeff Second value is how long the sensor is HIGH in microsec. Third value is the calculated MPH Fourth value is the average

even giving ave a value (float ave = 0/0.00/1/whatever) doesn't give me an output in the ave. Even if I don't pass a magnet in front of the sensor.

This is a little strange what you see here. I would start for testing purposes with ave=1.0 to start with and print the mph*coeff part.

The code looks good, but we all seem to miss something.

Korman

Ok... leaving the line:

float ave;

as is, I've taken the formula for the average down to

ave = mph * coeff;

which will give me an output. If mph = 0.34, ave will give me 0.03, which makes sense, given coeff = 0.1.

having float ave = 1.0; .... ave = mph * coeff + ave; ... wont output anything.

having float ave; .... ave = mph * coeff + ave; .... wont output anything

It appears that if I have ave in a formula that should equal ave is causing some problem.

try to initialize all of your variables (they should be zero, but who knows)

int pin = 2;
float mph=0.0; //variable for current mph
float ave=0.0; //variable for average mph
float time=0.0; //variable for time between sensor pulses
const float coeff = 0.10;

You may also change the formula to be sure that there are no odd type conversions you don't intend.

ave = mph * coeff + ave * (1.0 - coeff);

You could also rewrite that formula as (this likely won't fix any problems just reduces the number of operations to calculate)

ave = (mph - ave) * coeff + ave;

Tried the code [arduino 21 ] and pinned own to the call of PulseIn();

If you replace this by time = 1.0 * random(0, 1000); all code works just fine (so I consider this OK). It looks like memory is overwritten by the call. It should return an unsigned long but maybe it adds some crap to the stack / heap ??

digging further ..

(edit) arduino 19, same problem.

(edit) pulsein() returns an unsigned long and when it is converted to float it seems to fail. Please try the following code, it worked for me thanks to some explicit casting. The number 158832L has a long flag and is the product of the two numbers.

int pin = 2;

float avg=0.0; //variable for average mph
float mph=0.0; //variable for current mph
float time=0.0;
unsigned long t = 0;
float co = 0.10;

void setup(){
  pinMode(pin, INPUT);

  Serial.begin(9600);
  Serial.println("Start");
}

void loop(){
  
  t = pulseIn(pin, HIGH);   //time how long pin is HIGH
  
  Serial.print("TIM: "); Serial.println(t);

  mph = (float)((158832L)/t );
  Serial.print("MPH: "); Serial.println(mph,8);

  avg = avg * (1.0 - co) + mph * co;

  Serial.print("AVG: "); Serial.println(avg, 8);
  Serial.println();
  delay(1000);
}

If this resolves the problem there might be a problem with converting unsigned longs to float. stil digging.

(edit) Sometimes average shoots up to approx maxlong. This is probably due to the returnvalue of 0 that pulseIn can return. Need to catch that too.

Look here and for the averagelist to include in your project. :P http://www.arduino.cc/cgi-bin/yabb2/YaBB.pl?num=1288457281

Solved! finally (although I was wrong earlier, conversion was in the right direction). The real bug/feature is in the print(); statement. Still need to confirm this inner working but this scenario at last explains all and is repeatable. In summary it is caused by an implicit divide by unsigned zero to float conversion.

1 t = pulseIn(pin, HIGH);  
2 mph = (float)((158832L)/t );
3 Serial.println(mph,8);
4 avg = avg * (1.0 - co) + mph * co;
5 Serial.println(avg,8);

line 1 - When pulseIn() returns 0 => t becomes 0. line 2 - mph becomes a divide by zero error, in float internally represented as NaN == NotANumber. line 3 - println() displays NaN as 0 (zero), so we people think mph is zero but it is not. line 4 - avg is a function of NaN results in NaN line 5 - println() again displays a 0

In the next iteration t > 0 and mph gets a more normal value, but as avg is NaN and uses its oldvalue to calculate its new one it stays NaN until reset.

minimal test code to see the effect

float avg=0.0; 
unsigned long t = 0;  // note: unsigned long !

void setup(){
  Serial.begin(9600);
  Serial.println("Start");
  
  avg = 1/t ;                // avg = divide by zero = NaN
  Serial.println(avg,4);     // display's 0.0000
  avg = avg + 5;             // avg = NaN + 5 = NaN
  Serial.println(avg,4);     // display's 0.0000 
  avg = 5;                   // avg = 5
  Serial.println(avg,4);     // display's 5.0000
  
  while (1);
}

void loop() {}

The solution for the sketch is to catch the situations where pulsein() returns 0 [as stated earlier] and all goes well.

(edit) math.h contains isnan() and isinf() but these do not to detect the condition avg is in. So where I call this NaN in the text above this is probably not the right name for it. I only could detect it sofar with (please note the UL = unsigned long).

if (avg == 1/0UL) Serial.println("error");

Conclusion: The solution is to prevent divide by zero, both signed and unsigned in the code.

(edit2)

avg = 1/0.0;
if (isinf(avg)) Serial.println("error");
if (avg == INFINITY) Serial.println("NaN1");
if (avg == NAN) Serial.println("NaN2");

captures divide by zero float.

Rob

so, dividing by zero is a bad thing.

I’ve added an if/else statement to avoid the div0 problem

  //avoid dividing by 0!
  if (t/3600000000 <= 0){ //if denominator <= 0 
    delay(2000); //wait 2 sec
  }
    else{ //if denominator is greater than 0
      mph = (0.00004412)/(t/3600000000); //calculate mph
    }

This checks to see if the denominator in the equation to calculate mph is 0 or not. If it is, it will wait 2 sec. untill it is greater than 0. When the denominator is greater than 0, it performs the calculation and can then go on to calculate the average.

Just wondering if the delay will have an adverse effect on the numbers.

With this setup, it seems to be working. I even made a nifty spreadsheet in googleDocs of a test run with a pretty chart, instead of doing what I’m supposed to be doing here at work :P.

Anyway, heres the full code:

#include <LiquidCrystal.h>

LiquidCrystal lcd(7, 8, 9, 10, 11, 12);

int pin = 2; //Sensor on Pin 2
float mph; //variable for current mph
float ave; //variable for average mph
float t; //variable for time between sensor pulses
const float coeff = 0.10; //coefficient for exponential running average

void setup(){
Serial.begin(9600);
pinMode(pin, INPUT);
lcd.begin(16, 2);
lcd.print(“Current:”); //static LCD printout
lcd.setCursor(13, 0);
lcd.print(“mph”); //static LCD printout
lcd.setCursor(0, 1);
lcd.print(“Average:”); //static LCD printout
lcd.setCursor(13, 1);
lcd.print(“mph”); //static LCD printout
}

void loop(){
Serial.println(coeff);
delay(500);
t = pulseIn(pin, HIGH); //time how long pin is HIGH
Serial.println(t);
delay(500);
//avoid dividing by 0!
if (t/3600000000 <= 0){ //if denominator <= 0
delay(2000); //wait 2 sec
}
else{ //if denominator is greater than 0
mph = (0.00004412)/(t/3600000000); //calculate mph
}
Serial.println(mph);
delay(500);
ave = mph * coeff + ave * (1 - coeff); //calculation for average windspeed
Serial.println(ave);
delay(500);
lcd.setCursor(9, 0);
lcd.print(mph);
lcd.setCursor(9, 1);
lcd.print(ave);
}

for some reason I can’t get a link working properly, so if you want to see the spreadsheet/chart, you’ll have to copy/paste the url:

https://spreadsheets.google.com/ccc?key=0AvPP6gx6s-lLdFJJTmgyZFNvMkhtZ2hwelJIbEM3NVE&hl=en