Averaging angles… Again

后端 未结 12 2112
情歌与酒
情歌与酒 2020-12-14 08:26

I want to calculate the average of a set of angles, which represents source bearing (0 to 360 deg) - (similar to wind-direction)

I know it has been

相关标签:
12条回答
  • 2020-12-14 09:08

    Here's the answer I gave to this same question:

    How do you calculate the average of a set of circular data?

    It gives answers inline with what the OP says he wants, but attention should be paid to this:

    "I would also like to stress that even though this is a true average of angles, unlike the vector solutions, that does not necessarily mean it is the solution you should be using, the average of the corresponding unit vectors may well be the value you actually should to be using."

    0 讨论(0)
  • 2020-12-14 09:12

    This is incorrect on every level.

    Vectors add according to the rules of vector addition. The "intuitive, expected" answer might not be that intuitive.

    Take the following example. If I have one unit vector (1, 0), with origin at (0,0) that points in the +x-direction and another (-1, 0) that also has its origin at (0,0) that points in the -x-direction, what should the "average" angle be?

    If I simply add the angles and divide by two, I can argue that the "average" is either +90 or -90. Which one do you think it should be?

    If I add the vectors according to the rules of vector addition (component by component), I get the following:

    (1, 0) + (-1, 0) = (0, 0)

    In polar coordinates, that's a vector with zero magnitude and angle zero.

    So what should the "average" angle be? I've got three different answers here for a simple case.

    I think the answer is that vectors don't obey the same intuition that numbers do, because they have both magnitude and direction. Maybe you should describe what problem you're solving a bit better.

    Whatever solution you decide on, I'd advise you to base it on vectors. It'll always be correct that way.

    0 讨论(0)
  • 2020-12-14 09:14

    Edit: Equivalent, but more robust algorithm (and simpler):

    1. divide angles into 2 groups, [0-180) and [180-360)
    2. numerically average both groups
    3. average the 2 group averages with proper weighting
    4. if wraparound occurred, correct by 180˚

    This works because number averaging works "logically" if all the angles are in the same hemicircle. We then delay getting wraparound error until the very last step, where it is easily detected and corrected. I also threw in some code for handling opposite angle cases. If the averages are opposite we favor the hemisphere that had more angles in it, and in the case of equal angles in both hemispheres we return None because no average would make sense.

    The new code:

    def averageAngles2(angles):
        newAngles = [a % 360 for a in angles];
        smallAngles = []
        largeAngles = []
        # split the angles into 2 groups: [0-180) and [180-360)
        for angle in newAngles:
            if angle < 180:
                smallAngles.append(angle)
            else:
                largeAngles.append(angle)
        smallCount = len(smallAngles)
        largeCount = len(largeAngles)
        #averaging each of the groups will work with standard averages
        smallAverage = sum(smallAngles) / float(smallCount) if smallCount else 0
        largeAverage = sum(largeAngles) / float(largeCount) if largeCount else 0
        if smallCount == 0:
            return largeAverage
        if largeCount == 0:
            return smallAverage
        average = (smallAverage * smallCount + largeAverage * largeCount) / \
            float(smallCount + largeCount)
        if largeAverage < smallAverage + 180:
            # average will not hit wraparound
            return average
        elif largeAverage > smallAverage + 180:
            # average will hit wraparound, so will be off by 180 degrees
            return (average + 180) % 360
        else:
            # opposite angles: return whichever has more weight
            if smallCount > largeCount:
                return smallAverage
            elif smallCount < largeCount:
                return largeAverage
            else:
                return None
    

     

    >>> averageAngles2([0, 0, 90])
    30.0
    >>> averageAngles2([30, 350])
    10.0
    >>> averageAngles2([0, 200])
    280.0
    

    Here's a slightly naive algorithm:

    1. remove all oposite angles from the list
    2. take a pair of angles
    3. rotate them to the first and second quadrant and average them
    4. rotate average angle back by same amount
    5. for each remaining angle, average in same way, but with successively increasing weight to the composite angle

    some python code (step 1 not implemented)

    def averageAngles(angles):
        newAngles = [a % 360 for a in angles];
        average = 0
        weight = 0
        for ang in newAngles:
            theta = 0
            if 0 < ang - average <= 180:
                theta = 180 - ang
            else:
                theta = 180 - average
            r_ang = (ang + theta) % 360
            r_avg = (average + theta) % 360
            average = ((r_avg * weight + r_ang) / float(weight + 1) - theta) % 360
            weight += 1
        return average
    

    0 讨论(0)
  • I think the problem stems from how you treat angles greater than 180 (and those greater than 360 as well). If you reduce the angles to a range of +180 to -180 before adding them to the total, you get something more reasonable:

    int AverageOfAngles(int angles[], int count)
    {
        int total = 0;
        for (int index = 0; index < count; index++)
        {
            int angle = angles[index] % 360;
            if (angle > 180) { angle -= 360; }
            total += angle;
        }
    
        return (int)((float)total/count);
    }
    
    0 讨论(0)
  • 2020-12-14 09:22

    Maybe you could represent angles as quaternions and take average of these quaternions and convert it back to angle.

    I don't know If it gives you what you want because quaternions are rather rotations than angles. I also don't know if it will give you anything different from vector solution.

    Quaternions in 2D simplify to complex numbers so I guess It's just vectors but maybe some interesting quaternion averaging algorithm like http://ntrs.nasa.gov/archive/nasa/casi.ntrs.nasa.gov/20070017872_2007014421.pdf when simplified to 2D will behave better than just vector average.

    0 讨论(0)
  • 2020-12-14 09:24

    [Note the OP's question (but not title) appears to have changed to a rather specialised question ("...the average of a SEQUENCE of angles where each successive addition does not differ from the running mean by more than a specified amount." ) - see @MaR comment and mine. My following answer addresses the OP's title and the bulk of the discussion and answers related to it.]

    This is not a question of logic or intuition, but of definition. This has been discussed on SO before without any real consensus. Angles should be defined within a range (which might be -PI to +PI, or 0 to 2*PI or might be -Inf to +Inf. The answers will be different in each case.

    The world "angle" causes confusion as it means different things. The angle of view is an unsigned quantity (and is normally PI > theta > 0. In that cases "normal" averages might be useful. Angle of rotation (e.g. total rotation if an ice skater) might or might not be signed and might include theta > 2*PI and theta < -2*PI.

    What is defined here is angle = direction whihch requires vectors. If you use the word "direction" instead of "angle" you will have captured the OP's (apparent original) intention and it will help to move away from scalar quantities.

    Wikipedia shows the correct approach when angles are defined circularly such that

    theta = theta+2*PI*N = theta-2*PI*N
    

    The answer for the mean is NOT a scalar but a vector. The OP may not feel this is intuitive but it is the only useful correct approach. We cannot redefine the square root of -4 to be -2 because it's more initutive - it has to be +-2*i. Similarly the average of bearings -90 degrees and +90 degrees is a vector of zero length, not 0.0 degrees.

    Wikipedia (http://en.wikipedia.org/wiki/Mean_of_circular_quantities) has a special section and states (The equations are LaTeX and can be seen rendered in Wikipedia):

    Most of the usual means fail on circular quantities, like angles, daytimes, fractional parts of real numbers. For those quantities you need a mean of circular quantities.

    Since the arithmetic mean is not effective for angles, the following method can be used to obtain both a mean value and measure for the variance of the angles:

    Convert all angles to corresponding points on the unit circle, e.g., α to (cosα,sinα). That is convert polar coordinates to Cartesian coordinates. Then compute the arithmetic mean of these points. The resulting point will lie on the unit disk. Convert that point back to polar coordinates. The angle is a reasonable mean of the input angles. The resulting radius will be 1 if all angles are equal. If the angles are uniformly distributed on the circle, then the resulting radius will be 0, and there is no circular mean. In other words, the radius measures the concentration of the angles.

    Given the angles \alpha_1,\dots,\alpha_n the mean is computed by

    M \alpha = \operatorname{atan2}\left(\frac{1}{n}\cdot\sum_{j=1}^n
    

    \sin\alpha_j, \frac{1}{n}\cdot\sum_{j=1}^n \cos\alpha_j\right)

    using the atan2 variant of the arctangent function, or

    M \alpha = \arg\left(\frac{1}{n}\cdot\sum_{j=1}^n
    

    \exp(i\cdot\alpha_j)\right)

    using complex numbers.

    Note that in the OP's question an angle of 0 is purely arbitrary - there is nothing special about wind coming from 0 as opposed to 180 (except in this hemisphere it's colder on the bicycle). Try changing 0,0,90 to 289, 289, 379 and see how the simple arithmetic no longer works.

    (There are some distributions where angles of 0 and PI have special significance but they are not in scope here).

    Here are some intense previous discussions which mirror the current spread of views :-)

    http://mathforum.org/library/drmath/view/53924.html

    How do you calculate the average of a set of circular data?

    http://forums.xkcd.com/viewtopic.php?f=17&t=22435

    http://www.allegro.cc/forums/thread/595008

    0 讨论(0)
提交回复
热议问题