Фильтрация шума данных акселерометра

Как отфильтровать шум данных акселерометра в Android? Я хотел бы создать фильтр верхних частот для моих выборочных данных, чтобы я мог устранить низкочастотные компоненты и сосредоточиться на высокочастотных компонентах. Я читал, что фильтр Калмана может быть лучшим кандидатом для этого, но как мне интегрировать или использовать этот метод в моем приложении, которое в основном будет написано на Android Java? или это можно сделать в первую очередь? или через Android NDK? Есть ли шанс, что это можно сделать в режиме реального времени?

Любая идея будет высоко оценена. Спасибо!


person Faiz    schedule 28.10.2009    source источник


Ответы (5)


Образцы из Apple SDK на самом деле реализуют фильтрацию еще более простым способом, используя линейное изменение:

//ramp-speed - play with this value until satisfied
const float kFilteringFactor = 0.1f;

//last result storage - keep definition outside of this function, eg. in wrapping object
float accel[3]; 

//acceleration.x,.y,.z is the input from the sensor

//result.x,.y,.z is the filtered result

//high-pass filter to eliminate gravity
accel[0] = acceleration.x * kFilteringFactor + accel[0] * (1.0f - kFilteringFactor);
accel[1] = acceleration.y * kFilteringFactor + accel[1] * (1.0f - kFilteringFactor);
accel[2] = acceleration.z * kFilteringFactor + accel[2] * (1.0f - kFilteringFactor);
result.x = acceleration.x - accel[0];
result.y = acceleration.y - accel[1];
result.z = acceleration.z - accel[2];
person Till    schedule 15.11.2009
comment
Я не уверен, что понимаю, что здесь происходит... если Acceleration.x является постоянным (теоретически это может произойти), то result.x = 0; accel[0] выглядит как отфильтрованный вывод; не уверен, что такое result.x. - person Pandrei; 20.04.2015

Вот код для Android, адаптированный из примера адаптивного фильтра верхних частот Apple. Просто подключите это и реализуйте onFilteredAccelerometerChanged()

private static final boolean ADAPTIVE_ACCEL_FILTER = true;
float lastAccel[] = new float[3];
float accelFilter[] = new float[3];

public void onAccelerometerChanged(float accelX, float accelY, float accelZ) {
    // high pass filter
    float updateFreq = 30; // match this to your update speed
    float cutOffFreq = 0.9f;
    float RC = 1.0f / cutOffFreq;
    float dt = 1.0f / updateFreq;
    float filterConstant = RC / (dt + RC);
    float alpha = filterConstant; 
    float kAccelerometerMinStep = 0.033f;
    float kAccelerometerNoiseAttenuation = 3.0f;

    if(ADAPTIVE_ACCEL_FILTER)
    {
        float d = clamp(Math.abs(norm(accelFilter[0], accelFilter[1], accelFilter[2]) - norm(accelX, accelY, accelZ)) / kAccelerometerMinStep - 1.0f, 0.0f, 1.0f);
        alpha = d * filterConstant / kAccelerometerNoiseAttenuation + (1.0f - d) * filterConstant;
    }

    accelFilter[0] = (float) (alpha * (accelFilter[0] + accelX - lastAccel[0]));
    accelFilter[1] = (float) (alpha * (accelFilter[1] + accelY - lastAccel[1]));
    accelFilter[2] = (float) (alpha * (accelFilter[2] + accelZ - lastAccel[2]));

    lastAccel[0] = accelX;
    lastAccel[1] = accelY;
    lastAccel[2] = accelZ;
    onFilteredAccelerometerChanged(accelFilter[0], accelFilter[1], accelFilter[2]);
}
person rbgrn    schedule 30.11.2011
comment
Что должны делать norm() и clip()? - person Matthew Runo; 02.12.2011
comment
Я бы сказал, что «норма» относится к вычислению нормы данного вектора (sqrt ([0] ^ 2 + [1] ^ 2´[2] ^ 2)) и зажим — это предельная функция с верхней и нижней границей ( в этом случае первый аргумент ограничен от 0,0f до 1,0f). Кроме того, большое спасибо за адаптивный пример, я думаю, что буду использовать его в какой-то форме. - person ravemir; 15.02.2013
comment
Как определить значение этих переменных? (RC, dt, cutOffFreq и т. д.) - person keinabel; 06.01.2017

Для тех, кому интересно, что делают методы norm() и clip() в ответе от rbgrn, вы можете увидеть их здесь: http://developer.apple.com/library/IOS/samplecode/AccelerometerGraph/Listings/AccelerometerGraph_AccelerometerFilter_m.html

double norm(double x, double y, double z)
{
    return Math.sqrt(x * x + y * y + z * z);
}

double clamp(double v, double min, double max)
{
    if(v > max)
        return max;
    else if(v < min)
        return min;
    else
        return v;
}
person Shumoapp    schedule 25.05.2012

Кажется, я помню, как это делалось в примере кода Apple для iPhone. Посмотрим...

Найдите AccelerometerFilter.h / .m в Google (или возьмите образец Apple AccelerometerGraph) и эту ссылку: http://en.wikipedia.org/wiki/High-pass_filter (на этом основан код Apple).

В Вики тоже есть псевдокод. Но математику довольно просто перевести в код.

person inked    schedule 28.10.2009

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

person Jerry Coffin    schedule 28.10.2009
comment
В настоящее время я изучаю различные механизмы фильтрации. Каковы преимущества КИХ-фильтра по сравнению с принятым выше ответом? - person Nazerke; 27.03.2013
comment
@Nazerke: Похоже, принятый ответ является (действительно простым) КИХ-фильтром. Больше полюсов в фильтре даст вам больше контроля над скоростью спада фильтра, и особенно возможность иметь более быстрый спад (если вы этого хотите). - person Jerry Coffin; 28.03.2013
comment
@JerryCoffin Принятый ответ - это простой IIR, а также очень простой KF. - person Neil Townsend; 08.01.2015