How do you implement a Highpass filter for the IPhone accelerometer? - iphone

I remember seeing the code for a Highpass filter a few days back somewhere in the samples, however I can't find it anywhere now! Could someone remember me where the Highpass filter implementation code was?
Or better yet post the algorithm?
Thanks!

From the idevkit.com forums:
#define kFilteringFactor 0.1
static UIAccelerationValue rollingX=0, rollingY=0, rollingZ=0;
- (void)accelerometer:(UIAccelerometer *)accelerometer didAccelerate:(UIAcceleration *)acceleration {
// Calculate low pass values
rollingX = (acceleration.x * kFilteringFactor) + (rollingX * (1.0 - kFilteringFactor));
rollingY = (acceleration.y * kFilteringFactor) + (rollingY * (1.0 - kFilteringFactor));
rollingZ = (acceleration.z * kFilteringFactor) + (rollingZ * (1.0 - kFilteringFactor));
// Subtract the low-pass value from the current value to get a simplified high-pass filter
float accelX = acceleration.x - rollingX;
float accelY = acceleration.y - rollingY;
float accelZ = acceleration.z - rollingZ;
// Use the acceleration data.
}

Just in case someone wants to know, the highpass filter can be found in the Accelerometer Graph sample.

Here's the link, i was looking for this one too. This is an example for adaptive / non adaptive highpass and lowpass filter: Apple iOS Reference Library - AccelerometerGraph Example

Related

Calculate Jerk and Jounce from iPhone accelerometer data

I am trying to calculate Jerk (http://en.wikipedia.org/wiki/Jerk_(physics)) and jounce (http://en.wikipedia.org/wiki/Jounce) with the acceleration data from the accelerometer. I think I have Jerk figured out, but I am not sure what I am doing for jounce is correct. Can anyone confirm or deny what I am doing is giving me correct values (Do I need to take into consideration time?)
#define kFilteringFactor 0.4
float prevAccelerationX;
float prevAccelerationY;
float prevAccelerationZ;
float prevJerkX;
float prevJerkY;
float prevJerkZ;
- (void)viewDidLoad
{
[super viewDidLoad];
prevAccelerationX = 0;
prevAccelerationY = 0;
prevAccelerationZ = 0;
prevJerkX = 0;
prevJerkY = 0;
prevJerkZ = 0;
[self changeFilter:[LowpassFilter class]];
[[UIAccelerometer sharedAccelerometer] setUpdateInterval:1.0 / kUpdateFrequency];
[[UIAccelerometer sharedAccelerometer] setDelegate:self];
}
// UIAccelerometerDelegate method, called when the device accelerates.
- (void)accelerometer:(UIAccelerometer *)accelerometer didAccelerate:(UIAcceleration *)acceleration
{
float pax = prevAccelerationX;
float pay = prevAccelerationY;
float paz = prevAccelerationZ;
float pjx = prevJerkX;
float pjy = prevJerkY;
float pjz = prevJerkZ;
prevAccelerationX = acceleration.x - ( (acceleration.x * kFilteringFactor) +
(prevAccelerationX * (1.0 - kFilteringFactor)) );
prevAccelerationY = acceleration.y - ( (acceleration.y * kFilteringFactor) +
(prevAccelerationY * (1.0 - kFilteringFactor)) );
prevAccelerationZ = acceleration.z - ( (acceleration.z * kFilteringFactor) +
(prevAccelerationZ * (1.0 - kFilteringFactor)) );
// Compute the derivative (which represents change in acceleration).
float jerkX = ABS((prevAccelerationX - pax));
float jerkY = ABS((prevAccelerationY - pay));
float jerkZ = ABS((prevAccelerationZ - paz));
prevJerkX = jerkX - ( ( jerkX * kFilteringFactor) +
(prevJerkX * (1.0 - kFilteringFactor)));
prevJerkY = jerkY- ( (jerkY * kFilteringFactor) +
(prevJerkY* (1.0 - kFilteringFactor)) );
prevJerkZ = jerkZ - ( (jerkZ * kFilteringFactor) +
(prevJerkZ * (1.0 - kFilteringFactor)) );
// Compute the derivative (which represents change in acceleration).
float jounceX = ABS((prevJerkX - pjx));
float jounceY = ABS((prevJerkY - pjy));
float jounceZ = ABS((prevJerkZ - pjz));
}
In order to calculate derivatives, yes, you need to take time into consideration. Basically you can estimate jerk with just (a2-a1)/samplingtime. Its time derivative is similar. Your way of using kFilteringFactor seems weird to me but might work for your particular sampling time. You should not take ABS(), as it is perfectly valid for the derivative to be negative.
However, one big issue is probably going to be low sampling frequency. Sampling frequencies in phones are usually around 60 Hz. That means your actual bandwidth for acceleration is 30 Hz (the Nyquist frequency). Halve that and that's your jerk bandwidth. Halve that and your bandwidth for jounce, namely 7.5 Hz. Roughly speaking. All jerks (still a funny word) over 15 Hz and jounces over 7.5 Hz do not disappear but instead are aliased on top of your results. So not only you miss some information, the information you miss actually causes even more damage to your results. Properly done, you'd need low pass filtering before each derivative.
take several time series points from the acclerometer and perform B-Spline Interpolation and find the control points.
Take those points and utilize a a 3rd degree Berstein polynomial, take its first derivative and feed the control points from the B-Spline solution into the derived polynomial where t is between 0 and 1 (assuming 1 Hz sampling rate .. 0 to 1 interpolates everything in that second of time). Those values will be the Jerk/Jounce. You'll be computing this for front and side and acceleration values.

Accelerometer Low Pass Filtering

Still on the BigNerdRanch iOS Development book.
In the Accelerometer chapter, they first implement accelerometer tracking but it's fairly jumpy. They then suggest to apply a low pass filter to it by changing the original code:
- (void)accelerometer:(UIAccelerometer *)accelerometer didAccelerate:(UIAcceleration *)acceleration
{
HypnosisView *hv = (HypnosisView *)[self view];
[hv setXShift:10.0 * [acceleration x]];
[hv setYShift:10.0 * [acceleration y]];
[hv setNeedsDisplay];
}
to this:
- (void)accelerometer:(UIAccelerometer *)accelerometer didAccelerate:(UIAcceleration *)acceleration
{
HypnosisView *hv = (HypnosisView *)[self view];
float xShift = [hv xShift] * 0.8 + [accel x] * 2.0;
float yShift = [hv yShift] * 0.8 + [accel y] * 2.0;
[hv setXShift:xShift];
[hv setYShift:yShift];
[hv setNeedsDisplay];
}
Fairly simple question: where do they get these values from? I've been looking through the documentation and I found something about low pass filters, which suggests the following code:
#define kFilteringFactor 0.1
- (void)accelerometer:(UIAccelerometer *)accelerometer didAccelerate:(UIAcceleration *)acceleration {
// Use a basic low-pass filter to keep only the gravity component of each axis.
accelX = (acceleration.x * kFilteringFactor) + (accelX * (1.0 - kFilteringFactor));
accelY = (acceleration.y * kFilteringFactor) + (accelY * (1.0 - kFilteringFactor));
accelZ = (acceleration.z * kFilteringFactor) + (accelZ * (1.0 - kFilteringFactor));
// Use the acceleration data.
}
However, I first tried with that code and I got an error (by analyzing my app) saying 'the left value of '*' is a garbage value'. My accelerometer tracking didn't work either.
I'm fairly confused as to what these values mean. For example, in the first part of the code, why do they multiply the acceleration values by 10? To get a 'bigger' movement? I could make some sense out of that, but the second code with the low pass filter makes absolutely no sense to me.
accelX = (acceleration.x * kFilteringFactor) + (accelX * (1.0 - kFilteringFactor));
Whats happening in this code you are multiplying the acceleration at the moment by the Filtering factor 0.1 and then adding it to the filtered acceleration of the last time an update was called by 0.9.
This is pretty much getting the new value and adding it as 10% of the total accelX the other 90% is made up of the previous value which depends on the value before that, which depends on the value before that and so on. This cuts out high frequency values as only allows 10% of any change to go through to the new accelX value.
The KFilteringFactor of 0.1 makes this filter cut out all high frequencies. You will definitely want to experiment by changing this value to suit your particular application.
Since you're working through the Big Nerd Ranch Book - a good idea would be to go on to the Book's discussion forum.
For more information have a look at the Wikepedia article about low pass filters.
And for another example of filtering have a look at Apple's AccelerometerGraph example
Also - think if you take kFilteringFactor to be 0.2 which gives the multipliers for the current value to be 0.8 which is 1 - 0.2, and the multiplier for the new value is 2.0 because it's 0.2 x 10
I suppose 10 is the scaling factor to give reasonable values.

smooth scroll/inertial scrolling/momentum scroll

I have an OpenGL ES View in Android thats controlled by a matrix for translation. Im trying to figure out a way to get a hint of momentum scrolling as seen in the google maps app or the iPhone. Thanks.
If your problem is in 2d, it is quite simple
You need to get the elapsed time in each frame
Your onTouch function will find the acceleration of your finger. I forgot the formula on how to get the acceleration from a distance. It should be the second derivative of position with a time variable. But you should always convert your deltaX, deltaY in acceleration. To make it easy you don't really need to put something accurate there. Edit: I don't know why I didn't see it but the function was all there...
acceleration.x = 2(newposition.x - position.x - speed.x * elapsedTime) / (elapsedTime * elapsedTime);
Once you have your acceleration you can set your new position with that code. This is simple physic dynamics in 2d. With your acceleration you can find your speed and with your speed you can find your next position.
speed.x = (float) (mass * acceleration.x * elapsed + speed.x);
speed.y = (float) (mass * acceleration.y * elapsed + speed.y);
position.x += mass * acceleration.x / 2 * elapsed * elapsed + speed.x * elapsed;
position.y += mass * acceleration.y / 2 * elapsed * elapsed + speed.y * elapsed;
speed.x *= friction;
speed.y *= friction;
Mass and friction will let you define how fast it goes and how fast it will slow down by itself. You probably will have to tweak the code because this dynamic isn't exactly nice if you have to have to scroll backward to slow down.
At the end of each frame, you will have to reset your acceleration to (0,0). And on each new frame after a touch even, the acceleration should be set to something. It should work very well :)
Measure the speed that the view is scrolling at.
Detect when the user stops scrolling.
Gradually decrease the speed that the scroll view is scrolling at.
Something like this:
public void redraw() {
myScrollView.ySpeed = myScrollView.lastY-myScrollView.y;
myScrollView.xSpeed = myScrollView.lastX-myScrollView.x;
if (!userIsScrolling && ySpeed > 0) {
ySpeed--;
}
if (!userIsScrolling && xSpeed > 0) {
xSpeed--;
}
myScrollView.lastY = myScrollView.y;
myScrollView.y += ySpeed;
myScrollView.lastX = myScrollView.x;
myScrollView.x += xSpeed;
}
public void userStoppedScrolling() {
userIsScrolling = false;
}

Accelerometer direction detection

I have the following code
playerPosition.x += acceleration.x * 10;
playerPosition.y += acceleration.y * 20;
acceleration currently works, I would like to detect if the player should move backwards(y decreasing) and if so change it to
playerPosition.y += acceleration.y * 10;
How does one detect if acceleration from the accelerometer is negative?
How does one retrieve the direction of the movement? left right etc?
You just compare the acceleration with 0
acceleration.y < 0.0
or
acceleration.y > 0.0
There is a free app iSimulate where you can see what values accelerometer outputs.

iphone compass tilt compensation

has anybody already programmed a iphone compass heading tilt compensation?
i have got some approaches, but some help or a better solution would be cool!
FIRST
i define a vector Ev, calculated out of the cross product of Gv and Hv. Gv is a gravity vector i build out of the accelerometer values and Hv is an heading vector built out the magnetometer values.
Ev stands perpendicular on Gv and Hv, so it is heading to horizonatl East.
SECOND
i define a vector Rv, calculated out of the cross product Bv and Gv. Bv is my looking vector and it is defined as [0,0,-1]. Rv is perpendicular to Gv and Bv and shows always to the right.
THIRD
the angle between these two vectors, Ev and Rv, should be my corrected heading. to calculate the angle i build the dot product and thereof the arcos.
phi = arcos ( Ev * Rv / |Ev| * |Rv| )
Theoretically it should work, but maybe i have to normalize the vectors?!
Has anybody got a solution for this?
Thanks, m01d
Yep. You DEFINITELY have to normalize.
This is from my code that I use to extract the orientation of the device.
Gravity is obtained as the x,y,z of the accelerometer
and compass is obtained from the x,y,z of the heading function
gravity.normalize();
compass.normalize();
compassEast=gravity.cross(compass);
compassEast.normalize();
compassNorth=compassEast.cross(gravity);
compassNorth.normalize();
Let me know if you need the full code.
Also, for those who havnt yet seen the iphone 4s gyroscope in action: its amazing! I swapped the above input to gravity and compass for the equivalents from the gyro and the result is stable and smooth and awesome :) Go Apple.
I didn't receive the source code but I set up my own example. You can see the project and code here: http://www.sundh.com/blog/2011/09/stabalize-compass-of-iphone-with-gyroscope/
yes, i did it like described above. but the result is not very accurate. i think with smoother accelerometer values it should work that way. because of this i have choosen to do the tilt compensation by adding/subtracting the accelermoter values of the corresponding axis to/from the compass values.
Here iss my code for the solution above, but its not a final working solution:
- (void)locationManager:(CLLocationManager *)manager didUpdateHeading:(CLHeading *)newHeading{
if (newHeading != nil) {
float Ax = accelerationValueX;
float Ay = accelerationValueY;
float Az = accelerationValueZ;
float filterFactor = 0.2;
Mx = [newHeading x] * filterFactor + (Mx * (1.0 - filterFactor));
My = [newHeading y] * filterFactor + (My * (1.0 - filterFactor));
Mz = [newHeading z] * filterFactor + (Mz * (1.0 - filterFactor));
float counter = ( -pow(Ax, 2)*Mz + Ax*Az*Mx - pow(Ay, 2)*Mz + Ay*Az*My );
float denominator = ( sqrt( pow((My*Az-Mz*Ay), 2) + pow((Mz*Ax-Mx*Az), 2) + pow((Mx*Ay-My*Ax), 2) ) * sqrt(pow(Ay, 2)+pow(-Ax, 2)) );
headingCorrected = (acos(counter/denominator)* (180.0 / M_PI)) * filterFactor + (headingCorrected * (1.0 - filterFactor));
}
...
}