センサの入力などに使うディジタルフィルタ

温度センサや加速度センサなどの出力値はアナログ値であろうとデジタル値であろうとブレブレであることがほとんどです。
そのままでは使えないので必要な信号成分を取り出さないといけません。
アナログ出力のセンサの場合はフィルタ回路を組んでやってもいいですが、柔軟な対応ができなかったりします。

そこでソフトでフィルタを作ってやるとスマートにノイズの除去が可能になります。
センサ入力などにフィルタを使う場合、ノイズ除去がほとんどですのでローパスフィルタ(LPF)の紹介をします。

スポンサーリンク

前説

2Hzの正弦波に適当な雑音(白色雑音ではありません)を加えた信号を入力します。
それをArduinoとProcessingで作った簡易的なオシロスコープで入力と出力がどうなるかを見てみます。
Arduinoだとデジタルフィルタ出力の離散的な信号が連続信号に見えて非常に便利です。

最初にアナログローパスフィルタがどんなのか見てみます。
回路としては、下図になります。
アナログローパスフィルタ
今回はR=10kΩ, C=0.1uFとします。

すると入出力の波形は次のようになります。
10k 0.1u アナログローパスフィルタ
上が入力で下が出力になります。
入れたノイズが半分くらいになっていますね。
こういうのを回路で作るのではなくてソフトで処理してしまうのです、便利でしょう?

周波数特性や位相特性は特に説明しません。
カットオフ周波数などを求めたい場合は別途調べてください。

RCフィルタ

RCフィルタと同じ差分方程式のディジタルフィルタです。
抵抗とコンデンサでつくるローパスフィルタとほぼ同じです。
それのデジタル版だと思ってください。

式としてはyを出力、xを入力とすれば次のようになります。
aは係数です。

y[i] = a*y[i-1] + (1-a)*x[i]

ちょっと難しいので言葉で書きます。

出力値 = a * ひとつ前の出力値 + (1-a) * センサの値

実際に使う場合の係数aは0.8とか0.9とかにします。
係数aを大きくすると、LPFなのでどんどん滑らかになりますが応答が悪くなります。
Arduino的に書くとこんな感じでしょうか。

const int sensorPin = 0;
void setup() {}

void loop() {
  static float y[2] = {0};
  y[1] = 0.8 * y[0] + 0.2 * analogRead(sensorPin);
  
  /* フィルタ出力を使った処理 */

  y[0] = y[1];
}

a=0.9としたときの波形を見てみましょう。
波形と言っても離散値をつなげているものなので、こんな感じになるというイメージ図ですね。
ディジタルRCLPF 0.9
ノイズがほとんどなくなっているのがわかると思います。
プログラムだけで出来てしまうのです、面白くないですか?

さらにa=0.99とすると・・・
ディジタルRCLPF 0.99
かなり滑らかになりましたが、取り出したい信号が減衰し、位相も遅れています。
これはアナログフィルタにも言えることですけどね。

移動平均フィルタ

プログラムでフィルタをつくろうとするとこれが思いつきやすいのではないでしょうか。
移動平均をとって滑らかにします。

式としては次のようになります。

y[i] = ( x[n] + x[n-1] + ... + x[n-(N-1)] ) / N

言葉では次のようになります。

出力値 = ( センサの値 + 1つ前のセンサの値 + 2つ前のセンサの値 + ... ) / 個数

足し合わせるセンサの値の数を増やせば増やすほどなめらかになります。

3つの値を足して3で割ると数のような波形になります。
移動平均 3
少しましになったかな程度です。

次に10個の値を足して10で割ってみます。
移動平均 10
たぶんRCフィルタのが優秀なのかな・・・


これ以外にも様々なフィルタはありますが、これくらいまでが単純で簡単だと思います。
FIRフィルタやチェビシェフフィルタ、カルマンフィルタなどたくさんありますので調べて実装してみてもいいと思います。

スポンサーリンク

Leave a Comment