3

I need to calculate iphone velocity in space, punch speed for example.
My first question is: Are the acceleration values accelerometer:didAcceleratewith this filtering actions:

gravity_x = acceleration.x * kFilteringFactor + gravity_x * (1.0 - kFilteringFactor);
gravity_y = acceleration.y * kFilteringFactor + gravity_y * (1.0 - kFilteringFactor);
gravity_z = acceleration.z * kFilteringFactor + gravity_z * (1.0 - kFilteringFactor);
float gravityNorm = sqrt(gravity_x * gravity_x + gravity_y * gravity_y + gravity_z * gravity_z);
accelX = acceleration.x - gravity_x / gravityNorm;
accelY = acceleration.y - gravity_y / gravityNorm;
accelZ = acceleration.z - gravity_z / gravityNorm;

the same as using CoreMotion's
motionManager.deviceMotion.userAcceleration.x; motionManager.deviceMotion.userAcceleration.y; motionManager.deviceMotion.userAcceleration.z; ?

Next, according to same questions, I do the following

    const float accuracy=10;
    float accx = (float) ((int)  (accelX * accuracy))/ accuracy;
    float accy=  (float) ((int)  (accelY * accuracy))/ accuracy;
    float accz=  (float) ((int)  (accelZ * accuracy))/ accuracy;

for rounding values, then, as I think, I obtain current speed

float dx = accx*9.81+prevX*9.81;
float dy = accy*9.81+prevY*9.81;
float dz = accz*9.81+prevZ*9.81;

speed_after_x = dx/2*myAccelerometer.updateInterval+speed_before_x;
speed_after_y = dy/2*myAccelerometer.updateInterval+speed_before_y;
speed_after_z = dz/2*myAccelerometer.updateInterval+speed_before_z;

according to iphone accelerometer speed and distance
then

    prevX=accx;
    prevY=accy;
    prevZ=accz;

    speed_before_x=speed_after_x;
    speed_before_y=speed_after_y;
    speed_before_z=speed_after_z;

and finally calculating speed as vector's length

    float speed = sqrt(speed_after_x*speed_after_x+speed_after_y*speed_after_y+speed_after_z*speed_after_z);
    if (max_speed<speed)  max_speed = speed;

But speed value, that is containing in label, is always increasing. I mean if i moved device and then stopped, speed value doesn't become to 0. Doesn't acceleration compensate itself at 0?

Community
  • 1
  • 1
Aft3rmath
  • 669
  • 2
  • 12
  • 21
  • Doesn't this cancel itself out: `((int) (accelX * accuracy))/ accuracy;`. Like ((10 * 100) / 100 == 10. If your intention is to round the number and then cast back to a float there are better ways to do it. – Diziet May 14 '12 at 08:24
  • accuracy is 10, to avoid rapidly acceleration values changing when device is holding. – Aft3rmath May 14 '12 at 08:35
  • Yes, but multiplying a number then dividing by the same number is the equivalent of doing nothing. (A * B) / B = A. – Diziet May 14 '12 at 08:48
  • I don't think that this is why velocity doesn't change into 0, anyway, I have to use `acceleration.timestamp`s delta, not exactly `updateInterval` – Aft3rmath May 14 '12 at 09:52
  • Oh I know, that's why it's a comment not an answer. – Diziet May 14 '12 at 09:56
  • Is there any reason you are not using Core Motion? I think that is available in >=ios4.0. – Diziet May 14 '12 at 10:04

1 Answers1

13

Here's the example code I managed to hash out. I'll just put it here for now:

//
//  ViewController.m
//  Acce
//
//  Created by Diziet on 14/05/2012.
//  Copyright (c) 2012 __MyCompanyName__. All rights reserved.
//

#import "ViewController.h"

@interface ViewController () {
    UIAccelerationValue gravX;
    UIAccelerationValue gravY;
    UIAccelerationValue gravZ;
    UIAccelerationValue prevVelocity;
    UIAccelerationValue prevAcce;
}

@property (strong) UIAccelerometer *sharedAcc;

@end

@implementation ViewController

@synthesize sharedAcc = _sharedAcc;

#define kAccelerometerFrequency        50.0 //Hz
#define kFilteringFactor 0.1

- (void)viewDidLoad
{
    [super viewDidLoad];
    // Do any additional setup after loading the view, typically from a nib.
    self.sharedAcc = [UIAccelerometer sharedAccelerometer];
    self.sharedAcc.delegate = self;
    self.sharedAcc.updateInterval = 1 / kAccelerometerFrequency; 

    gravX = gravY = gravZ = prevVelocity = prevAcce = 0.f;
}

- (void)viewDidUnload
{
    [super viewDidUnload];
    // Release any retained subviews of the main view.
}

- (BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)interfaceOrientation
{
    return (interfaceOrientation != UIInterfaceOrientationPortraitUpsideDown);
}

- (UIAccelerationValue)tendToZero:(UIAccelerationValue)value {
    if (value < 0) {
        return ceil(value);
    } else {
        return floor(value);
    }
}

#define kAccelerometerFrequency        50.0 //Hz
#define kFilteringFactor 0.1
- (void)accelerometer:(UIAccelerometer *)accelerometer didAccelerate:(UIAcceleration *)acceleration {
    gravX = (acceleration.x * kFilteringFactor) + (gravX * (1.0 - kFilteringFactor));
    gravY = (acceleration.y * kFilteringFactor) + (gravY * (1.0 - kFilteringFactor));
    gravZ = (acceleration.z * kFilteringFactor) + (gravZ * (1.0 - kFilteringFactor));

    UIAccelerationValue accelX = acceleration.x - ( (acceleration.x * kFilteringFactor) + (gravX * (1.0 - kFilteringFactor)) );

    UIAccelerationValue accelY = acceleration.y - ( (acceleration.y * kFilteringFactor) + (gravY * (1.0 - kFilteringFactor)) );
    UIAccelerationValue accelZ = acceleration.z - ( (acceleration.z * kFilteringFactor) + (gravZ * (1.0 - kFilteringFactor)) );
    accelX *= 9.81f;
    accelY *= 9.81f;
    accelZ *= 9.81f;
    accelX = [self tendToZero:accelX];
    accelY = [self tendToZero:accelY];
    accelZ = [self tendToZero:accelZ];

    UIAccelerationValue vector = sqrt(pow(accelX,2)+pow(accelY,2)+pow(accelZ, 2));
    UIAccelerationValue acce = vector - prevVelocity;
    UIAccelerationValue velocity = (((acce - prevAcce)/2) * (1/kAccelerometerFrequency)) + prevVelocity;

    NSLog(@"X %g Y %g Z %g, Vector %g, Velocity %g",accelX,accelY,accelZ,vector,velocity);

    prevAcce = acce;
    prevVelocity = velocity;
}

@end

It'll need modifying for your needs, especially as I'm just throwing the values away afterwards. The resultant value 'velocity' logged as 'Velocity' tends back towards extremely small negative values after acceleration events have ceased, e.g. *10^-17. So yeah, that's practically zero in my book. You'll want to do some rounding in there and probably even scale the values up. I don't think I could get it higher than 0.2 or 0.3 but then again I don't want to hurl my phone across the room (yet).

Diziet
  • 2,397
  • 1
  • 26
  • 34
  • I don't think so, because I added this multiplier after found out the problem, and it is used to convert G-measures to m per sec – Aft3rmath May 14 '12 at 10:15
  • It's not the * 9.81 I'm wondering about, that was an 'also'/aside. It's the fact that you add accx to prevX. If prevX cannot be negative, which judging by your math I don't think it can be, then you will get a constantly increasing value for acceleration. You need to have some multiplication of the existing value, such that if the current moment acceleration in a particular axis is zero the acceleration you record will be zero. I'll put this in the answer. – Diziet May 14 '12 at 10:27
  • why prevX cannot be negative?`prevX=accx; prevY=accy; prevZ=accz;`accx can be negative. I add accx to prevX according to `velocity[i] = (acceleration[i] + acceleration[i-1])/2 * interval + velocity[i-1]` – Aft3rmath May 14 '12 at 10:34
  • update interval is 0.01, i and i tried 0.05. This filter is for ignoring rotations around its own axes. What values you need to know? – Aft3rmath May 14 '12 at 11:02
  • let us [continue this discussion in chat](http://chat.stackoverflow.com/rooms/11228/discussion-between-diziet-and-aft3rmath) – Diziet May 14 '12 at 11:07
  • thanks) x*x faster then pow(x,2) as i know, am i wrong? and I don't need to calculate acceleration vector as I understand it, I need `i` and `i-1` accel values to calculate velocity as `v[i] = (a[i]+a[i-1])/2*delta t + v[i-1]` what I actually did, the problem is why velocity doesn't change into 0 when I stop moving device – Aft3rmath May 14 '12 at 17:34
  • I think that's as close as I'm going to get to solving this for you without getting some mighty funny looks where I work. :D – Diziet May 15 '12 at 09:19
  • Dude, you are awesome! Don't test yet, but your help is great! Report you soon) – Aft3rmath May 15 '12 at 19:43
  • And I don't understand `UIAccelerationValue acce = vector - prevVelocity;` Why do you subtract previous velocity value from acceleration vector value – Aft3rmath May 16 '12 at 07:01
  • Because the acceleration at that instance is the change in velocity (e.g. current velocity minus previous). If we are currently going (pretending units are m/s which they are not) 9 m/s and were going 12 m/s our acceleration is -3 m/s. This lets the equation tend towards zero when motion stopped. Without that you get continuously increasing values. – Diziet May 16 '12 at 08:44
  • hm, can we compare m/s(velocity) with m/s^2 (acceleration)? Is it correct? – Aft3rmath May 16 '12 at 12:19
  • max detected speed is 0.33 m/s, seems to be incorrect =\ it must be 5-8 m/s with punch, now i'll try to apply it to core motion – Aft3rmath May 16 '12 at 12:40
  • Because I have no idea what the original measurements are in. – Diziet May 17 '12 at 14:10
  • I need to to calculate the punch speed. Plz tell the final method you have implemented .. – Ankur Aug 09 '14 at 05:39
  • 1
    Just because I can't comment, I post here : I think the unit of acceleration is in m/s^2. > A G is a unit of gravitation force equal to that exerted by the earth’s gravitational field (9.81 m s−2). https://developer.apple.com/library/prerelease/ios/documentation/CoreMotion/Reference/CMAccelerometerData_Class/index.html#//apple_ref/c/tdef/CMAcceleration But it's with the method whit CMMotionManager to get acceleration... –  Feb 03 '15 at 15:31
  • Aha, I didn't know for sure it was G that was returned. Excellent. – Diziet Feb 04 '15 at 10:07
  • Why velocity is not 0 when device stoped? – Dmitriy Pushkarev May 25 '16 at 03:55