Smoothing Accelerometer Readings

,

The Accelerometer’s CurrentValueChanged event is raised, by default, 50 times a second and reflects the raw hardware sensor readings. Updating UI elements based on the raw values from the accelerometer can make elements appear jittery, much like the effects of Brownian motion under a microscope. You can allow your app to appear more stable by smoothing the readings received by the accelerometer through ignoring small changes in acceleration.

Some apps may benefit from some degree of smoothing, yet may need to react quickly to sudden fluctuations in reading values, such as games, which usually need input to be as direct as possible. This section looks at applying various data smoothing techniques to reduce jitter while also minimizing latency.

Much of the code and theory in this section is based on an article on the Windows Team Blog by Dave Edson at http://bit.ly/cXJ2EC. It is recommended that you take a look at the article to better understand the theory behind the smoothing algorithms employed in the sample code. The advantage of the sample code provided here is that you also have a number of other features included that you can take and use immediately in your own apps.

The example code for this section is located in the Devices/Sensors directory of the WPUnleashed project in the downloadable sample code.

In the example, a custom class called EnhancedAccelerometer is used in place of the built-in Accelerometer. The EnhancedAccelerometer class uses an Accelerometer, allowing the application of smoothing algorithms based on previous readings. EnhancedAccelerometer has a number of features that the Accelerometer does not, such as calibration support, shake detection, and data smoothing.

Like the Accelerometer, the EnhancedAccelerometer is IDisposable. When the EnhancedAccelerometer is disposed, it in turn disposes the built-in Accelerometer. So, too, EnhancedAccelerometer is started by calling its Start method, which instantiates an Accelerometer, subscribes to its CurrentValueChanged event, and starts the Accelerometer as shown:

public void Start()
{
    if (accelerometer == null)
    {
        lock (accelerometerLock)
        {
            if (accelerometer == null)
            {
                accelerometer = new Accelerometer();
                accelerometer.CurrentValueChanged
                                        += HandleSensorValueChanged;
                accelerometer.Start();
            }
        }
    }
}

EnhancedAccelerometer has a Reading property of type EnhancedAccelerometerReading, which not only supplies the raw value supplied by the Accelerometer, but also the following three smoothed reading values:

Image AverageAcceleration

Image LowPassFilteredAcceleration

Image OptimallyFilteredAcceleration

Each value is the result of the application of a particular smoothing algorithm. The first, AverageAcceleration, has the highest latency (lag) of the three, while the other two attempt to combat the latency by responding to large reading variations immediately so that you get smoothing as well as responsiveness. These properties are examined in greater detail in the following sections.

AverageAcceleration

The AverageAcceleration property provides an average value of the last 25 readings. As stated, this approach has the highest latency; a large change in acceleration is less evident as the previous readings average it out. This approach may suit an app that requires input to be very steady—a spirit level app for example—but would not be suitable for a game that needs to respond quickly to user input.

LowPassFilteredAcceleration

The LowPassFilteredAcceleration property is calculated using the current reading and the previously calculated output. This approach has less latency than averaging, yet still does not respond to large changes in acceleration immediately.

The EnhancedAccelerometer.LowPassFilterCoefficient property allows you to adjust the level of smoothing applied to the output value. Each reading dimension value is calculated like so:

double newOutputValue = priorOutputValue
   + LowPassFilterCoefficient * (newInputValue - priorOutputValue);

By decreasing the LowPassFilterCoefficient, the more smoothing is applied.

OptimallyFilteredAcceleration

The OptimallyFilteredAcceleration property uses a low pass filter in conjunction with a threshold value, which causes the output value to be set to the raw reading immediately if the reading exceeds the threshold value. This approach eliminates the latency of the pure low pass approach for sharp changes in acceleration.

If the difference between a new reading and the previous output is greater than the noise threshold, the raw value is used, as shown in the following excerpt:

double ApplyLowPassFilterWithNoiseThreshold(
              double newInput, double previousOutput)
{
    double newOutputValue = newInput;
    if (Math.Abs(newInput - previousOutput) <= NoiseThreshold)
    {
        /* A simple low-pass filter. */
        newOutputValue = previousOutput
              + LowPassFilterCoefficient * (newInput - previousOutput);
    }
    return newOutputValue;
}

The noise threshold of the filter can be adjusted using the EnhancedAccelerometer.NoiseThreshold property. Its default value is 0.05, and by increasing the value you increase the level of acceleration needed to produce an immediate response.

..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset
3.22.60.167