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?
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) );
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.
What's the application?
Edit: btw, Kazzmir's approach is what I would have suggested, although you can just use the sums.
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 | |
4 | def rad(r) |
5 | $pi * r / 180.0 |
6 | end |
7 | |
8 | def avg(nums) |
9 | nums.inject( 0 ){ |a,b| a + b } / nums.length.to_f |
10 | end |
11 | |
12 | def ang(r) |
13 | 180.0 * r / $pi |
14 | end |
15 | |
16 | def 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 ) |
21 | end |
22 | |
23 | puts average_angle(0,90,180,280) |
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
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 ).
I read the thread title as
Averaging an arbitary number of angels.
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?
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.
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 |
2 | float 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 |
12 | float 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 |
18 | float 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 | } |
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!