Recording Maximum Gust and Average Wind Speed

Thanks to Korman and Richard, I was able to conquer the Gray code, and am now refining the anemometer. I have used the following code to generate the appropriate MPH for the id-4001 anemometer which uses a 32 pulse optical encoder and IR detector. I have tried so many times to read and store a peak Gust, and would also like to have rolling 2 minute and 10 minute averages.

// #include <avr/pgmspace.h>

// Table with the pins to use as input
const int pinCount = 4;
int pins[pinCount] = {
8, 9, 10, 11};

// Decoding table
const int decodeCount = 16;
const char* decode[decodeCount]=
{
"SE", "ESE", "WSW", "W",
"SSE", "S", "SW", "SSW",
"ENE", "E", "NW", "WNW",
"NE", "NNE", "NNW", "N"};

byte sensorInterrupt = 1; // 0 = pin 2; 1 = pin 3
byte sensorPin = 2;
float calibrationFactor = 11.6;
volatile byte pulseCount;
float flowRate;
unsigned int flowMPH;
unsigned long oldTime;

void setup(void) {
// Configure pins for input
for (int i = 0; i < pinCount; i++) {
pinMode (pins*, INPUT);*

  • }*
  • pinMode(sensorPin, INPUT); *
  • digitalWrite(sensorPin, HIGH); *
  • // enable the 20K pull-up resistor to steer *
  • // the input pin to a HIGH reading. *
  • pulseCount = 0;*
  • flowRate = 0.0;*
  • flowMPH = 0;*
    _ Serial.begin(9600);_
    _ Serial.println("GONNA MAKE THIS WORK!"); _
  • // The ANEMOMETER sensor is connected to pin 3 which uses interrupt 1.*
  • // Configured to trigger on a FALLING state change (transition from HIGH*
  • // state to LOW state)*
  • attachInterrupt(sensorInterrupt, pulseCounter, FALLING);*
    }
    // Configure pins for input
    /*
    _ * Main program loop_
    _ */_
    void loop() {
  • int gc = 0;*
  • // Build index for decoding table*
  • for (int i = 0; i < pinCount; i++) {*
    _ gc = (gc << 1) | digitalRead(pins*);_
    _
    }_
    _
    if (gc < decodeCount) {_
    _ Serial.print ("Wind is from the ");
    Serial.print (decode[gc]);
    Serial.print (" at ");_

    _
    }_
    _
    else {_
    _ Serial.print ("Error in Gray Code ");
    Serial.println (gc);_

    _
    }_
    _
    delay (750);_
    _
    {_
    _
    if((millis() - oldTime) > 750) // Only process counters every 750 milliseconds*_
    * { *
    * // Disable the interrupt while calculating flow rate and sending the value to*
    * // the host*
    * detachInterrupt(sensorInterrupt);*
    * // Because this loop may not complete in exactly 1 second intervals we calculate*
    * // the number of milliseconds that have passed since the last execution and use*
    * // that to scale the output. We also apply the calibrationFactor to scale the output*
    * // based on the number of pulses per second per units of measure (litres/minute in*
    * // this case) coming from the sensor.*
    _ flowRate = ((750.0 / (millis() - oldTime)) * pulseCount) / (calibrationFactor * 0.75);
    * // Note the time this processing pass was executed. Note that because we've*
    * // disabled interrupts the millis() function won't actually be incrementing right*
    * // at this point, but it will still return the value it was set to just before*
    * // interrupts went away.*
    * oldTime = millis();*
    * flowMPH = (flowRate);*
    * // Uncomment the following two lines to display the count value.*
    * // if(int(flowRate) != 0)*
    * // Serial.print(pulseCount, DEC );*
    * // Write the calculated value to the serial port. Because we want to output a*
    * // floating point value and print() can't handle floats we have to*
    * // output the whole number part, then a decimal point, then the fractional part.*
    * unsigned int frac;*
    * // Print the flow rate*
    Serial.print(int(flowRate )); // Print the integer part of the variable_

    _ Serial.print("."); // Print the decimal point_
    * // Determine the fractional part. The 10 multiplier gives us 1 decimal place.*
    _ frac = (flowRate - int(flowRate)) * 10;
    Serial.print(frac, DEC ) ; // Print the fractional part of the variable_

    _ Serial.println("MPH "); // Output + separator_
    * // if(int(flowRate) < 1) optional*
    * // {*
    * // Serial.println(" CALM - LESS THAN 1 MPH ");*
    * // }*
    * // if(int(flowRate) > 0)*
    * // Reset the pulse counter so we can start incrementing again*
    * pulseCount = 0;*
    * // Enable the interrupt again now that we've finished sending output*
    * attachInterrupt(sensorInterrupt, pulseCounter, FALLING);*
    * }*
    * }*
    }
    /**
    _ * Invoked by interrupt0 once per rotation of the anemometert sensor. Interrupt_
    _ * handlers should be kept as small as possible so they return quickly.
    /_
    void pulseCounter()
    _
    {_
    _
    pulseCount++;_
    _
    }_
    _
    [/quote]*_
    I realize this is very do-able, but as a noob, I am just stuck. I am also painfully aware that my coding may well be sloppy. I am very open to criticism and suggestions.
    Can anyone point me in the right direction?
    Thanks in advance!

I'm sorry if the last post was not right. I tried to peel away as much commenting as possible, and may well have removed some necessary info as well.

Yes, the instantaneous wind speed is being measured sucessfully without any difficulty. The working code responsible for that is as follows:

byte sensorInterrupt = 1; // 0 = pin 2; 1 = pin 3
byte sensorPin = 2;
float calibrationFactor = 11.6;
volatile byte pulseCount;
float flowRate;
unsigned int flowMPH;
unsigned long oldTime;

void setup(void) {
pinMode(sensorPin, INPUT);
digitalWrite(sensorPin, HIGH);

pulseCount = 0;
flowRate = 0.0;
flowMPH = 0;
oldTime = 0;
Serial.begin(9600);

attachInterrupt(sensorInterrupt, pulseCounter, FALLING);
}

void loop()
{
if((millis() - oldTime) > 750) // Only process counters every 750 milliseconds
{
detachInterrupt(sensorInterrupt);
flowRate = ((750.0 / (millis() - oldTime)) * pulseCount) / (calibrationFactor * 0.75);

oldTime = millis();

flowMPH = (flowRate);

unsigned int frac;
frac = (flowRate - int(flowRate)) * 10;
Serial.print((int)flowRate);
Serial.print(".");
Serial.print(frac, DEC ) ;
Serial.println("MPH ");

pulseCount = 0;
attachInterrupt(sensorInterrupt, pulseCounter, FALLING);
}
}

void pulseCounter()
{
pulseCount++;
}

The questions are:

  1. How do I get the peak gust, compared to current?
    and
  2. How do I get a rolling average of readings for say, 2 minutes and 10 minutes?

Thanks once again for following this, Richard!

John

Thanks, Richard.

I have come up with the following to take care of the peak gust and I will try it this evening.

My next question is, how do I accumulate the peaks for 2 minutes (160 values) and for 10 minutes (800 values)? Particularly since I am using an interrupt to do the counting, and I want to get in and out as quickly as possible?

byte sensorInterrupt = 1; // 0 = pin 2; 1 = pin 3
byte sensorPin = 2;
float calibrationFactor = 11.6;
volatile byte pulseCount;
float flowRate;
unsigned int flowMPH;
unsigned int maxflowMPH;
unsigned long oldTime;
int threshold = 50; //set your own value based on your sensors
unsigned int maxflowRate;

void setup(void) {
pinMode(sensorPin, INPUT);
digitalWrite(sensorPin, HIGH);

pulseCount = 0;
flowRate = 0.0;
flowMPH = 0;
oldTime = 0;
maxflowMPH = 0; // for peak wind gust
Serial.begin(9600);

attachInterrupt(sensorInterrupt, pulseCounter, FALLING);
}

void loop()
{
if((millis() - oldTime) > 750) // Only process counters every 750 milliseconds
{
detachInterrupt(sensorInterrupt);
flowRate = ((750.0 / (millis() - oldTime)) * pulseCount) / (calibrationFactor * 0.75);

oldTime = millis();

flowMPH = (flowRate);
maxflowMPH = (maxflowRate);

unsigned int frac;
frac = (flowRate - int(flowRate)) * 10;
Serial.print((int)flowRate);
Serial.print(".");
Serial.print(frac, DEC ) ;
Serial.println("MPH ");
{
unsigned int frac;
frac = (maxflowRate - int(maxflowRate)) * 10;
Serial.print("GUSTS TO ");
Serial.print((int)maxflowRate);
Serial.print(".");
Serial.print(frac, DEC ) ;
Serial.println("MPH GUST ");
}

pulseCount = 0;
attachInterrupt(sensorInterrupt, pulseCounter, FALLING);
}
if ( flowRate > maxflowRate ) {
flowRate = maxflowRate;
}
}

void pulseCounter()
{
pulseCount++;
}

You can cheat. Just accumulate the highest value for each minute. If the new value is higher than the last one, replace it as the new high-score, otherwise ignore it for the peaks. For the average count the samples and keep a runningtotal.

int samples; // How many samples do we have
long runningtotal; // Sum of all speeds
int topspeed; // Top speed

... in processing function ...

int curspeed = ....; // Get wind speed
if (curspeed > topspeed) {
    topspeed = curspeed;
}
runningtotal += curspeed;
smaples++;

... Somewhere else in your display function do every minute or so ...
int average = runningtotal / samples;
Serial.println (average);
Serial.println (topspeed);
// Reset counters
topspeed = 0;
samples = 0;
runningtotal = 0;

Just to give you ideas.

Korman

Thank you both for the replies. I will certainly consider both as I find a solution. Kormans approach seems to be more direct.
Richard, although it may seem not to be critical, instrumentation limitations have traditionally limited our understanding of wind gust phenomena. I have anemometers from various manufacturers that provide measurements in 1 minute, 2 minute and 6 second averages. From my experience - in a nutshell - they are worthless. A gust of wind must be captured quickly in order for it to be meaningful. A peak gust may occur over a very short period; it is simply missed by an averaging type device. Although the gust is 'averaged' over the duration and is therefore registered, its magnitude is not known. I prefer the peak gust be just that - an instantaneous reading (albeit limited by the mass of the measurement instrument). (Sorry - a bit passionate about wind gusts :-).

Thanks, Richard. I DO appreciate responses - all of them.

My keen interests stems from life experiences with wind, and the lack of affordable and accurate instruments for the hobbyist. You would be amazed at some of the inferior hardware that is being sold - at staggering prices I might add. While my project approach will not compete with a thermal, vortex or doppler anemometry, I am confident that with the kind help that you and others have provided, I can raise the bar for simple, affordable and accurate cup-style anemometers.