JavaScriptプログラム

スマホセンサーのノイズ軽減

スマートフォンのセンサーには、「ノイズ」が乗っています。そのため、センサーの値をプログラムで使用する場合、ノイズを軽減させる必要があります。
本記事は、記事「スマートフォンの傾き角のプログラム」の続き記事です。

 

 

センサーのノイズ

スマートフォンの傾き角(θ)を求めるプログラムを作っています。

これは、スマートフォンを床やテーブルなどに置くことで、そこの傾きが分かる「水準器」などへの応用を目指しています。

 

スマートフォンに搭載された「加速度センサーを用いることで、スマートフォンの傾き角(θ)を求めることができます【1】。

上記記事で作成したプログラムでは、加速度センサーからの値をそのまま使用していました。

そのため、スマートフォンを水平なテーブルの上に静かに置いても、傾き角(θ)は激しく変動していました。

 

一般的に、雑音(ノイズ)は無秩序(ランダム)に発生し、本来の信号(シグナル)に加わります。

そのため、一定期間の平均をとると、ノイズはそのランダム性により軽減し、一方、信号は残ります。

 

ノイズを軽減する前のデータを原始データ(original data)とよぶことにします。

また、原始データからノイズを軽減させることは「平滑化」とよばれています。

 

  • 原 始データ:original data
  • 平滑化データ:smooth data

 

【参照.1】記事「スマートフォンの傾き角のプログラム

 

 

移動平均法

単純移動平均法

単純移動平均法は、次式で表せます。

ここで、o は 原始データ(original data で、s は平滑化データ( smooth data )です。

添え字の i は、回数を表します。

n は、平滑化データを計算する際に使用する原始データの数です。

式の意味は、以下となります。

  • i 回目の平滑化データは、過去n 回の原始データの平均値

例えば、n 3 の場合、以下となります。

また例えば、i 5 の場合、以下となります。

これは、5 回目の平滑化データ(smooth data)は、5 回目・4 回目・3 回目の原始データ(original data)の平均値として計算しています。

指数移動平均法

指数移動平均法は、次式で表せます。

ここで、o は 原始データ(original data で、s は平滑化データ( smooth data )です。

添え字の i は、回数を表します。

α は、比率で、0.8 とか0.9 などの値を取ります。

式の意味は、以下となります。

  • i 回目の平滑化データは、1 回前(i-1 回目)の平滑化データとi 回目の原始データを、α 対 1-α の比率で足す

例えば、α 0.9 の場合、以下となります。

また例えば、i 5 の場合、以下となります。

これは、5 回目の平滑化データ(smooth data)は、4 回目の平滑化データ(smooth data)に0.9 掛けた数と、5 回目の原始データ(original data)に0.1 掛けた数との和として計算しています。

 

プログラム

プログラム1 :単純移動平均
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>Smoothing</title>
<script>
    var o = [0, 0, 0, 0, 0, 0, 0, 0, 0, 0];
    window.addEventListener("devicemotion", function(evt){
    //
        var ele = document.getElementById("output");
    //
        var accel = evt.accelerationIncludingGravity;
        var G_x = accel.x;
        var G_y = accel.y;
        var G_z = accel.z;
    //
        var G = Math.sqrt(G_x*G_x+G_y*G_y+G_z*G_z);
        var theta = 180/Math.PI*Math.acos(-G_z/G);
    //
        var theta1 = 0;
        for (var i=0; i<o.length-1; i++) {
            o[i] = o[i+1];
            theta1 += o[i];
        }
        o[o.length-1] = theta;
        theta1 += theta;
        theta1 /= o.length;

        ele.innerHTML  = "G_x      = " + G_x   + "<br>";
        ele.innerHTML += "G_y      = " + G_y   + "<br>";
        ele.innerHTML += "G_z      = " + G_z   + "<br>";
        ele.innerHTML += "G        = " + G     + "<br>";
        ele.innerHTML += "theta    = " + theta + "<br>";
        ele.innerHTML += "theta1   = " + theta1;

        }, true);
</script>
</head>
<body>
    <output id="output"></output>
</body>
</html>

 

プログラム1 の説明

原始データの計算

プログラム1 の8 行目から18 行目で、スマートフォンの傾き角(θ)の原始データを計算しています。

詳細は、記事「スマートフォンの傾き角のプログラム」をご参照ください。

 

平滑化データの計算

プログラム1 の7 行目は、原始データ(original data)を保存する配列です。

    var o = [0, 0, 0, 0, 0, 0, 0, 0, 0, 0];

20 行目から27 行目で、平滑化データ(smooth data)を計算しています。

変数 theta, theta1 は、それぞれ以下の意味で使用しています。

  • original data: theta
  • smooth data: theta1

 

 

 

プログラム1 の動作

Fig.1 は、プログラム1 の実行結果です。

Fig.1 センサーノイズ平滑化:単純移動平均

Fig.1 の横軸は回数(count)で、縦軸は傾き角(θ)です。

  • スマートフォンを横向きに立てた状態で、プログラム1 を動かしました。

Fig.1 から、以下のことが分かります。

  • original data: 最大0.5 度程度のノイズが発生している
  • smooth data: ノイズが軽減している

 

平滑化の特徴

今回、n を10 としたので、平滑化が機能するのは10 回後となります。

言い換えると、スマートフォンが傾き角を変化させてから数えて、10 回センサーが動いた後、平滑化データが機能します。

傾き角の変化が激しい場合、平滑化データが追随するのは難しいです。

しかし、「水準器」のように、傾き角が一定状態をしばらく保てる場合、この平滑化は実装が簡単で十分に機能します。

 

 

プログラム2 :指数移動平均
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>Smoothing</title>
<script>
    var oldTheta=0;
    window.addEventListener("devicemotion", function(evt){
    //
        var ele = document.getElementById("output");
    //
        var accel = evt.accelerationIncludingGravity;
        var G_x = accel.x;
        var G_y = accel.y;
        var G_z = accel.z;
    //
        var G = Math.sqrt(G_x*G_x+G_y*G_y+G_z*G_z);
        var theta = 180/Math.PI*Math.acos(-G_z/G);
    //
        var newTheta = 0.9*oldTheta + 0.1*theta;
        oldTheta = newTheta;

        ele.innerHTML  = "G_x      = " + G_x   + "<br>";
        ele.innerHTML += "G_y      = " + G_y   + "<br>";
        ele.innerHTML += "G_z      = " + G_z   + "<br>";
        ele.innerHTML += "G        = " + G     + "<br>";
        ele.innerHTML += "theta    = " + theta + "<br>";
        ele.innerHTML += "newTheta = " + newTheta;

        }, true);
</script>
</head>
<body>
    <output id="output"></output>
</body>
</html>

 

プログラム2 の説明

原始データの計算

プログラム1 の8 行目から18 行目で、スマートフォンの傾き角(θ)の原始データを計算しています。

詳細は、記事「スマートフォンの傾き角のプログラム」をご参照ください。

 

平滑化データの計算

プログラム2 の7 行目は、1 回前の平滑化データ(smooth data)を保存する変数を定義しています。

    var oldTheta=0;

20 行目と21 行目で、平滑化データ(smooth data)を計算しています。

変数 theta, newTheta, oldTheta は、それぞれ以下の意味で使用しています。

original data: theta
smooth data: newTheta,  oldTheta

 

プログラム2 の動作

Fig.2 は、プログラム2 の実行結果です。

Fig.2 センサーノイズ平滑化:指数移動平均

Fig.2 の横軸は回数(count)で、縦軸は傾き角(θ)です。

  • スマートフォンを横向きに立てた状態で、プログラム2 を動かしました。

Fig.2 から、以下のことが分かります。

  • original data: 最大0.5 度程度のノイズが発生している
  • smooth data: ノイズが軽減している。

 

平滑化の特徴

今回、変数oldTheta の初期値は 0 でした。そこから、正解である約90 度に達するのに、約50 回必要でした。

言い換えると、スマートフォンが傾き角を変化させてから数えて、約50 回センサーが動いた後、平滑化データが機能します。

これは、α が0.9 の場合、約50 回なので、α を0.8 にすると、正解に達する回数は減ると思われます。

この方法も、傾き角の変化が激しい場合、平滑化データが追随するのは難しいです。

しかし、「水準器」のように、傾き角が一定状態をしばらく保てる場合、この平滑化は実装がより簡単で十分に機能します。

 

 

 

 

コメントを残す

メールアドレスが公開されることはありません。 が付いている欄は必須項目です