質問
Androidで加速度計データのノイズをフィルタリングするにはどうすればよいですか?サンプルデータ用のハイパスフィルターを作成して、低周波数成分を除去し、高周波数成分に集中できるようにします。カルマンフィルターがこれに最適な候補であることを読みましたが、主にAndroid Javaで記述されるアプリケーションでこのメソッドを統合または使用するにはどうすればよいですか?または、そもそもそれを行うことができますか?またはAndroid NDKを介して?これがリアルタイムで実行できる可能性はありますか?
どんなアイデアでも大歓迎です。ありがとう!
解決
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];
他のヒント
これは、Appleの適応型ハイパスフィルターの例から改変されたAndroid用のコードです。これを接続して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]);
}
rbgrnからの回答でnorm()およびclamp()メソッドが何をするのか疑問に思う方は、ここでそれらを見ることができます:
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;
}
これは、AppleのiPhone用サンプルコードで行われたことを覚えているようです。見てみましょう...
GoogleでAccelerometerFilter.h / .m(またはAppleのAccelerometerGraphサンプルを入手)と次のリンクを探します: http://en.wikipedia.org/wiki/High-pass_filter (これがAppleのコードのベースです)。
Wikiにもいくつかの擬似コードがあります。しかし、数学はコードに変換するのはかなり簡単です。
IMO、最初の試みとしてカルマンフィルターを設計することは、おそらくかなり単純な問題を複雑にしすぎています。単純なFIRフィルターから始めて、それをテストし、必要なものを提供できないという合理的な確実性がある場合にのみ、より複雑なものを試します。しかし、私の推測では、必要なことはすべて実行でき、はるかに簡単かつ効率的に実行できます。