Thursday, August 8, 2013

Consensus Averaging vs. Vector Averaging

One Wire Weather Service for Java has been using Consensus Averaging to smooth wind vane data and increase device resolution, from its initial implementation several years ago. I thought it gave good results, although the algorithm proved difficult for me to analyze clearly.

I was reviewing some weather data recently, and I noticed that the wind direction seemed to have slight but noticeable affinity for the sixteen primary compass points. Since nature doesn't do that, I had to suspect a problem with the hardware or software. I decided to start with the software, since that's easier to tweak. I began looking for angle averaging algorithms on the web, simply to get an idea of what kinds of solutions other people had come up with. There are several, some of them quite convoluted, home-brew algorithms. However, I found several similar examples of vector averaging. 

Vector averaging entails converting each angle (wind compass heading from the wind vane) to a vector on the unit circle, and finding the x and y coordinates, averaging the coordinates, and taking the arc tangent, converting them back to an angle. The code to do this is actually very simple.

    /**
     * Calculates the average value by converting the angles to 
     * vectors on the unit circle and averaging the Cartesian 
     * coordinates. This avoids the 360~0 wrap-around at North. 
     * Math.atan2 returns the angle between -pi and pi. Therefore, 
     * we add tau to the result to force a positive angle, mod by
     * tau and convert to degrees.
     * @param data array of sensor data to average.
     * @return average directional value.
     */
    public double averageValue(double[] data) {
        int length = data.length;
        double sin = 0, cos = 0;

        for (int ii = 0; ii < length; ii++) {
            sin += Math.sin(data[ii]);
            cos += Math.cos(data[ii]);
        }
        double theta = Math.atan2(sin / length, cos / length);

        return Math.toDegrees((tau + theta) % tau);
    }

where tau = 2π.

One of the main reasons for averaging wind vane data is that the resolution of the wind vane itself is very coarse - only 16 compass points. But wind is turbulent, so the wind vane swings back and forth over several points. This turbulence dithers the data, so the average has a much higher resolution.

I mentioned earlier that consensus averaging did increase the wind vane resolution, but some affinity remained. I had difficulty analyzing the algorithm, so it wasn't obvious to me how to modify it. But the vector averaging algorithm appears to exhibit no affinity; the output is completely de-correlated, without requiring any tweaks or tuning. It "just works".

Vector averaging does have one potential problem: if two vectors are 180 degrees out of phase, they will cancel out, yielding an undefined angle. Fortunately, we have about 40 data points for each average sample. In order for the average to be zero, all of the vectors would have to be in opposition. That would be exceedingly unlikely for a wind vane that is supposed to point into the wind, even with very low air motion. The widest wind vane swing is about 90 degrees over relatively short time periods (e.g., a two minute averaging interval).

Update: I found out from the authors of consensus averaging that the original implementation did not have the benefit of a software math library with floating point arithmetic and trigonometric functions. That makes all the difference in the world. Necessity is a mother ... ~ KU

No comments :

Post a Comment