Smoothing Sensor Data, Part 2
After a query from an older blog entry, I figured I should properly follow-up since there were a couple questions about how to use the low-pass filter I described to smooth sensor data from Android.
So the question was "shouldn't the algorithm be output[i] = output[i-1] + ALPHA * (input[i] - output[i]);
" Well, the answer is no, here's why:
So the wikipedia entry I referenced uses y[i-1]
to represent the prior value in time. In my case, the index values of output
represent 3 different dimensions (x,y,z) not sequential values in time. Maybe it's a little confusing, but to call to lowPass looks like this:
public void onSensorChanged(SensorEvent event) { // thank you http://www.codingforandroid.com/2011/01/using-orientation-sensors-simple.html if (event.sensor.getType() == Sensor.TYPE_ACCELEROMETER) accelVals = lowPass( event.values.clone(), accelVals ); if (event.sensor.getType() == Sensor.TYPE_MAGNETIC_FIELD) compassVals = lowPass( event.values.clone(), compassVals ); if (accelVals != null && compassVals != null) { float R[] = new float[9]; float I[] = new float[9]; boolean success = SensorManager.getRotationMatrix(R, I, accelVals, compassVals); if (success) { float orientation[] = new float[3]; SensorManager.getOrientation(R, orientation); // at this point, orientation contains the azimuth, pitch and roll values. this.compassView.updateBearing(orientation[0]); } } }
So two things to note here: First, event.values
is an array of sensor values for different axes (see the Android docs.)
Second, accelVals
and compassVals
are instance variables that hold the
last set of smoothed values. I suppose the arguments to lowPass
should
have been named newVals
and oldVals
- that would have made more
sense then.
Since it's apparent I didn't give enough detail in my original post, hopefully this will clear up any confusion!