How to average angles?

Peter J. Floriani, Ph.D. floriani at epix.net
Sat Feb 15 18:37:25 EST 1997


Rainer Gratias wrote:

> How do I correctly average angles, keeping the periodicity in mind?
> The only (more or less) correct way I found is derived from averaging
> complex numbers, using the transformation from polar to cartesian
> coordinates:
> <ang>=arctan(<sin(ang_i)>/<cos(ang_i)>)
> (in Fortran: atan2(<sin(ang_i)>,<cos(ang_i)>))

To remove the "periodicity" of angles, apply the "modulus" function, 
which is being invisibly applied by the SINE and COSINE library 
functions. For positive m,n, you can compute modulus in this way:

   m modulus n = m - n*FLOOR(m/n)

Thus, an angle a in the real numbers can be brought to the 
half-open interval [0,2*pi) by the following:
   If a is not negative:
      aprime = a - 2*pi * FLOOR(a/(2*pi))
   If a is negative:
      aprime = 2*pi - (-a - 2*pi*FLOOR(-a/(2*pi)))

where FLOOR(x) is the largest integer less than or equal to x.
Note, in the above, that FLOOR will never be given a negative argument.

As a general rule, explicit trigonometric functions ought to be avoided 
whenever possible, for reasons of accuracy and efficiency. The 
single-argument atan has an additional limitation because the 
mathematical "inverse tangent" has a range of only (-pi/2,pi/2) rather 
than the range (-pi,pi] typically supplied by the two-argument form.

Regarding the "strange behavior" of averaging angles:

The results appear consistent to me, except for the -90 given for 
{0,0,180,180} which is an implementation artifact; the answer could have 
been reasonably given as 90. But clearly, the average angle for any two 
angles separated by 180 degrees is "no angle", and so any number of 
opposing angles contribute nothing to the average.  However, each of the 
values do indeed affect the result, as can easily be seen by slightly 
changing one of them.

The special case when the angles, as it were, cancel each other out, 
requires explicit handling. This is easily approached by converting the 
angles to unit vectors (as Dr. Gratias noted), averaging them, and 
reporting back the average.  Then, the special case is easily detected as 
the null vector (0,0), which is directionless.  The pseudocode is:

   SUMX = 0
   SUMY = 0
   N =0
   FOR each angle a (in radians) DO
      SUMX = SUMX + COS(a)
      SUMY = SUMY + SIN(a)
      N = N + 1
   ENDFOR
   AVGX = SUMX/N
   AVGY = SUMY/N
   IF (AVGX,AVGY) is "too close" to (0,0) THEN
      report directionless, NULL VECTOR
   ELSE
      AVERAGEANGLE = ARCTAN(AVGY,AVGX)
   ENDIF

I hope this helps.

Peter J. Floriani, Ph.D.
floriani at epix.net
----------------------------------------------------
"I deny that biology can destroy the sense of truth, 
which alone can even desire biology. No truth which
I can find can deny that I am seeking the truth.  
My mind cannot find anything which denies my mind."
G. K. Chesterton, "The Long Bow" in Collected Works 14:96



More information about the Molmodel mailing list