2009-10-28 15 views
23

Jak odfiltrować szum z danych przyspieszeniomierza w systemie Android? Chciałbym utworzyć filtr górnoprzepustowy dla moich danych przykładowych, aby wyeliminować komponenty niskiej częstotliwości i skoncentrować się na komponentach o wysokiej częstotliwości. Czytałem, że filtr Kalmana może być najlepszym kandydatem do tego, ale jak mogę zintegrować lub użyć tej metody w mojej aplikacji, która będzie głównie napisana w systemie Android Java? czy może to zrobić w pierwszej kolejności? lub przez Android NDK? Czy istnieje szansa, że ​​można to zrobić w czasie rzeczywistym?Filtrowanie danych z akcelerometru

Każdy pomysł zostanie doceniony. Dziękuję Ci!

Odpowiedz

24

Próbki z SDK Apple'a rzeczywiście realizować filtrowanie w jeszcze prostszy sposób, który jest za pomocą zagłębianiu skośnym:

 
//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]; 
+1

Nie jestem pewien, czy śledzę to, co się tutaj dzieje ... jeśli acceleration.x jest stały (teoretycznie może się to zdarzyć), to result.x = 0; accel [0] wygląda jak przefiltrowane wyjście; nie wiem, co to jest result.x. – Pandrei

1

Wydaje się, że pamiętam, że robiono to w przykładowym kodzie Apple'a dla iPhone'a. Zobaczmy ...

Poszukaj AccelerometerFilter.h/.m w Google (lub chwycić AccelerometerGraph próbki Apple) i ten link: http://en.wikipedia.org/wiki/High-pass_filter (to co kod Apple opiera się na).

Istnieje trochę pseudokodu na Wiki. Ale matematyka jest dość prosta do przetłumaczenia na kod.

0

IMO, zaprojektowanie filtra Kalmana jako pierwszej próby jest zbyt skomplikowane, co prawdopodobnie jest dość prostym problemem. Zaczynam od prostego filtru FIR i próbuję tylko czegoś bardziej złożonego, kiedy/jeśli to przetestowałeś iz przekonaniem stwierdziłeś, że nie może on dostarczyć tego co chcesz. Domyślam się jednak, że będzie w stanie zrobić wszystko, czego potrzebujesz, i zrobić to znacznie łatwiej i wydajniej.

+0

jestem obecnie badanie różnych mechanizmów filtrowania. Jakie są zalety filtra FIR w porównaniu z powyższą akceptowaną odpowiedzią? – Nazerke

+0

@Nazerke: Wygląda na to, że zaakceptowana odpowiedź * jest * (bardzo prostym) filtrem FIR. Więcej biegunów w filtrze da ci większą kontrolę nad szybkością, z jaką filtr się odsuwa, a zwłaszcza możliwością szybszego rozwijania (jeśli chcesz). –

+0

@JerryCoffin Przyjęta odpowiedź to prosty IIR, a także bardzo prosty KF. –

12

Oto kod dla Androida, zaadaptowany z jabłko adaptacyjnego górnoprzepustowy przykład filtra. Wystarczy podłączyć to i wdrożyć 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]); 
} 
+4

Co powinny normować() i clamp()? –

+0

Powiedziałbym, że "norma" odnosi się do obliczania normy dla danego wektora (sqrt ([0]^2 + [1]^2'[2]^2)) a zacisk jest funkcją ograniczającą z górną i dolną granicą (w tym przypadku pierwszy argument jest ograniczony między 0.0f a 1.0f). Ponadto, dziękuję za adaptacyjny przykład, myślę, że idę w jakiejś formie. – ravemir

+0

norma? jej nie ma w android sdk –

Powiązane problemy