I have a very basic question. What is Low Pass filter and High Pass filter in case of Android Accelerometer?
When I see the output from the Accelerometer Sensor, I
Low Pass Filter: passes low-frequency signals and reduces the amplitude of signals with frequencies higher than the threshold frequency
High Pass Filter: passes high-frequency signals and reduces the amplitude of signals with frequencies lower than the threshold frequency
If you look at the documentation, it says: "in order to measure the real acceleration of the device, the contribution of the force of gravity must be eliminated. This can be achieved by applying a high-pass filter. Conversely, a low-pass filter can be used to isolate the force of gravity."
You could check out this tutorial on low pass filtering: http://www.raweng.com/blog/2013/05/28/applying-low-pass-filter-to-android-sensors-readings/
Reading the docs at http://developer.android.com/reference/android/hardware/SensorEvent.html#values, you can see that you can access the a values on all x,y,z axis by doing:
values[0] - a on x axis
values[1] - a on y axis
values[2] - a on z axis
Output of accelerometer includes noise if you subtract directly from these values that include noise. To eliminate noise it is required to implement highpass and lowpass filters.
If you look at the documentation you will see that SensorEvent returns an array which represents the vector of all the forces. http://developer.android.com/reference/android/hardware/SensorEvent.html#values This is how the components of the acceleration break down into each axis:
values[0] //acceleration on x axis
values[1] //acceleration on y axis
values[2] //acceleration on z axis
You need to find which direction gravity is operating in then decompose that into its component parts. The magnitude of the gravity force will always be 9.8 but the direction, and hence how it breaks down into the component parts, will change. Assuming that we could get the value of gravity and store that vector in an array like gravity[3]
:
gravity[0] //gravity x axis
gravity[1] //gravity y axis
gravity[2] //gravity z axis
The total acceleration, T
, on the phone is T = g + a
. To get just a
we would need a = T - g
:
linear_acceleration[0] = event.values[0] - gravity[0];
linear_acceleration[1] = event.values[1] - gravity[1];
linear_acceleration[2] = event.values[2] - gravity[2];
Notice how this calculates everything element by element because it's a vector operation.
The tricky part is finding gravity
because there is only one accelerometer in the phone which measures both the gravity AND the other forces at the same time. We have 2 different forces that we want to find from the one sensor. If we could only look at the forces at an isolated point in time we wouldn't be able to extract the information. However we do get samples over a range of times and by looking at how the forces change over time we can extract the information.
This means we need to filter out the results from that one source based on how quickly those forces change. The magnitude of acceleration due to gravity does not change quickly because it doesn't change at all. Gravity is a constant force. However other forces will change over time. If we filter out the slow changing forces like gravity by using a high-pass filter then the remaining forces are the fast changing ones like the forces being applied to the phone. This is why the high-pass filter is used.
I usually use this formula To filter the data from the accelometer sensor data coming out to linear sensor(like gyroscope) data. Use it if you are not sure there is a built-in Gyroscopic sensor.
private float[] values;
private float[] valuesN;
private float[] prev;
private float[] prevHF;
private boolean doHPF = false;
// ind - index of three dimensions (x, y, z)
private void makeHPFf() {
for (int ind = 0; ind < 3; ind++) {
valuesN[ind] = values[ind] * 0.002f * 9.8f;
if (doHPF)
values[ind] = valuesN[ind] - prev[ind] + (prevHF[ind] * 0.8f);
prev[ind] = valuesN[ind];
prevHF[ind] = values[ind];
}
if (!doHPF)
doHPF = true;
}