 # Which best way to calculate wind speed

Hello

I have to configure my station to calculate the wind speed.
Some years ago, I bought this anenometer
They wrote the following

0.4V (0 m/s wind) up to 2.0V (for 32.4m/s wind speed)

My board is Cotex MO as the Arduino Zero

• ATSAMD21G18 ARM Cortex M0 processor,
• clocked at 48 MHz
• and at 3.3V logic

I connected the anenometer signal to A0.

Then when I read my analog pin

``````int windValue = analogRead(A0);
``````

I supposed when it retuen 0, there is NO wind
and when it return 1023, the anenometer measure 32.4 m/s wind speed

or

when the anenometer return 0.4V, I should read 0 at the analog red pin, and
when the anenometer return 2V, I should read 1023 at the analog pin

Are you agree?

Keeping in mind that 0.4V is no wind and 2V is wind speed of 32.4V, which will be the best wayy to measure the wind speed?

I suppose, I should convert the analog read to voltage and I am not sure about my proposal

``````float windValue = analogRead(A0); //Get a value between 0 and 1023 from the analog pin connected to the anemometer
windValue *= 3.3;  // Multiply by 3.3V, our reference voltage
windValue /= 1023; // convert to voltage
``````

Let say, there is a tornado, the anenometer (if it still there  ) should return 2V at I should read 1023 at A0. If I want to convert 1023 in volatage, as my reference voltage is 3.3V, I would calculate
1023*3.3/1023=3.3V, but the result should be 2V.

Then I wonder I would better use map

``````wind_volt  = map(vaéue, 0,1023,0.4,2);
``````

and use again map to know the speed

``````wind_speed = map(wind_volt,0.4,2,0,32,4);
``````

I am realy not convainced about using twice the map fonction

What would be your recommandation?

Cheers

If your reference voltage is 3.3V, then the reading at maximum would be 1024 * 2.0 / 3.3, not 2.0

So you should map 0-621 to 4-32

However be aware that the Arduino map() function only uses integers, not float values.

Your logic is kinda OK but many things to say, first one being that map does not deal with float or double, so you need to write your own.

When there is no wind, 0m/s you’ll see 0.4V so analogRead will give you a certain value that represents those 0.4V.

When wind is 32.4 m/s you’ll see 2.0V so analogRead will give you a certain value that represents those 2.0V

The Zero board have 12-bit ADC capabilities. If resolution is set to 12, this will return values from analogRead() between 0 and 4095.

At full resolution, as your reference voltage is 3.3V, 0.4V will be represented by 0.4 * 4095 / 3.3 = ~496 and your max speed’s 2.0V will be represented by 2.0 * 4095 / 3.3 = ~2482

So your speed would be calculated as

``````analogReadResolution(12);
double windSpeed = fmap(analogRead(A0), 496, 2482, 0.0, 32.4); // m/s
windSpeed = constrain(windSpeed, 0.0, 32.4);// to stay in known device range
``````

The fmap function would be defined as

``````double fmap(double x, double in_min, double in_max, double out_min, double out_max)
{
return (x - in_min) * (out_max - out_min) / (in_max - in_min) + out_min;
}
``````
``````0.4V (0 m/s wind) up to 2.0V (for 32.4m/s wind speed)
``````

0.4v / 3.3v * 1024 = analog reading of 124 -> 0 meters per second
2.0v / 3.3v * 1024 = analog reading of 621 -> 3240 cm per second

``````WindSpeed = map(analogRead(windPin), 124, 621, 0, 3240);
``````

That will get you the wind speed in centimeters per second.

Yes, since map() uses long arithmetic, it can work with scaled quantities. It's much faster than float arithmetic too. You could also use imperial units like feet, miles for this... scale to a finer scale like feet per second and then convert to miles/hr only for the purposes of display or data reporting.

Yes that would be faster for sure.

I would still recommend the constrain() to keep the linear interpolation within known bounds as you could see negative wind speed otherwise when there is no speed with ADC approximation.

As discussed, ADC resolution needs to be considered to calculate min and max values.

Hello All,

Thank for your replies.
Thanks J-M-L, it's exactely what I was missing.

When there is no wind, 0m/s you'll see 0.4V so analogRead will give you a certain value that represents those 0.4V.
When wind is 32.4 m/s you'll see 2.0V so analogRead will give you a certain value that represents those 2.0V

Then I will never measure 0 or 1024, as the minimum return value is never 0V, and never 3.3V for the max wind speed

The Zero board have 12-bit ADC capabilities. If resolution is set to 12, this will return values from analogRead() between 0 and 4095.

Yes!!! And this the info I missed (or forget )

In fact, I worked on this topics a long time ago... . I defined the resolution at 10, with this

``````analogReadResolution(10);
analogReference(AR_EXTERNAL);
``````

and to force the voltage reference to 3.3V. I also connected the aref pin to 3.3V
To be honest, I do no remember why I chosed 10, but it may have a good reason. I beleive it was to stay in a basis of 1024

At full resolution, as your reference voltage is 3.3V, 0.4V will be represented by 0.4 * 4095 / 3.3 = ~496 and your max speed's 2.0V will be represented by 2.0 * 4095 / 3.3 = ~2482

Then, let say, I keep a resolution of 10, the above should change to

``````0.4 * 1024 / 3.3 = 124.12
2 * 1024  / 3.3 = 620.50
``````

As wrote johanwasser.
Then if I am correct and following the next of your suggestion, I should have cm/s in order to use interger, as it's faster than float

``````int speed_cm_s = map(124, 621, 0, 3240)
windSpeed = constrain(windSpeed, 0, 3240);// to stay in known device range
``````

Optional:

``````windSpeed_m_s = speed_cm_s/100;
``````

That would be a good idea to use contrain(), but if the anenometer never return below 0.4V and never above 2V, I should anyway, stay in the range, isn't`?
Thanks you!!

but if the anenometer never return below 0.4V and never above 2V, I should anyway, stay in the range, isn't`?

You are not guaranteed that the ADC will not return 122 or 123 and 622 or 623 (or worse) due to the précision in the conversion and possible variations of your reference

As map() is just an affine function (the line going through 2 points), if you have an input value that is not in between the two reference points X, then the output will be below or above the two reference Y. Constrain() will force values into the interval.

pierrot10:
Optional:

``````windSpeed_m_s = speed_cm_s/100;
``````

That will work if you only want integer numbers of meters per second (0…34). If you want fractions of a meter you should do the math in ‘float’:

``````float windSpeed_m_s = speed_cm_s/100.0;
``````

Remember, the expression to the right of the equal sign does not depend at all on the variable to the left of the equal sign. The constant ‘100’ is an int and if ‘speed_cm_s’ is an integer type (int, long, unsigned…) then the division will be done in integers, throwing away any fractional part.

Hello J-M-L and John

Thans a lot for you additionall information.Very nice!!

That will work if you only want integer numbers of meters per second (0..34).
...
should do the math in 'float':

Yes, of course!
Thanks a lot. I am wainting for a connector to connect my anenometer to my board, and I will try asap
Have nice sunday!!!

Hello

I have a similar issue with another devise.

For reminder,my board is Cotex MO as the Arduino Zero

• ATSAMD21G18 ARM Cortex M0 processor,
• clocked at 48 MHz
• and at 3.3V logic

and the resolution is 10

``````analogReadResolution(10);
analogReference(AR_EXTERNAL);
``````

The doc say

Fil vert : Sortie de 0 à 3V CC; 1.67 mV par W/m2

We are agree
No sun = 0V 0> 0W/m2
sunshine = 3V => 179.64W/m2
Then, just to make sure, I go on the good way, and following our previous discussion

``````void get_sun()
{
//https://www.meteo-shopping.fr/Station-meteo/Pyranometre-pour-mesure-du-rayonnement-solaire-6450-Davis-Instruments#caracteristique
// Read the vlaue at A0
float sunValue = analogRead(A0); //Get a value between 0 and 1023 from the analog pin connected to the anemometer
sunValue *= 3.3;  // Multiply by 3.3V, our reference voltage
sunValue /= 1023; // convert to voltage
sunValue = map(sunValue, 0, 3, 0, 179.64); // 0V => 0w/m2, 3V =>179.64W/m2
Serial.print(F("Sun radiation: ")); Serial.print(sunValue); Serial.println(F("W/m2"));
``````

That make sense?

As mentioned elsewhere map does not deal with floating point, so this code` sunValue = map(sunValue, 0, 3, 0, 179.64);`will return a rounded down integral number.
Is that good enough for you ?

Since 0 maps to 0 the formula is pretty trivial to write (it’s just an y = a.x équation)without map and maintaining floating point opeartion:

``````float sunValueVolts = (3.3 / 1023.0) * analogRead(A0);
float sunValueWm2 = (179.64 / 3.0) * sunValueVolts;
``````

Hello J-M-L

Thanks a lot

Is that good enough for you ?

Yes, thanks, I changed it with fmap()

Hello
I am just trying the pyranometer but the values seam to be wrong.
I disconnecter and I measure the voltage at the analog pin of my board.

As the analog pin is "Open", I should seen 0.
It show me 570

``````float sunValue = analogRead(pin_readSun); //Get a value between 0 and 1023 from the analog pin connected to the anemometer
Serial.print(F("DEBUG: ")); Serial.println(sunValue);
``````

there is no pull-down resistance.
Can it be the reason?
Should I connected, at any time, 4.7Ohm pull down resistance at analog pin?

Thanks

pierrot10:
As the analog pin is "Open", I should seen 0.
It show me 570

An 'Open' pin is what we call 'floating'. It will read semi-random values depending on the local electromagnetic field. You can't predict what analog read value you will get from an analog input pin that is not connected to a voltage source. Connecting a pull-up or pull-down resistor is fine will give you a fixed value (0 or 1023) but you have to disconnect the resistor when you want to read from a voltage source if you want an accurate reading.

Dear All

I would like to come back to that topic for a very similar issue.

I need now to calculate the wind direction with a Davis Anemometer.
The sensor work at 5V but can work at 3.3V

My resolutaion is 10

``````analogReadResolution(10);
analogReference(AR_EXTERNAL);
``````

The sensor has two wires, one for the wind speed and one for the wind direction. Wind direction wire is an analog input

``````VaneDirection = analogRead(A2);
``````

the doc use map

``````Direction = map(VaneDirection, 0, 1023, 0, 360);
``````

By default when the (I do not know in english) bar is in the same direction of the arm, it indicate north and the Direction variable should print 0 (or 360)

If I rotate the bar to East, Direction should print 90, then 180 for south, 270 for west and 360 for noth.

When I tried, the value was total wrong and I never get the good value for the variable Direction

I tried to evaluate the value of the anlog pin at 3.3V

1023 / 5 * 3.3 = 675

then the map function changed to

``````Direction = map(VaneDirection, 0, 675, 0, 360);
``````

I rotated again the bar to north, east, south, and north and this time, Direction print the right values

I wonder if my hack is due to the fact that the sensor work at 5V?

I am worried because now, I have to settup a bud/leaf sensor and I wonder if I have to consider 1023 or 675. The problem I can not simulate the value as I can do with the rotation of the bar. The manufacturer of the bud sensor told me that the sensor can work with 5V or 3.3V and I now for a better result, the voltage should be closer to 2.5V

If the sensor is power with 3.3V and I connect HREF to the 3.3V VCC pin, can I trust 1023 or 675?

Many thanks for your advise

We would need to see the doc of that wind direction sensor. Working at 3.3V or 5V might or might not impact the output signal. Depends what they do in the board.

I’d be tempted to say if you power at 3.3V that’s what you’ll get out at 360°

If you set your analog reference to 3.3V then reading 1023 (10 bits config) on the ADC would mean 360°

But If your analog reference is 5V then (assuming the Max voltage you read is 3.3V) you will never see 1023 and indeed 675 will be 360°.

I have been using a Davis Anemometer 6410E with a project (monitor wind speed and direction on a paragliding landing field). It is this model: Connections are like this: This setup shown uses 5 Volts but I also used a version with 3.3 Volts (and Arduino Mini 3.3 V). Both worked like expected.

This links were starting points:

Items you will need

• Measure the wind speed using an anemometer, a simple device you can find at your local hardware store.
• Convert a wind speed measured in kilometers per hour to mph: Divide the kilometers per hour wind speed by 1.61 to get the wind speed in mph.

Can Hamsters Eat Cabbage