Android Accelerometer

Android Accelerometer Noise, Offset and Skew:

This article discusses software development with the use of acceleration sensors on Android devices.

Author: Kaleb Kircher

Version: 3.0

4.3.14.3.0

Refactoring History:

v1.0 1.7.13.1.0 Kaleb Kircher Authored
v2.0 7.5.13.2.0 Kaleb Kircher Refactored
v3.0 4.3.14.3.0 Kaleb Kircher Refactored

Copyright: 2012-2014 Kircher Engineering, LLC

Associated Applications Projects: 

Acceleration Explorer for Android:

 Acceleration Explorer 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 in real-time. The diagnostic mode allows the user to investigate the noise, offset and skew associated with the acceleration sensor.

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

Google Play icon

You can fork the Acceleration Explorer source code from GitHub!

GitHub icon

Accelerometer Introduction:

An accelerometer is an electromechanical device that measures acceleration forces in units of meters/sec2 or G-force (the gravity of earth) which is about 9.8 m/s2. Accelerometers measure both the static acceleration, like the gravity field of earth, and dynamic acceleration caused by the movement of the accelerometer. In fact, the accelerometer cannot differentiate between static and dynamic acceleration. This means an accelerometer can be used to determine the tilt of the device by measuring static acceleration or the linear acceleration of the device by measuring dynamic acceleration. However, an accelerometer cannot measure both static and dynamic acceleration at the same time. Accelerometers usually measure acceleration/gravity it two or three-axis, but on Android devices it is almost always three-axis. They can be used to detect the orientation of the device, determine if the device is in free fall, control objects in a game, tap detection, measure acceleration, etc…

How Accelerometers Work:

There are a number of different implementations of accelerometers available. Some rely on the capacitance between two objects. If a force from acceleration moves one of the objects, the capacitance between the objects will change. This capacitance can be converted to a voltage which can then be used to measure the force of the acceleration. Another implementation of accelerometers uses piezoelectric effect which rely on crystal structures that produce a voltage when an acceleration force is applied to them. More advanced accelerometers use lasers to measure acceleration.

Digital and Analog Accelerometers:

Accelerometers with an analog output will produce a voltage that is directly proportional to the sensed acceleration. Digital accelerometers usually feature a serial interface be it SPI or I²C. Some digital accelerometers use pulse width modulation (PWM) for their output. This means there will be a square wave of a certain frequency, and the amount of time the voltage is high will be proportional to the amount of acceleration. Digital accelerometers are advantageous because they are less susceptible to noise than their analog counterparts.

The Code:

On Android devices, we can access the devices accelerometer sensor data with the following code. Note that here we are requesting the fastest possible update frequency. Also note that the sensor events are registered in onResume() and removed in onPause(). This is done so the acceleration sensor is stopped when the user navigates away from the activity to save battery life.

public class AccelerationActivity extends Activity implements SensorEventListener
{

	private float[] acceleration = new float[3];

	float time = System.nanoTime();
	float timeOld = System.nanoTime();
	int count = 0;

	private SensorManager sensorManager;

	@Override
	protected void onCreate(Bundle savedInstanceState)
	{
		super.onCreate(savedInstanceState);
		setContentView(R.layout.activity_main);

		sensorManager = (SensorManager) this
				.getSystemService(Context.SENSOR_SERVICE);

		sensorManager.registerListener(this,
				sensorManager.getDefaultSensor(Sensor.TYPE_ACCELEROMETER),
				SensorManager.SENSOR_DELAY_FASTEST);

	}

	public void onResume()
	{
		sensorManager.registerListener(this,
				sensorManager.getDefaultSensor(Sensor.TYPE_ACCELEROMETER),
				SensorManager.SENSOR_DELAY_FASTEST);
	}

	public void onPause()
	{
		sensorManager.unregisterListener(this);
	}

	@Override
	public void onSensorChanged(SensorEvent event)
	{
		if (event.sensor.getType() == Sensor.TYPE_ACCELEROMETER)
		{
			// Get a local copy of the acceleration measurements
			System.arraycopy(event.values, 0, acceleration, 0,
					event.values.length);

			time = System.nanoTime();

			// The event timestamps are irregular so we average to determine the
			// update frequency instead of measuring deltas.
			double frequency = count++ / ((time - timeOld) / 1000000000.0);

		}
	}

	@Override
	public void onAccuracyChanged(Sensor sensor, int accuracy)
	{
		// TODO Auto-generated method stub
		
	}
}

Noise and Filters:

Noise:

Android devices black-box (meaning we have no idea what is actually going on under the hood, we just get the sensor outputs)  their sensor implementations and they vary by the model and manufacturer. Filters may or may not be applied to sensors before providing an output, and some sensors even have filters designed into them. It is useful to have some idea of what kind of filtering is already occurring in cases where we would like to do filtering of our own. Knowing how much noise exists on the sensor outputs is a good place to start.

A fair amount of information can be gained by determining what hardware is being used on the Android device and then referring to data sheets to determine the expected noise density of the sensor. The noise density, denoted in units of ug/sqrt(Hz), is defined as the noise per unit of square root bandwidth and can be used to determine the expected noise output from a sensor. To determine the expected noise output from noise density, we take the equivalent noise bandwidth, B, of the output filter. The equivalent noise bandwidth of a filter is the -3dB bandwidth multiplied by a coefficient corresponding to the order of the filter. The coefficients are as follows:

B = 1.57 * f-3dB for a 1st order filter
B = 1.11 * f-3dB for a 2nd order 
B = 1.05 * f-3dB for a 3rd order filter
B = 1.025 * f-3dB for a 4th order filter

Filters:

low-pass filter eliminates all frequencies above a cut-off frequency, while all other frequencies pass through altered. This makes them ideal for eliminating noise that occurs above a certain frequency. A first order filter reduces the signal amplitude by half every time the frequency doubles. A second order filter attenuates higher frequencies more steeply resulting in a signal that is one fourth the original level every time the frequency doubles. There are different versions of a low-pass filter, but a common implementation found on Wikipedia is xOld = xOld * alpha + (1-alpha) * xNew. When alpha is very small, the effect of the filter is small, the response is very quick and changes in the input are allowed to build up very quickly. When alpha is close to 1, the effect of the filter is large, the response is very slow and changes in the input are allowed to build up very slowly. Implemented in Java, the low-pass filter looks like this:

public class LowPassFilter
{
	private float alpha;
	private float[] acceleration;
	
	public float[] lowPassFilter(float[] input)
	{
		// Update the Android Developer low-pass filter
		// y[i] = y[i] * alpha + (1 - alpha) * x[i]
		this.acceleration[0] = alpha * acceleration[0]
				+ (1 - alpha) * input[0];
		this.acceleration[1] = alpha * acceleration[1]
				+ (1 - alpha) * input[1];
		this.acceleration[2] = alpha * acceleration[2]
				+ (1 - alpha) * input[2];
		
		return acceleration;
	}
}

Android Accelerometers:

Applying low-pass filters to Android accelerometers is unfortunately not as straightforward as setting alpha to a static value and moving on. Android devices are equipped with different acceleration sensors, each with their own noise density and output frequency, and this means that more attention needs to be given to the alpha value as these factors will change the behavior of the low-pass filter, however this is beyond the scope of this article.

Device Sensor Noise Density Maximum Output Frequency
Nexus 4 MPU-6050 400ug/sqrt(Hz) 193Hz
Galaxy S4 Bosch Sensortec 150ug/sqrt(Hz) 100Hz
Droid Razr STMircoelectronics LIS2DH 220ug/sqrt(Hz) 50Hz

The results from testing the noise on the devices acceleration sensors correlates with the specified noise densities. In the case of an accelerometer, if you apply a 50 Hz first order low pass filter to the outputs of Nexus 4 MPU-6050 accelerometer (ND = 400 ug/sqrt(Hz)) the expected noise would be (400 ug/sqrt(Hz)) * sqrt(1.57 *50 Hz) = 3544 ug. This is the RMS sensor dependent noise expected on the outputs of the MPU-6050. The actual noise seen on the sensor outputs may be larger than this reported error due to environmental noise (thermal, Vdd regulation, mechanical accelerations) on the sensor.

Device Expected Noise Measured Noise
Nexus 4 3544ug 2390ug
Galaxy S4 1329ug 1430ug
Droid Razr 1949ug 1680ug

Sensor Accuracy and Offset:

The accuracy of a sensor and the offset of a sensor can manifest in a similar way. A reasonably accurate acceleration sensor would measure the gravity of earth when the axis of the sensor was pointed straight up towards the sky. Determining the accuracy is a little more complicated than this because the gravity of earth actually changes slightly depending where on earth you are and because of sensor offset. If the positive axis of a an acceleration sensor over-estimates the gravity of earth, and the negative axis of the same sensor under-estimates the gravity of earth (or vise versa), there is likely some offset occurring where the center of the axis is slight skewed towards the positive or negative axis.

Accuracy:

First, we can ignore offset and look at the accuracy of one axis of the acceleration sensor and assume gravity is equal to 9.78 m/s2.

Nexus 4 MPU-6050:

We can see that the positive z-axis of the Nexus 4 MPU-6050 slightly over-estimates the acceleration of Earth's gravity.

Nexus 4 MPU-6050 gravity measurement

Offset:

Now we can take offset into consideration by looking at the accuracy of both the positive and negative axis of an acceleration sensor... again, assuming gravity is equal to 9.78 m/s2.

Droid Razr STMircoelectronics LIS2DH:

We can see that the positive z-axis is slightly under-estimating gravity while the negative z-axis is slightly over-estimating gravity indicating there is a small amount of sensor offset occurring (the center of the axis is shifted slightly towards the positive axis) in addition to a small degree of inaccuracy in the measurements. Although the errors are small, in an scenario where you would want to integrate the measurements, say to calculate the velocity, the errors begin to compound and become large over a period of time. There are methods to help correct for the accuracy and the offset, but they are beyond the scope of this article.

Droid Razr acceleration sensor offset

Sensor Skew:

Sensor skew is the most difficult subject to visualize and to compensate for. It is related to both the accuracy and the offset of the sensor and occurs because some of the axis of the sensor might under-estimate or over-estimate acceleration measurements more than others. In two dimensions, a perfectly accurate acceleration sensor would measure exactly 9.78 m/son the negative and positive axis of X and Y. In units of G's, where 1G = 9.78 m/s2, you could visualize this as a unit circle, centered on the point 0,0 with a radius of 1.

Unit Circle

Since acceleration sensors are imperfect because of noise, offset and skew the unit circle that we would see in a perfect world becomes something that looks like an oval that is offset from the center point 0,0. 

Acceleration Sensor Unit Circle Skew

The skew can be compensated for, to some extent, by scaling the oval back into a circle and transforming that circle onto the center point 0,0, but this is beyond the scope of this article.