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

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

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

(РЕДАКТИРОВАТЬ: удалена тонна гампфа)

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


person P i    schedule 30.06.2011    source источник
comment
stackoverflow.com/questions/5530833 /   -  person P i    schedule 30.06.2011


Ответы (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;
    }
}
person P i    schedule 10.07.2011
comment
Примечание: это обычно выводит значение от 0 до 0,9 для постукивания по моей ладони. однако, размахивая им в воздухе, он достигает 1,5. - person P i; 10.07.2011
comment
Я пытаюсь попробовать этот код, но получаю ошибки для DOUBLE_EMPTY. Не могли бы вы объяснить, что такое DOUBLE_EMPTY? Спасибо - person Darren; 29.10.2012
comment
DOUBLE_EMPTY — это значение, указывающее, что переменная пуста. Используйте что-то вроде DBL_MAX, например: #define DOUBLE_EMPTY DBL_MAX - person William henderson; 29.05.2013
comment
@Pi, не могли бы вы объяснить, что делает ваш код, я пытаюсь использовать ваш код для обнаружения дорожных неровностей, но столкнулся с некоторыми трудностями. Пожалуйста, помогите мне. - person Shabir jan; 27.01.2015
comment
@Pi, не могли бы вы помочь в кодировании этого алгоритма в моем приложении. open-sci.net/wiki/sealappexamplepotholes - person Shabir jan; 27.01.2015

Во-первых, вопросы, которые вы задали:

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

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

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

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

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

person Beta    schedule 01.07.2011
comment
Извиняюсь за переработку моего вопроса, оставив этот ответ на то, чего больше нет. Я сделал это, чтобы создать лучший ресурс (чтобы быть более кратким) для тех, кто будет искать это в будущем. Спасибо за ответ! - person P i; 10.07.2011

Вам нужен фильтр Калмана. Погуглите эту фразу; писать об этом выходит за рамки интернет-форума, такого как этот. Есть книги, книги и книги о фильтрах Калмана.

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

Что касается показаний акселерометра, когда он лежит горизонтально: он должен регистрировать 1G вверх, а не вниз. Невозможно ощутить гравитацию. (Точка зрения Ньютона: гравитационного щита не существует. Точка зрения релятивиста: Гравитация — вымышленная сила.) Акселерометр не измеряет гравитацию. Он ощущает, что Земля или стол толкают акселерометр вверх.

person David Hammen    schedule 02.07.2011