![]() ![]() |
I have a weather station which measures both the direction and speed of the wind. It is connected to a SCADA system (TSX57xxx + Monitor Pro). Now I have a mathematical problem with calculating the average direction of the wind (my client needs the information for their reports). The problem is that the direction 0 degrees and 360 degrees are the same (the north, as You know...). Let's say that the wind is from the north; if I have e.g. 10 samples and half of them are 360 degrees and the other half are 0 degrees the result is 180 degrees! This is mathematically right result but... you know...it isn't!
Please help, I feel stupid...
Ville
![]() ![]() |
![]() ![]() |
![]() ![]() |
(10 + 10 + 10 + 350) / 4 = 95 (incorrect)
((10 + 10 + 10 + 350) modulo 360) / 4 = 5 (correct)
Also - don't allow 360 as a valid reading. It aliases with 0 and is therefore ambiguous.
![]() ![]() |
(90+90+90+90+90) modulo 360) / 5 = 18 (incorrect)
(90+90+90+90+90) / 5 = 90 (correct).
The method that you proposed doesn't work!
![]() ![]() |
![]() ![]() |
![]() ![]() |
Then take the SIN of the Radians.
Next Average the SINs.
Now Take the inverse sin of the average.
Finally convert back to degrees.
Using EXCEL do this
Input directions in degrees say from cell A1 through A10.
in Cell B1 type -> Radians(A1)
in Cell C1 type -> SIN(B1)
in Cell A13 type -> Average(A1:A10)
in Cell A14 type -> ASIN(A13)
in Cell A15 type -> Degrees(A14)
Then if you would like to round to nearest five degrees you can
in Cell A16 type -> Mround(A15,5)
![]() ![]() |
>Then take the SIN of the Radians.
>Next Average the SINs.
>Now Take the inverse sin of the
>average.
>Finally convert back to degrees.
The solution is again so simple, only to figure it out... thanks!
![]() ![]() |
moin all,
for angles the mathematics work slightly different as usual (angles do not belong to the body of real numbers.)
Angles are in the one side open range [0..360), i.e. including 0 but excluding 360 and above. While building the sum of all measured angles subtract 360 until the result is in that range.
Sample: 2 times 350 degrees and 1 time 20 degrees. The sum will hold
1. 350
2. 700, which will be reduced to 340
3. 360, which will be reduced to 0
finally divide by 3.
If you have the mod function available, you could simply sum all angles and finally calc the remainder mod 360 before you divide by the number of measured values.
Regards
Friedrich Haase
Ing.-Büro Dr. Friedrich Haase
Consulting - Automatisierungstechnik
email Friedrich@61131.com
WEB http://www.61131.com
![]() ![]() |
((100+100+100+100)modulo 360) / 4 = 10 (incorrect, should be 100).
Here is a solution that really will work. For each angle sampled, accumulate the sum of the sines and the sum of the cosines. Then divide each of these sums by the number of entries to get:
x = average cosine
y = average sine
Then use the arctan2 function to get the average angle as:
Angle = arctan2( y , x);
Note that it is still possible to get an indeterminate answer if x=0 and y=0, as would be the case when trying to average 90 and 270. There is no solution to that problem anyway. Finally, you might want to weight the averages with the wind velocity. A wind angle of 10 degrees at 20 knots averaged with a wind angle of 20 degrees at 3 knots should probably not be 15 degrees. The angle when the wind was at 20 knots is probably more important than the angle when the wind was almost calm. So they should not be averaged together without some unequal weighting.
Robert Scott
Real-Time Specialties
Embedded Systems Consulting
![]() ![]() |
Convert the wind direction and speed into a vector, sum them up, then divide by the number of samples.
![]() ![]() |
However, the trigonometric algorithm is itself not a general solution, as it may produce an average direction which the instrument never at any time pointed to or passed through. For example consider the following set of direction readings (taken in sequence) 120, 120, 120, 90, 0, 0, 270, 240, 240, 240. We can see the wind gradually shifted from 120 degrees to 240 degrees, while passing through 0 degrees. It would seem reasonable that the "average" in this case is 0 degrees. We can also see that the wind did in fact blow at 0 degrees, at one point.
The trigonometric solution though produces a result of 180 degrees, even though the wind never in fact blew in that direction at any time. It would appear that the path taken to travel between points is as important as the readings themselves.
The modulo solution is not incorrect, it is simply incomplete as it does not cover all cases. Admittedly, this distinction is probably of little interest to most people.
There is however, another approach which is probably simpler than the modulo version, but also does not require trigonometric functions (which are not always available). Unless I am mistaken, I believe there are two cases. One case is where the line which connects the extreme and all intermediate values passes through zero, and the other case is where it does not.
Where the line passes through zero, the values to the "right" of zero (e.g. 359, 358, 357, etc.) could be converted to negative angles (e.g. 359 would be -1, 358 would be -2, etc.). If the average is negative, this would then be corrected to a positive angle by adding 360 again.
Where the line does not pass through zero, this step would be unecessary. In either case, a simple mathematical average could be used as there is no longer a numerical discontinuity. The objective in either case is to produce a single continuous scale describing the path actually taken.
Determining whether the line passes through zero is an exercise that is left for the student.
![]() ![]() |
179,179,179,179,179,10,195,181,181,181,181,181
If your purpose in forming the average is to determine where to place a windscreen to protect a rose bush, I would say something near is 180 is best. But your method would have me place the windscreen on exactly the wrong side.
Robert Scott
Real-Time Specialties
Embedded Systems Consulting
![]() ![]() |
If the wind is sampled every 5 minutes, then averaging the reading via a simple formula is pointless. If the readings are intended for use in weather prediction, then the appropriate source to be consulted on this should be a
meteorologist, not the Automation List. Meteorologists no doubt have standard measurement and analysis techniques to address these questions in a manner which is consistant with readings taken elsewhere. We could come up with dozens of clever algorithms, but none of them are of much use if they don't follow the conventions used in collecting weather data.
As for protecting your rose bushes, the normal means to do this is to wrap them completely in burlap for the winter, is it not? Knowing the average is of little use in the exception.
![]() ![]() |
Hi.
There seems to have been rather a lot of wide-ranging discussion already on this topic (I've also learnt something about gardening too, which is a bonus).
I've done something like this before, and used a vector based approach. As you have a SCADA system, it is straightforward to build two analog calculation tags, say WindX and WindY, which represent the X and Y component of the wind magnitude and direction. These two tags should be historized, so that it is easy to extract the 1 hour average or 8 hour average or whatever you need for the report.
WindX = Magnitude*COS(2*3.1416*(90-Direction)/360)
WindY = Magnitude*SIN(2*3.1416*(90-Direction)/360)
The convention for X and Y is standard rectangular coordinates, ie X = East, Y = North
Once you've got the X and Y values being historized, the average wind strength and direction can be calculated by getting the average of X and Y over the required period.
You then need to convert back to compass-based co-ordinates. The following VBA script (part of a macro in a spreadsheet) does this:
'---------------------
Sub WindCalculations()
'---------------------
'
Dim nRow As Long, nCol As Long
Dim rAlpha As Single ' Angle, polar coordinates
Dim rBeta As Single ' Angle, from North
Dim x As Double, y As Double
Dim rVal As Double
For nRow = 2 To 18
x = Cells(nRow, 5) ' Column E, WindX
y = Cells(nRow, 6) ' Column F, WindY
' Magnitude
' ---------
Cells(nRow, 8) = Sqr(x * x + y * y)
' Calculate polar coordinate angle
' --------------------------------
If x = 0 Then
If y > 0 Then
rAlpha = 90
ElseIf y < 0 Then
rAlpha = -90
Else
rAlpha = 0
End If
Else
rVal = y / x
If x > 0 And y > 0 Then
rAlpha = 180 / 3.14159265358979 * Atn(rVal)
ElseIf x < 0 And y < 0 Then
rAlpha = 180 + 180 / 3.14159265358979 * Atn(rVal)
ElseIf x > 0 And y < 0 Then
rAlpha = 180 / 3.14159265358979 * Atn(rVal)
Else
' x < 0 and y > 0
rAlpha = -180 + 180 / 3.14159265358979 * Atn(rVal)
End If
End If
Cells(nRow, 9) = rAlpha
' Convert to compass bearing
' --------------------------
rBeta = 90 - rAlpha
If rBeta < 0 Then
rBeta = rBeta + 360
End If
Cells(nRow, 10) = rBeta
Next nRow
End Sub
--- End of WindCalcs ---
This VBA code forms part of a macro in a spreadsheet, which can be downloaded from my web site:
http://www.procdev.com/downloads/windcalcs.zip
Hope that helps you out. Now I'd better get back to my regular job...
Chris D<br>
http://www.procdev.com
![]() ![]() |
http://www.webmet.com/met_monitoring/621.html
Compliments of the Canadian Weather Service.
Bob Pawley
![]() ![]() |
1. Find the average and standard deviation of the given numbers.
2. Increase the smallest number by 360.
3. Repeat steps 1 and 2 until all numbers are greater than 360.
4. Choose the average that yields the smallest standard deviation.
5. If the average is greater than 360 then subtract 360.
I have posted a longer explanation at http://polytope.com/average-angle.txt
![]() ![]() |
--
Romeli
Electrical engineer
PT.Smelting
Affiliate of Mitsubishi Materials
phone: 62-31-3976464 fax: 62-31-3976466
www.smelting.co.id
![]() ![]() |
In first step, you should calculate sum of sin(theta) and cos (theta), where theta is your wind direction. In second step take atan2[sum(sin(theta),sum(cos(theta)]), represents the average wind direction. But the answer is positively defined, however this type of wind direction traditionally does not used in meteorology, since 0 (or 360) indicates Northly but in mathematics it is 90 degree; hence you should convert to meteorological wind directions.
Dr. Hasan TATLI (Canakkale Onsekiz Mart University, Dept. of Geography, Turkey)
![]() ![]() |
Sorry to disrupt the party, but I'm pretty sure most answers to this posting are not correct.
Averaging x,y-directions, sines of angles... (e.g. obtained after atan()-calls) is bound to fail because it will produce biased results.
What should be done is computing the first eigen-vector of the direction covariance-matrix. Here is how to do it:
1. Stack all n directions (normalised wind-vectors) in an (n x 2)-matrix M (i.e. 1 direction per row).
2. Compute the direction covariance matrix as follows:
C = M' * M
where M' is the transpose of M and * is the regular matrix-product. C should now be a (2 x 2)-matrix.
3. Compute the first eigen-vector of this matrix. This is the dominant direction.
Notice that this procedure does not take the magnitude of each direction into account, i.e. the dominant direction is not biased towards the direction(s) with largest wind-magnitude. If you also want to take this into account, just omit the normalisation of wind-vectors when computing C.
Kind regards,
Rik
![]() ![]() |
I tried some examples using your eigen-vector method and using the method I proposed:
atan2(sum of sines, sum of cosines)
and I got the same answer. Can you give a simple example where the eigen-vector method gives a different result from mine? (See my posting above in this thread).
Robert Scott
Real-Time Specialties
Embedded Systems Consulting
![]() ![]() |
Is there a difference in methods for real-time processing (while the data is collected) and post-processing (after the data is collected) to calculate average? I checked the sensor documentation and it says it uses vector components to calculate real-time averages? What about using software that come with the weather station? I know it will generate average too. Any suggestion will be highly appreciated.
![]() ![]() |
Robert Scott
Real-Time Specialties
Embedded Systems Consulting
![]() ![]() |
IMO, Bob Peterson has the best solution (and it's one of the simplest approaches, too).
But I would probably tweak his approach...
Because the only problem with his solution is that 1/2 hour of wind due north at 50 mph followed by 1/2 hour of wind due south at 50 mph would yield an average wind velocity of 0 mph. I'm guessing you would probably prefer the average value to equal 50 mph.
What I would do is this...
To computer average direction, convert each direction sample into a UNITY vector and add them up and divide by the number of samples.
To obtain the average velocity, add together the absolute value of all the velocity samples and divide by the number of samples.
Hope this helps!
![]() ![]() |
Averaging unity direction vectors can also be misleading. Suppose the wind is nearly calm for much of the day, but when it blows hard, it always blows from the West (270 degrees). But when the wind is nearly calm, it is mostly from the East (090 degrees). All those easterly unity vectors will overwhelm the westerly ones. I'm not sure you want to give such weight to vectors that were nearly zero in magnitude.
Aldous:
The website you cited:
http://www.webmet.com/met_monitoring/62.html
confirms the method that I outlined in my 20 May 2005 posting above.
Robert Scott
Real-Time Specialties
Embedded Systems Consulting
![]() ![]() |
http://www.webmet.com/met_monitoring/62.html
Aldous
![]() ![]() |
Can you tell me if it works correctly for your problem?
#include <stdio.h>
#include <stdlib.h>
#include <math.h>
static float angle_0to360(float theta)
{
int k = (int)(theta / 360);
theta = theta - k * 360;
if (theta < 0) {
theta = theta + 360;
}
return theta;
}
static float new_angle_mean(float old_theta, float new_theta, int old_num)
{
float mean_theta;
float dtheta;
if (old_theta == new_theta) {
return old_theta;
}
dtheta = fabsf(old_theta - new_theta);
if (dtheta > 180) {
old_theta = (old_theta > 180) ? old_theta - 360: old_theta;
new_theta = (new_theta > 180) ? new_theta - 360: new_theta;
}
mean_theta = (old_theta*old_num + new_theta) / (old_num + 1.);
return angle_0to360(mean_theta);
}
int main()
{
int i, num;
float *theta;
float mean_theta = 0.;
printf("give number of angles: ");
scanf("%d", &num);
theta = malloc(num * sizeof(float));
printf("give %d angles: ", num);
for (i = 0; i < num; i++) {
scanf("%f", θ[i]);
theta[i] = angle_0to360(theta[i]);
mean_theta = new_angle_mean(mean_theta, theta[i], i);
}
printf("\nmean_theta = %f\n\n", mean_theta);
free(theta);
}
![]() ![]() |
angle______"mean" so far
4 _____ 4
180 _____ 92
270 _____ 151.3
340 _____ 108.5
270 _____ 140.8
330 _____ 112.3
300 _____ 87.7
260 _____ 109.2
300 _____ 90.4
If you plot these angles, you will agree that the average ought to be somewhere around 270 degrees, not 90.4. I can clearly keep extending the list using angles that are all close to 270 and still make your "average" stay around 90. As I and several others have said earlier, you have to average the sines and cosines and then take are arctangent.
Robert Scott
Real-Time Specialties
Embedded Systems Consulting
![]() ![]() |
I´m following your example mentioned above (20 May 2005). In the case we would work with the negative values (359 = -1; 358 = -2, etc) where could we find the limit to this negative values? I mean that if we have 179 and -179 for example (in the situation that South=180 were the limit) the average is 0=N when should be 180=S.
So where could we find the limit to estimate the real average? Have you got some suggestion?
Thank you very much.
Julian
Uppsala Universitet
![]() ![]() |
>...So where could we find the limit to estimate the real average? Have you got some suggestion?<
My suggestion is the same as before (see my earlier postings). Stop trying to average the angles directly and average the sines and cosines instead. It is the only way that actually works in all situations.
Robert Scott
Real-Time Specialties
Embedded Systems Consulting
![]() ![]() |
![]() ![]() |
Try to trap 360 value and output it as 0 so to make your average correct. Just add the following logic :
value = X "data acquired"
If value = 360 then value = 0 else value = X
"Then use "value" as your data element for the degrees or wind direction then you're OK.
randy
![]() ![]() |
% Develop a total wind vector to determine average heading. This eliminates any problems with averaging values like [5,355,-180,180]
N = sum(MG .* cosd(HD));
E = sum(MG .* sind(HD));
Ave_MG = mean(MG);
Ave_HD = atan2(E,N) * cR2D;
![]() ![]() |
http://stackoverflow.com/questions/491738/how-do-you-calculate-the- average-of-a-set-of-angles/3651941#3651941
![]() ![]() |
Try this with excel:
For realvector averaging:
Put windspeed and winddirection data in column A and B.
Then calculate the components of wind (u and v are in column C and D):
=-A1*SIN(PI()/180*B1)
=-A1*COS(PI()/180*B1)
In column E and F (for example,if you have 60 data in one hour) calculate the average of the components of wind:
=AVERAGE(c1:c60)
=AVERAGE(d1:d60)
Column G is the average value of the windspeed:
=SQRT(e1*e1+f1*f1))
Column H is the average value of the winddirection:
=IF(e1=0;(IF(f1=0;0;IF(f1>0;360;180)));IF(e1>0;(270-180/PI()* ATAN(f1/e1));(90-180/PI()*ATAN(f1/e1))))
For unitvector averaging:
column C and D:
=-SIN(PI()/180*B1)
=-COS(PI()/180*B1)
column E and F:
=AVERAGE(c1:c60)
=AVERAGE(d1:d60)
column G:
=average(a1:a60)
column H:
=IF(e1=0;(IF(f1=0;0;IF(f1>0;360;180)));IF(e1>0;(270-180/PI()* ATAN(f1/e1));(90-180/PI()*ATAN(f1/e1))))
Hope this helps.
M.A.Saghafi
Meteorology Specialist (M.Sc)
Tehran University
![]() ![]() |
Here's an different but very easy solution. I searched for myself a way to have daily averages of my hourly measured wind direction data. I found that there is no excellent and %100 correct solution. Therefore I make my own method to have a most represanting daily direction. My way will give you not the exact average value of the measured degrees, but you will have the most dominated daily wind direction.
1) Convert you degree data to direction codes. Here is the formula for excel:
=IF(B1<=22;"1";IF(B1<=67;"2";IF(B1<=11 2;"3";IF(B1<=157;"4";IF(B1<=202;"5";I F(B1<=247;"6";IF(B1<=292;"7";IF(B1<337;" ;8";"1"))))))))
1= N, 2=NE, 3=E, 4=SE, 5=S, 6=SW, 7=W, 8=NW
2)Calculate the most frequent value (in excel: MODE) for each day.
That's all.
Cemil Seyis
TUBITAK MRC, Turkey
![]() ![]() |
=IF(e1=0;(IF(f1=0;0;IF(f1>0;360;180)));IF(e1>0;(270-180/PI()* ATAN(f1/e1));(90-180/PI()*ATAN(f1/e1))))
![]() ![]() |
=IF(e1=0,(IF(f1=0,"n/a",IF(f1>0;360;0))),IF(e1>0,(2 70-180/PI()*ATAN(f1/e1)),(90-180/PI()*ATAN(f1/e1))))
![]() ![]() |
> =IF(e1=0,(IF(f1=0,"n/a",IF(f1>0;360;0))),IF(e1>0,(270- 180/PI()*ATAN(f1/e1)),(90-180/PI()*ATAN(f1/e1))))
This is a very simple mathematical and meteorological issue (actually page 2 of "Meteorology for Scientists and Engineers" by Roland B Stull..
Note: time period can be any time period (this example is hourly)
*** Matlab code below
For each ten minute wind speed measurement the u- and the v-component of the wind need to be calculated in order to average wind direction.
u-comp ws = -1 * (ws*sin(wd*PI/180))
v-comp ws = -1 * (ws*cos(wd*PI/180))
where PI = 3.1415926535897
assuming six 10-minute values in an hour
average the six u-comp WS and six v-comp WS to get an average u-comp and v-comp for the hour
if average u-comp > 0
hourly average WD = (90-180/PI*atan(average v-comp/average u-comp)+180)
elseif average u-comp < 0
hourly average WD = (90-180/PI*atan(average v-comp/average u-comp))
elseif average u-comp = 0
if average v-comp < 0
hourly average WD = 360
elseif average v-comp > 0
hourly average WD = 180
else
hourly average WD = 0
end
end
Example Calculation:
Six WS measurements: [2.3, 2.7, 4.5, 5.2, 10.3, 8.1]
Six WD measurements: [220, 174, 43, 356, 99, 67]
Results:
Average u-comp = -3.18989225
Average v-comp = -0.930826755
Hourly Average WD = 73.73 degrees
Hourly Average WS = 5.5167 m/s
![]() ![]() |
just wondering why there is -1 in calculating the U and V components?
Thanks
Jy
![]() ![]() |
So, here's what I got to work for me using a couple columns of logic (no radians, sin or vector required):
A1:A10 = Raw Data
B1: =IF(A1>180,A1-360,A1) <drag down to B10
C2: =IF(ABS(A1-A2)>180,1,"") <drag down to C10
D10: =IF(SUM(C1:C10)>0,IF(AVERAGE(B1:B10)<0,360+AVERAGE(B1:B10),AVERA GE(B1:B10)),AVERAGE(A1:A10))
Users of this site are benefiting from open source technologies, including PHP, MySQL and Apache. Be happy.
Fortune
Brain, v. [as in "to brain"]:
To rebuke bluntly, but not pointedly; to dispel a source of
error in an opponent.
-- Ambrose Bierce, "The Devil's Dictionary"









on 8 February, 2010 - 2:21 pm
