スマホセンサーのノイズ軽減
Contents
スマートフォンのセンサーには、「ノイズ」が乗っています。そのため、センサーの値をプログラムで使用する場合、ノイズを軽減させる必要があります。
本記事は、記事「スマートフォンの傾き角のプログラム」の続き記事です。
センサーのノイズ
スマートフォンの傾き角(θ)を求めるプログラムを作っています。
これは、スマートフォンを床やテーブルなどに置くことで、そこの傾きが分かる「水準器」などへの応用を目指しています。
スマートフォンに搭載された「加速度センサー」を用いることで、スマートフォンの傾き角(θ)を求めることができます【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 の横軸は回数(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 の横軸は回数(count)で、縦軸は傾き角(θ)です。
- スマートフォンを横向きに立てた状態で、プログラム2 を動かしました。
Fig.2 から、以下のことが分かります。
- original data: 最大0.5 度程度のノイズが発生している
- smooth data: ノイズが軽減している。
平滑化の特徴
今回、変数oldTheta の初期値は 0 でした。そこから、正解である約90 度に達するのに、約50 回必要でした。
言い換えると、スマートフォンが傾き角を変化させてから数えて、約50 回センサーが動いた後、平滑化データが機能します。
これは、α が0.9 の場合、約50 回なので、α を0.8 にすると、正解に達する回数は減ると思われます。
この方法も、傾き角の変化が激しい場合、平滑化データが追随するのは難しいです。
しかし、「水準器」のように、傾き角が一定状態をしばらく保てる場合、この平滑化は実装がより簡単で十分に機能します。