iosmathaccelerometerdetectbump

iOS: Accurately determining energy of a bump from accelerometer output


I am creating a tuning fork app, where you pat the iPhone into the palm of your other hand, or against a soft surface in order to set the fork zinging.

So I would like to detect the energy contained in each 'bump'

(EDIT: Removed a ton of gumpf)

Can anyone help me crack this one?


Solution

  • Thanks to one of the wizards on freenode's #math channel (thanks Igor), I have a really good working solution.

    You use the standard method to fire a callback at the maximum frequency possible (100Hz), which will contain the instantaneous acceleration x,y,z values.

    I will let the code speak for itself, good code should always speak for itself.

    typedef 
    struct {
        double x,y,z;
    }
    vec_d3;
    
    #define RECENT_COUNT 10
    
    #define SMOOTH_IP( x, x_new, fac )  x  =  fac * x  +  ( 1. - fac ) * x_new
    
    - (void) accelerometer: (UIAccelerometer *) accelerometer 
              didAccelerate: (UIAcceleration *) acceleration 
    {
        // smooth incoming acceleration values
        static vec_d3 smooth = { DOUBLE_EMPTY, 0, 0 };
    
        {
            if ( smooth.x == DOUBLE_EMPTY )
            {
                smooth.x = acceleration.x;
                smooth.y = acceleration.y;
                smooth.z = acceleration.z;
    
                return;
            }
    
            SMOOTH_IP( smooth.x, acceleration.x, 0.9 );
            SMOOTH_IP( smooth.y, acceleration.y, 0.9 );
            SMOOTH_IP( smooth.z, acceleration.z, 0.9 );
        }
    
        // keep track of last k smoothed acceleration values
        static vec_d3 recent[ RECENT_COUNT ];
        {
            static int ptr = 0;
            static BOOL gotEnoughData = NO;
    
            recent[ ptr ] = smooth;
    
            ptr++;
            if ( ptr == RECENT_COUNT )
            {
                ptr = 0;
                gotEnoughData = YES;
            }
    
            // return if array not filled yet
            if ( ! gotEnoughData )
                return;
        }
    
        // get the resultant variation in acceleration over the whole array
        double variation;
        {
            vec_d3 min = smooth, max = smooth;
    
            for ( int i=0; i < RECENT_COUNT; i++ )
            {
                min.x = MIN( min.x, recent[ i ].x );
                min.y = MIN( min.y, recent[ i ].y );
                min.z = MIN( min.z, recent[ i ].z );
    
                max.x = MAX( max.x, recent[ i ].x );
                max.y = MAX( max.y, recent[ i ].y );
                max.z = MAX( max.z, recent[ i ].z );
            }
    
            vec_d3 V = (vec_d3) 
            {
                .x = max.x - min.x,
                .y = max.y - min.y,
                .z = max.z - min.z
            };
    
            variation = sqrt(
                             V.x * V.x  +
                             V.y * V.y  +
                             V.z * V.z
                             );
        }
    
        // smooth it
        static double var_smoothed = DOUBLE_EMPTY;
        {
            if ( var_smoothed == DOUBLE_EMPTY )
            {
                var_smoothed = variation;
                return;
            }
            SMOOTH_IP( var_smoothed, variation, 0.9 );
        }
    
    
        // see if it's just passed a peak
        {
            static double varSmoothed_last = DOUBLE_EMPTY;
            if ( varSmoothed_last == DOUBLE_EMPTY )
            {
                varSmoothed_last = var_smoothed;
                return;
            }
    
            static double varSmoothed_preLast = DOUBLE_EMPTY;
            if ( varSmoothed_preLast == DOUBLE_EMPTY )
            {
                varSmoothed_preLast = varSmoothed_last;
                varSmoothed_last = var_smoothed;
                return;
            }
    
    #define THRESHOLD_IMPULSE .15
    
            if ( varSmoothed_last > varSmoothed_preLast  
                &&  varSmoothed_last > var_smoothed  
                &&  varSmoothed_last > THRESHOLD_IMPULSE )
            {
                LOG ( @"PotPeak @ %f", varSmoothed_last );
    
                // hit a peak at imp_last
                [self peakedWithImpulse: varSmoothed_last ];
            }
    
            varSmoothed_preLast = varSmoothed_last;
            varSmoothed_last = var_smoothed;
        }
    }