Posted by: Yanyan | January 1, 2013

Accelerometer Sensor Data Processing

Happy New Year and Gong Hee Fot Choy!

In the past few days I have been playing with accelerometer sensor on my Galaxy Nexus. On MEMS sensors, acceleration is measured by attaching a mass to springs and seeing how far the mass deviates from its equilibrium position. It is then easy to see why an accelerometer in free-fall will report zero acceleration even though it is still subject to Earth’s gravity. Data is collected in 3 dimensions X/Y/Z. The default orientation for phones is portrait, but this is not true of most tablets. However, even for a device that has a default orientation of landscape, the axes will still be orientated as Y pointing up, X pointing to the right, and Z pointing out of the screen.

On Android, to collect data from any sensor, an app needs to register a SensorEventListener to receive sensor data, extract data from SensorEvent depending on the sensor type, and ensure that an app unregisters at the right time. It can be implemented like so:

public class AccelerationEventListener implements SensorEventListener {

@Override
public void onSensorChanged(SensorEvent event) {
float[] values = event.values.clone();

}

}

values[0] to values[2] will have the data from X, Y and Z axes. However, the raw sensor data can be erroneous, containing background noise, drift, and of course Z value has the extra g m/s^2. I plotted the value of accelerometer when the phone is lying on the desk. The result is very obvious.

Screenshot_2013-01-01-14-02-46

First, to mitigate some errors and spikes in data, in many cases an app may rely on some form of smoothing or averaging, also known as low-pass filtering (it filters out high-frequency noise and “passes” low-frequency or slowly varying changes). Very much the same way in signal processing in Electrical Engineering. The simplest form of low-pass filter is by a weighted smoothing. Define a smoothing parameter (or weighting value) a, a value from 0 to 1, such that (New mean) = (Last value) * (1– a) + xi * a, and can be implemented as

float[] lowPass(float x, float y, float z) {

float[] filteredValues = new float[3];

filteredValues[0] = x * a + filteredValues[0] * (1.0f – a);
filteredValues[1] = y * a + filteredValues[1] * (1.0f – a);
filteredValues[2] = z * a + filteredValues[2] * (1.0f – a);

return filteredValues;

}

To be slightly more complicated, you can do a moving average of the last k values of sensor data as the filtered data. On the other hand, the simplest way perform high-pass filtering is to do a low-pass filter and then subtract the result from the sensor data. The following code is from Android doc to filter out the constant down-ward gravity component of the accelerometer data and keep the higher-frequency transient changes.

private float[] highPass(float x, float y, float z) {

float[] filteredValues = new float[3];

gravity[0] = ALPHA * gravity[0] + (1 – ALPHA) * x;
gravity[1] = ALPHA * gravity[1] + (1 – ALPHA) * y;
gravity[2] = ALPHA * gravity[2] + (1 – ALPHA) * z;

filteredValues[0] = x – gravity[0];
filteredValues[1] = y – gravity[1];
filteredValues[2] = z – gravity[2];

return filteredValues;

}

Of course, with the high and low-pass filter, there will be something to do them both, and this is bandpass filter. In its simplest incarnation, and in the form most useful for most Android sensor applications, it is simply a combination of a low-pass and high-pass filter. Data is first filtered to keep the higher-frequency components, and then the very high-frequency noise is filtered out with a low-pass smoothing filter. Some screenshots show the result of applying one of both of the filters.

Screenshot_2013-01-01-13-39-30 Screenshot_2013-01-01-13-39-57 Screenshot_2012-12-31-22-01-39

BTW, the Linear Acceleration Sensor is a synthetic sensor provided by Android which factors out the force due to gravity. It is available from Android 2.3 (API level 9).

Advertisements

Responses

  1. Hi , first of all I appreciate such an informing post .
    1) Could you please tell how you get the gravity[]array ?
    2) How did you find out the acceleration value ? is it the vector of AccX,Y and Z?
    3) I could not understand the difference between Sensor.TYPE_ACCELEROMETER and Linear Acceleration Sensor, because I seem to get similar results (gravity included) for both .

    Regards,

    SAMA

  2. […] friend asked me a few questions on an earlier post on Accelerometer Sensor Data Processing. I think it’s probably better explained by a follow up […]

  3. Hi,
    does and when how does this work for things like iPad and iPhone?

    • We currently only support Android, but an iPhone version will appear soon.

  4. As someone who is familiar with capturing the accelerometer sensor data, this really helped me out with what I am currently working on. Thank you!

  5. The article is really good, but need to clarify some things..
    how did you get gravity[ ] values? and what ALPHA?

  6. is the source of the app on screenshots available somewhere? would help me a lot.


Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out /  Change )

Google+ photo

You are commenting using your Google+ account. Log Out /  Change )

Twitter picture

You are commenting using your Twitter account. Log Out /  Change )

Facebook photo

You are commenting using your Facebook account. Log Out /  Change )

Connecting to %s

Categories

%d bloggers like this: