iOS: точное определение энергии удара по выходу акселерометра

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

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

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

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

3 ответа

Решение

Благодаря одному из мастеров на канале #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;
    }
}

Сначала вопросы, которые вы задали:

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

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

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

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

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

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

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

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

Другие вопросы по тегам