加速度センサーから取得したデータを平滑化する方法です。
生のデータは、SensorManager#registerListenerメソッドの第3パラメータの指定によって、こんな感じで変わります。
SENSOR_DELAY_NORMAL ⇒ 標準。スクリーンの回転検出に適す
SENSOR_DELAY_UI ⇒ ユーザインタフェース用に適す
SENSOR_DELAY_GAME ⇒ ゲーム用に適する
SENSOR_DELAY_FASTEST ⇒ 可能な限り早く
いまいち何を言ってるのかわかりませんので、実際に取得したデータをグラフ化してみました。
グラフは普通に端末を手で持った時の物で、端から端までで約5秒分のデータです。
データ採取のプログラムはこんな感じで、1000個の配列に5msごとに値を入れています。
void setGSensorData(double x, double y, double z) {
double now = System.nanoTime();
if( mPTime != 0 ) {
double dt = now - mPTime;
long msec = (long)(dt / 5000000.0);
for(int n=0; n < msec; n++ ) {
mValX[mValPtr] = mPValX;
mValY[mValPtr] = mPValY;
mValZ[mValPtr] = mPValZ;
mValPtr++;
if (mValPtr == UnitCount)
mValPtr = 0;
}
}
mPValX = (float)x;
mPValY = (float)y;
mPValZ = (float)z;
mPTime = now;
mValX[mValPtr] = mPValX;
mValY[mValPtr] = mPValY;
mValZ[mValPtr] = mPValZ;
mValPtr++;
if (mValPtr == UnitCount)
mValPtr = 0;
}
SENSOR_DELAY_NORMALとSENSOR_DELAY_UIはデータの取得間隔が60ms~200ms程度と結構粗く、グラフでも線がガタガタしているのが見て取れます。
SENSOR_DELAY_FASTESTとSENSOR_DELAY_GAMEはそれより速く20ms程度のようで、細かな動きまでとらえているようです。
このデータ取得間隔は端末の機種によってもかなりバラつきがあるので、APIでは抽象化したシンボルで指定するようになっているようです。
細かな振動があるように見えますが、私の手が小刻みに震えているわけではなく、机の上などにおいてもこの振動は消えることがありません。センサーのノイズです。
ノイズに注目してグラフを良く見ると、FASTESTとGAMEの違いがわかるでしょうか?
GAMEの方はヒゲが少なく線が滑らかになっています。おそらく、GAMEの動作に不要な細かな振動とノイズをローパスフィルターによる平滑化が行われて滑らかにしていると思います。
用途によっては更に滑らかにする必要があるので、加速度センサーの利用にはローパスフィルターが欠かせません。
こういう信号のローパスフィルターは色々なアルゴリズムがあるのですが、滑らかにすればするほど信号に遅れが発生したり、本来必要な部分も消えてしまう事になります。
このあたりはどれが正解という事はなく、用途に応じて選択する事でしょう。
実際に2種類のローパスフィルターで、波形の変化を見てみます。
ローパスフィルター1
過去いくつかの値の平均を取る方法です。この例ではWindSize=10で10個の平均としています。
mLPuX[mWndPtr] = in;
mWndPtr++;
if (mWndPtr == WindSize) {
mWndPtr = 0;
}
double out = 0;
for (int i = 0; i < WindSize; i++) {
out += mLPuX[i];
}
out /= WindSize;
ローパスフィルター2
前回の値と混ぜる方法です。
double out = mPrev * 0.8 + in * 0.2;
mPrev = in;
ローパスフィルター3
前回の値と混ぜる方法ですが、混ぜた値で畳み掛けます。
double out = mPrev * 0.8 + in * 0.2;
mPrev = out;
では、以上のフィルターを通した結果です。
すべてFASTESTの同じチャンネルのデータを使用し、フィルターだけを変えています。
赤い線は生データ、緑がローパスフィルター1、青がローパスフィルター2です。
赤い線は生データ、緑がローパスフィルター2、青がローパスフィルター3です。
同じアルゴリズムでもパラメータ(平均化する数や混ぜ合わせる比率)を変えれば、様々な結果が取り出せます。
アルゴリズム的には平均化は単純で効果が分かりやすいですが、フィルター2や3の混ぜ合わせの方がCPU負荷が低い割に平滑化効果が高く遅れも少ないのでお勧めです。
コメントする