iOS: точное определение энергии удара по выходу акселерометра - PullRequest
0 голосов
/ 30 июня 2011

Я создаю приложение камертона, в котором вы кладете iPhone на ладонь другой руки или на мягкую поверхность, чтобы установить вилку.

Итак, я хотел бы обнаружитьэнергия, содержащаяся в каждом «ударе»

(РЕДАКТИРОВАТЬ: Удалена тонна gumpf)

Может кто-нибудь помочь мне взломать это?

Ответы [ 3 ]

4 голосов
/ 10 июля 2011

Благодаря одному из мастеров канала #math от freenode (спасибо Игорю) у меня есть действительно хорошее рабочее решение.

Вы используете стандартный метод для запуска обратного вызова на максимально возможной частоте (100 Гц), которая будет содержать мгновенные значения ускорения x, y, z.

Я позволю коду говорить за себя, хороший код всегда должен говорить сам за себя.

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;
    }
}
3 голосов
/ 01 июля 2011

Сначала задали вопросы:

А) Просто откалибруйте. Ускорение стояния - это постоянное притяжение силы тяжести, а любое внезапное отклонение - это добавление ускорения из-за удара. Вам также придется отслеживать изменения в ориентации , как сообщает гироскоп, чтобы вы могли игнорировать внезапное смещение гравитации в новое направление.

B) Интегрируйте ускорение, чтобы получить изменение скорости. Этот квадрат, умноженный на массу телефона, разделенный на два, является энергией (в кадре покоя).

C) Этот в принципе неразрешим. Теоретически, если случай является гибким, ускорение от удара будет проявляться в виде кривой, подобной шипу, с характерной формой, так что если у вас есть пара точек, которые не находятся на пике, вы можете оценить всю форму , Но я подозреваю, что устройство слишком жесткое, а выборка слишком редкая. Вы ничего не можете с этим поделать, если аппаратное обеспечение не будет интегрировать ускорение для вас, в чем я сомневаюсь (я не знаю iPhone).

Но энергия, вероятно, не лучшая мера для использования в любом случае; Вы можете доставить столько энергии, ударяя по ней подушкой, сколько постукивая молотком, но вы не ожидаете, что камертон зазвонит так громко. Пиковое ускорение может быть лучше, но это все еще зависит от хороших данных от акселерометра.

Не могли бы вы использовать микрофон? Попробуйте записать то, что он слышит, когда вы касаетесь его коленом, и ищите функции, которых нет в обычном звуке, например, я не знаю, большая низкочастотная амплитуда, широкий спектр, возможно, даже характерный резонанс дело. Он все еще может немного реагировать на громкий шум в окружающей среде, но тогда это вполне реально.

1 голос
/ 02 июля 2011

То, что вы хотите, это фильтр Калмана. Google эту фразу; писать об одном выходит за рамки интернет-форума, такого как этот. На Kalman Filters есть книги, книги и книги.

Одна проблема: интерфейс iphone на самом деле не создан для того, что вам нужно. Из-за этой проблемы моему работодателю пришлось работать с Apple, чтобы получить доступ к внутренним ресурсам и работать с ними. И нет, я не могу много рассказать о том, что они сделали или что это за проект.

Относительно показаний акселерометра, когда он остается ровным: он должен регистрировать 1G вверх , а не вниз. Нет способа ощутить гравитацию. (Ньютоновский POV: гравитационного щита не существует. Релятивистский POV: гравитация - это фиктивная сила.) Акселерометр не воспринимает гравитацию. Он ощущает Землю или стол, толкающий акселерометр вверх.

...