Low Pass Filter: Linear Acceleration

Android Accelerometer: Low-Pass Filter Estimated Linear Acceleration

Discussing how a low-pass filter can be used to separate the gravity and linear acceleration components of the raw acceleration signal from the device sensor. 

Author: Kaleb Kircher

Version: 3.0

4.8.14.3.0

Refactoring History

v1.0 1.14.13.1.0 Kaleb Kircher Authored
v2.0 7.15.13.2.0 Kaleb Kircher Refactored
v3.0 4.8.14.3.0 Kaleb Kircher Refactored

Copyright: 2012-2015 Kircher Engineering, LLC

Relevant Code and Projects:

Acceleration Explorer:

Low Pass Linear Acceleration Promotional Graphic

Acceleration Explorer is an Android code example and working application. The application allows users to plot and log the outputs from the devices acceleration sensor and low-pass filter based linear acceleration in real-time. The settings on the low-pass filter can be defined by the user allowing low-pass filter based linear acceleration algorithms to be quickly fine-tuned across multiple devices.

You can download Acceleration Explorer from the Google Play store for free!

You can fork the source code for Acceleration Explorer from GitHub!

Linear Acceleration:

An accelerometer can measure the static gravitation field of earth (like a tilt sensor) or it can measure measure linear acceleration (like accelerating in a vehicle), but it cannot measure both at the same time. When talking about linear acceleration in reference to an acceleration sensor, what we really mean is Linear Acceleration = Measured Acceleration - Gravity (so we can determine the actual acceleration of the device no matter how the device is oriented/tilted). The hard part is determining what part of the signal is gravity.

The Problem:

It is difficult to sequester the gravity component of the signal from the linear acceleration. Some Android devices implement Sensor.TYPE_LINEAR_ACCELERATION  and Sensor.TYPE_GRAVITY which perform the calculations for you. Most of these devices are new, high-end and equipped with a gyroscope. It is also worth noting that Sensor.TYPE_LINEAR_ACCELERATION does not actually work very well while the device is accelerating on many devices I have tested. This is because the acceleration sensor is often used to compensate for the drift of the gyroscope, which causes a feedback loop between the two sensors. When the device is accelerating, the drift compensating algorithm assumes the device is actually tilted, instead of accelerating, and begins to compensate the gyroscope erroneously. This is, however, beyond the scope of the article.

If you have and older device and do not have a gyroscope, you are going to face some limitations with Sensor.TYPE_ACCELERATION. The tilt of the device can only be measured accurately assuming the device is not experiencing any linear acceleration. The linear acceleration can only be measured accurately if the tilt of the device is known. We can, however, estimate the tilt with a low-pass filter and apply the corrections selectively. This implementation can be very advantageous because when it is tuned correctly, it works very well and only uses the one acceleration sensor instead of relying on sensor fusions.

A Low-Pass Filter Solution:

In theory, the force of gravity can be isolated with a low-pass filter and then the gravity can be subtracted from the raw signal, essentially creating a high-pass filter that isolates the linear acceleration. Android Developer documentation gives an example of an implementation that can be found here.

The Code:

*Note how the sample period is calculated using an averaging method. This is done because the sample period between two consecutive updates (sampleTimeNew-sampleTimeOld) is very inconsistent. The averaging method gives a much more steady estimation of the sample period.

       
// Constants for the low-pass filters
private float timeConstant = 0.18f;
private float alpha = 0.9f;
private float dt = 0;

// Timestamps for the low-pass filters
private float timestamp = System.nanoTime();
private float timestampOld = System.nanoTime();

// Gravity and linear accelerations components for the
// Wikipedia low-pass filter
private float[] gravity = new float[]
{ 0, 0, 0 };

private float[] linearAcceleration = new float[]
{ 0, 0, 0 };

// Raw accelerometer data
private float[] input = new float[]
{ 0, 0, 0 };

private int count = 0;

/**
* Add a sample.
* 
* @param acceleration
*            The acceleration data.
* @return Returns the output of the filter.
*/
public float[] addSamples(float[] acceleration)
{
// Get a local copy of the sensor values
System.arraycopy(acceleration, 0, this.input, 0, acceleration.length);

timestamp = System.nanoTime();

// Find the sample period (between updates).
// Convert from nanoseconds to seconds
dt = 1 / (count / ((timestamp - timestampOld) / 1000000000.0f));

count++;
		
alpha = timeConstant / (timeConstant + dt);

gravity[0] = alpha * gravity[0] + (1 - alpha) * input[0];
gravity[1] = alpha * gravity[1] + (1 - alpha) * input[1];
gravity[2] = alpha * gravity[2] + (1 - alpha) * input[2];

linearAcceleration[0] = input[0] - gravity[0];
linearAcceleration[1] = input[1] - gravity[1];
linearAcceleration[2] = input[2] - gravity[2];

return linearAcceleration;
}

If this does not look familiar to you, you can review my other posts on Low-Pass Filters: The Basics and Low-Pass Filters: Optimizing Alpha. On paper, this algorithm is fantastically more simple than alternative approaches, like Cardan angles with sensor fusions, that require a significant amount of trigonometry.

Linear Acceleration and Rotation:

Alpha 0.9:

Static Tilt:

For testing, a Droid Razr with an update frequency of about 50Hz was used. The algorithm implements the Wikipedia version of the low-pass filter with a filter time constant of 0.002 seconds. The time constant produces an alpha of about 0.9. Assuming no linear acceleration is being experienced by the accelerometer, the low-pass filter can effectively sequester gravity from linear acceleration. We can see that when the device was tilted on axis, the accelerometer measured the tilt while the low-pass filter did not. This is because almost everything is passing through the filter, which means the acceleration is essentially being subtracted from itself.

The effect of the LPF is most visible on the Y-axis (the color green). You can see the dark green line (the raw acceleration) is moving a lot as the device is tilted back and forth. The light green line (the LPF linear acceleration) moves very little relative to the raw acceleration as it is compensating for the tilt of the device. You can also see this effect in the tilt gauges where the gauge on the left (raw acceleration) is titled heavily with the device and the gauge on the right (the LPF linear acceleration) is compensating for the tilt.

Note that while this configuration works well for demonstrating the tilt compensation of the LPF, the time constant is so short it is effectively just subtracting the acceleration from itself. This means that if you actually tried to measure true linear acceleration with this configuration, it wouldn't work very well at all.

Linear Acceleration:

While the gravity estimation is responsive with alpha at .9 and a time constant of 0.002 seconds, it is very poor at estimating actual linear acceleration. In order to effectively measure linear acceleration, the gravity estimation needs to be much more stiff, i.e it needs to be less responsive. You can see this most clearly with the Y-axis. The dark green line is the raw acceleration when the phone is accelerated back and forth and the light green line is the LPF linear acceleration. We can see that the light green line significantly under estimates the actual linear acceleration.

Alpha 0.1:

Static Tilt:

With a time constant of 0.18 seconds and an alpha of 0.1, the gravity estimation of much more stable. It takes longer for the tilt to compensate, but it will be more effective at measuring linear acceleration (at least for short periods of time).

Linear Acceleration:

With the gravity estimation more stable, estimation of the linear acceleration becomes more effective. As alpha decreases, the time constant will increase, increasing the lag time and stability/stiffness of the gravity estimation. We can see this most clearly on the Y-axis (green lines). While the device was tilted at 45 degrees, the light green line (LPF linear acceleration) was close to the amplitude of the dark green line (raw acceleration) while the device was being accelerated back and forth.

While this implementation works well for short periods of time, you run into a wall of sorts when trying to measure linear acceleration for extended periods of time. This would require an extremely long time constant, and the tilt compensation would take an extremely long time... to the point where the purpose of the low-pass filter is defeated. However, you can work around this by only applying the low-pass filter compensations when the device is not experiencing linear acceleration by analyzing the variance or magnitude (or both) of the acceleration sensor inputs. This is beyond the scope of this article.