1

In my little weather station I collect temperature, humidity, MQ-2 smoke sensor, and wind speed readings for display on a 20x4 LCD display, every 500 ms.
The Anemometer readings jump up and down by quite a bit.

Initialization of variables before Setup is like so:

// Wind Speed Anemometer
const int sensorPin = A3;
int sensorValue = 0;
float sensorVoltage = 0;
float windSpeed = 0;
float voltageConversionConstant = 0.004887586;  // (5/1024)
float voltageMin = .33;   // 0.4 in the documentation
float windSpeedMin = 0;
float voltageMax = 1.5;   // 2.0 in the documentation
float windSpeedMax = 32;

// 20 x 4  LCD Display  
#include <LiquidCrystal_I2C.h>
// set the LCD address to 0x3F for a 20 chars 4 line display\/ Set the pins on the I2C chip used for LCD connections:
//                    addr, en,rw,rs,d4,d5,d6,d7,bl,blpol
LiquidCrystal_I2C lcd(0x3f, 2, 1, 0, 4, 5, 6, 7, 3, POSITIVE);  

Then in Setup I initialize the LCD and flash the backlight.

lcd.begin(20,4);  
lcd.clear();
for(int i = 0; i< 3; i++) {
  lcd.backlight();
  delay(250);
  lcd.noBacklight();
  delay(250);
  }
lcd.backlight(); // finish with backlight on  

In Loop, I paint the initial screen then take readings and display them

void loop() {
  lcd.clear();
  lcd.setCursor(0,0);
  lcd.print("Weather");

  ...etc... to display time and show temp and humidity

  // Wind Speed
  sensorValue = analogRead(sensorPin); 
  sensorVoltage = sensorValue * voltageConversionConstant;
  if (sensorVoltage <= voltageMin) windSpeed = 0; 
  else windSpeed = ((sensorVoltage-voltageMin)*windSpeedMax /(voltageMax-voltageMin)*2.23694); 
  lcd.setCursor(0,3);
  lcd.print(windSpeed);
  lcd.print(" MPH  "); 

  ...etc... to display smoke detection...

  delay (500);
  }  // end loop

So the question is: How can I slow down the Wind Speed fluctuations? It jumps up and down quite widely.

2 Answers 2

2

A: Use a running average

In the initialization I include an array to hold 10 values

// Wind Speed Anemometer
const int sensorPin = A3;
int sensorValue = 0;
float sensorVoltage = 0;
float windSpeed = 0;
float voltageConversionConstant = 0.004887586;  // (5/1024)
float voltageMin = .33;   // 0.4 in the documentation
float windSpeedMin = 0;
float voltageMax = 1.5;   // 2.0 in the documentation
float windSpeedMax = 32;

float ws[10] = { };      // (initializes all to zero)
int wsIndex = 0;
float wsTot = 0.0;
float wsDisplay = 0.0;

Then in the Loop I fill the array with values and display the average of the 10 readings stored there

  // Wind Speed
  sensorValue = analogRead(sensorPin); 
  sensorVoltage = sensorValue * voltageConversionConstant;
  if (sensorVoltage <= voltageMin) windSpeed = 0; 
  else windSpeed = ((sensorVoltage-voltageMin)*windSpeedMax /(voltageMax-voltageMin)*2.23694); 

  if (wsIndex<9) {
    ws[wsIndex] = windSpeed;
    wsIndex++;
    }
  else {
    wsTot = 0.0;
    for (int i=0;i<=9;i++) wsTot = wsTot + ws[i];
    wsDisplay = wsTot / 10.0;
    lcd.setCursor(0,3);
    lcd.print(wsDisplay);
    lcd.print(" MPH  "); 
    wsIndex = 0;
    ws[wsIndex] = windSpeed;
    }   
4
  • 1) Depending on the nature of the fluctuations, a median filter may be way more efficient than a running average. 2) An exponentially weighted running average is simpler and less resource intensive than the “flat” average you are doing. Nov 10, 2016 at 20:17
  • 1
    Interesting comment. Median is interesting but takes more code. In your #2 part I am not sure how you would decide to weight it. And again, it would take more code. I like how my averaging algorithm is implemented in two lines of code. It is easy to read. My favorite code is of the self-documenting type.
    – SDsolar
    Nov 11, 2016 at 1:22
  • Median is indeed more complex, but it's worth the trouble if you have “spiky” noise. It is no better than averaging if your noise is white and Gaussian. The exponentially weighted running average takes less code and less memory: output += constant * (input - output). It's the standard low-pass filter for when you want simplicity and efficiency. You choose the constant as a function of how much smoothing you want. constant = 1.0/N; is roughly equivalent to an N point running average. Nov 11, 2016 at 9:34
  • Ah. Thank you for explaining that. I see your point. I will remember this. My original readouts were wildly variable and I would say they are white and Gaussian. btw, I have doubled the length of my array to 20 and it is very nice to see a good stable readout with much less variability.
    – SDsolar
    Nov 11, 2016 at 16:43
1

How about this one, it supposed to press fluctuations of your sensors reading

void loop(){
..
...
....
last_reading = sensorValue2; //

sensorValue = analogRead(sensorPin); 
sensorVoltage = sensorValue * voltageConversionConstant;
if (sensorVoltage <= voltageMin) windSpeed = 0; 
else windSpeed = ((sensorVoltage-voltageMin)*windSpeedMax /(voltageMax-voltageMin)*2.23694); 

sensorValue2 = (sensorValue+last_reading)/2; 
....
...
..
}
2
  • That certainly is less code - very readable. It would be like my solution but as if I had an array of 2 entries. If this works for you, then that's great.
    – SDsolar
    Nov 11, 2016 at 16:37
  • you can also combine it with averaging method, but it will lessen the sensitivity. Not advised if used in quickly changing environment
    – duck
    Nov 11, 2016 at 16:58

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge that you have read and understand our privacy policy and code of conduct.

Not the answer you're looking for? Browse other questions tagged or ask your own question.