Average wind direction

Hi,

I'm playing with a weather vane (aka a wind direction indicator). It returns a number from 0 to 359. I'd like to apply some damping/averaging to stabilize the displayed value.

Normally with this sort of issue I'd just load all the most recent readings into an array and take an average. The problem is that this doesn't work with circular values - consider 355 degrees and 5 degrees, mathematically they average 180 degrees, but from a direction perspective they should average 0 (north).

There's a weighty mathematical solution explained here.... https://en.wikipedia.org/wiki/Mean_of_circular_quantities

My question is this, do I need to bite the bullet and get down to some serious maths, or is there a quick and dirty fix to produce similar results?

Thanks

How about just reducing the sample time. .

How about just reducing the sample time.

That's an option, it would reduce the constant changing of the display, but I'd prefer to smooth or average the value rather than just taking a snapshot.

You could use the (moving) average of the x-axis value and the (moving) average of the y-axis value, and calculate the vector and degrees after that.

That is in short what the Wikipedia page is talking about: for the average, use the sum of sinus and also the sum of cosinus, and the result it turned into an angle with atan2.

I hope this does make sense. It is not so hard, just split the degrees into an x value and y value. Those x- and y-values can be averaged.

I don't know a trick to average the degrees with a number from 0 to 360 :(

Here's another description of the vector method.

Fulliautomatix: My question is this, do I need to bite the bullet and get down to some serious maths, or is there a quick and dirty fix to produce similar results?

For creating an "average wind direction" and an "average wind speed" you will have to take all the "wind vectors" of your single measurements, and sum up all the 2D wind vectors. The direction of the sum vector is the average direction. The length of the sum vector divided by the number of measurements is the average wind speed.

When calculating with wind averages, you are at 2D vector math.

Example, let's say you have just 2 measurements: 1st: 10 m/s from direction 0° 2nd: 5 m/s from direction 180°

What's the average? Direction mean: (0°+180°)/2= 90° Average of 10m/s wind from north and 5m/s wind from south is 7.5m/s wind from east? No, that is nonsense!

For average you are using the "wind run". So if the wind runs 1second with 10m/s from North 0° and 1second with 5m/s from South, the air has moved within that 2 seconds: 10m south and 5m north = 5m south over all.

That is the same as if during 2 seconds the wind came from north 0° at a speed of 2.5m/s.

The simplest approach is to calculate the circular average. This does away with the 0/360 ambiguity.

(–EDIT-- this is exactly what everyone else is suggesting. But this response has code :slight_smile: )

I would use a rolling average.

Keep the wind direction as a vector (x,y). Each time you take a reading, calculate that reading as a vector, average it with the current rolling average (maybe weight it) to get a new rolling average. Use atan2 to get the angle from the resulting vector.

It’s math, but I wouldn’t call it “heavy”.

See the docs for atan2.

#include <math.h>

float windAvgX;
float windAvgY;

float getAngle(int latestReading) {
  // convert reading to radians  
  float theta = latestReading / 180.0 * PI;
  
  // running average
  windAvgX = windAvgX * .75 + cos(theta) * .25;
  windAvgY = windAvgY * .75 + sin(theta) * .25;
  
  // get the result in degrees
  theta =  atan2(windAvgY, windAvgX) / PI * 180;

  // result is -180 to 180. change this to 0-360.  
  if(theta < 0) theta += 360;
  
  return theta;
}

+1 PaulMurrayCbr

windAvgX = windAvgX * .75 + cos(theta) * .25;
<==>
windAvgX = windAvgX * (1 - 0.25) + cos(theta) * .25;
<==>
windAvgX = windAvgX - windAvgX * 0.25 + cos(theta) * .25;
<==>
windAvgX += ( cos(theta) - windAvgX) * 0.25;

replaces MUL with ADD, should be slightly faster

have the weight 0.25 based upon (the log of) the strength of the wind.