Math: Averaging an arbitary number of angles
Fladimir da Gorf

OK, there should be a simple answer to this - how can I get the average of an arbitarily large set of angles? It's clear how to average 2 angles - along the smallest angle between them, but how about a larger set? Also, what'll be the result then if the averaged angles are 0, PI/2, PI and 3PI/2?

kazzmir

Hm, is it something like taking the average of all the cosines, average of all the sines, then convert the resulting unit coordinate back into an angle?

atan2( average(sines), average(cosines) );

Fladimir da Gorf

Oh what an evil solution, I like it! That's a bit computationally expensive, though (this is for a very limited device), so if there's any other ways which don't include using trigonometric functions, it'd be great.

Matthew Leverton

<math>\frac{\Sigma_{i=1}^n a_i}{n}</math>
8-)
What's the application?

Edit: btw, Kazzmir's approach is what I would have suggested, although you can just use the sums.

kazzmir

Although if you just convert all the angles to be between -pi and pi you can just average the values directly, I think. Here is a stupid little ruby script to do it

1 
2$pi = 3.14159265
3 
4def rad(r)
5 $pi * r / 180.0
6end
7 
8def avg(nums)
9 nums.inject( 0 ){ |a,b| a + b } / nums.length.to_f
10end
11 
12def ang(r)
13 180.0 * r / $pi
14end
15 
16def average_angle(*angs)
17 # xs = avg(angs.collect{ |x| Math.cos(rad(x)) })
18 # ys = avg(angs.collect{ |y| Math.sin(rad(y)) })
19 # ang(Math.atan2(ys,xs))
20 ang( avg(angs.collect{|x| rad(x) - $pi}) + $pi )
21end
22 
23puts average_angle(0,90,180,280)

Fladimir da Gorf

ML, yeah, that's the basic average function for linear values, but angles are cyclic. When averaging angles like 10 and 350 decrees, the result, with that equation, would be 180 decrees, which isn't right...

For the application, let's just say that it's geodata related ;)

kazzmir

Oh it doesn't work if you average it from -pi to pi, but it does seem to work with my original method( the lines that are commented in the above code ).

ImLeftFooted

I read the thread title as
Averaging an arbitary number of angels.

nonnus29

I spent about a month trying to do trig on the gameboy color a long time ago, and depending on just how limited of a device you're talking about; how about using trig functions with lookup tables or Cordic functions?

http://www.dspguru.com/info/faqs/cordic2.htm

Matthew Leverton
Quote:

For the application, let's just say that it's geodata related ;)

I wondered because if you have the data stored as vectors, it's a trivial solution. But I suppose then you wouldn't be asking.

SiegeLord

I made a nice angle subtraction function for my ChristMass hack entry, so I figured that it would work here. My method incrementally averages the angles by subtracting each successive angle from the average (using my function) and creating a new angle that is in the same revolution as the current average angle. The current average angle and this new angle are then averaged (the average angle is obviously weighed). Not sure if this is mathematically accurate, but my little test program seemed to show this to work well.

1//forces the angle to be between 0 and 2 PI
2float FixAngle(float angle)
3{
4 if(angle < 0 || angle > 2 * AL_PI)
5 {
6 return angle - floorf(angle / (2 * AL_PI)) * 2 * AL_PI;
7 }
8 return angle;
9}
10 
11//subtracts angle2 from angle1 and returns the real distance between them
12float SubtractAngles(float angle1, float angle2)
13{
14 return FixAngle(angle1 + AL_PI - angle2) - AL_PI;
15}
16 
17//return the average angle of an array of angles
18float GetAverageAngle(vector<float>& angles)
19{
20 ASSERT(angles.size() > 0);
21 float average_angle = angles[0];
22 
23 for(int ii = 1; ii < angles.size(); ii++)
24 {
25 float diff = SubtractAngles(angles[ii], average_angle);
26 average_angle = average_angle * float(ii) + average_angle + diff;
27 average_angle /= float(ii + 1);
28 }
29 return average_angle;
30}

Fladimir da Gorf

Yes indeed, it works, because:

ii * avg(ii-1) = ii * ((ii-1) * avg(ii-2) + angle[ii-1])/ii
= (ii-1) * avg(ii-2) + angle[ii-1]
= (ii-1) * ((ii-2) * avg(ii-3) + angle[ii-2]) + angle[ii-2]
= (ii-2) * avg(ii-3) + angle[ii-2] + angle[ii-2]
...
= sum(angles{0...ii}) (except that it's not a sum in the normal way)

Thanks a lot!

Thread #595008. Printed from Allegro.cc