こんばんは。
今回は“アナログローパス・フィルタとデジタルローパス・フィルタの比較”ということで、回路で作ったアナログローパス・フィルタとプログラムで作ったデジタルローパス・フィルタの性能を比較してみます!
超音波センサを使っていて、そのノイズに悩んでいる方には特に参考になると思います。
それでは~
シュワッチ!
⓪用意するもの:
・絶縁ラジアルリード型積層セラミックコンデンサー0.1μF 50V 2.54mm(10個入)
①元の信号
まずは今回の企画を思いついた経緯について。
昨日、超音波センサを使って物体との距離を測定しようとしていた所、シリアルプロッタで以下の図1のような信号が得られました↓
図1:元の信号
これまで普通に使ってきたこの値ですが、グラフ化するとかなり振動していて実は使えないデータだったと分かりますね
なので、この時折混じる高い周波数のノイズを低い周波数だけを透過させるという性質を持つローパス・フィルタを用いて消していこうと思いました。
そして、調べてみるとローパス・フィルタには回路図を工夫して作る方法とプログラムを工夫して作る方法の2つがあるようなので、どちらの方法が優れているのかについても検討していこうと思います。
②アナログローパス・フィルタ
まずは“アナログローパス・フィルタ”についてです。
今回はアナログローパス・フィルタの中の1つであるRCフィルタを使用します。
RCフィルタの回路図は図2です。(wordで描いたので下手ですm(__)m)
図2:RCフィルタ
ここからは大学で習った電子回路の知識です。(軽く読んでくれれば♪)
RCフィルタのゲインは式(1)のようになります。
式(1)の実数部と虚数部が等しい時、ωCR=1であるので式(2)のようになります。
fcはカットオフ周波数といい、この周波数を境に信号の通過域と減衰域が決まります。
ローパス・フィルタの場合、カットオフ周波数よりも周波数が低い信号が通過域となります。
カットオフ周波数では振幅は元の1√2。
今回は抵抗値R=300[Ω],電気容量C=0.1[μF]のものを使っているので式(2)に代入すると、カットオフ周波数fc=5.31[kHz]であることが分かります。
実際に組んだ回路図が図3になります。
・回路図:
図3:アナログローパス・フィルタの回路図
・プログラム:
double duration = 0; //パルスが行って帰ってくるまでの時間 | |
double distance = 0; //距離 | |
void setup() { | |
Serial.begin( 9600 ); //デバッグのため | |
//超音波センサのピン | |
pinMode(3, INPUT ); | |
pinMode(2, OUTPUT ); | |
} | |
void loop() { | |
digitalWrite(2, LOW); | |
delayMicroseconds(2); | |
digitalWrite(2, HIGH); //超音波出力、START | |
delayMicroseconds(10); | |
digitalWrite(2,LOW); //超音波出力、STOP | |
duration = pulseIn(3,HIGH); | |
if (duration > 0) { | |
duration = duration/2; //duratinoのままでは往復にかかった時間なので、半分にする | |
distance = duration*340*100/1000000; // 音速(0.034[cm/μs])に時間をかけて距離を求める。ここで、"μs"にしてるのはarduinoで取れる時間がμsだからです。 | |
//"340*100/1000000*1000000"としてしまうと途中で計算の途中でとても小さい値になるからか、0[cm]としか出力されず上手くいきません | |
Serial.println(distance); | |
} | |
delay(500); | |
} |
・結果:
時折、ノイズが混じってしまっていますが使える程度のデータにはなっていると思います。
③デジタルローパス・フィルタ
次はプログラムを工夫してシステム的にローパス・フィルタを使う方法について検討してみます。
普通のプログラムに数行追記するだけなので簡単です♪
・回路図:
回路はフィルタを付けない時と同じです。
・プログラム:
int y,old_y; | |
double duration = 0; //パルスが行って帰ってくるまでの時間 | |
double distance = 0; //距離 | |
void setup() { | |
Serial.begin( 9600 ); //デバッグのため | |
//超音波センサのピン | |
pinMode(3, INPUT); | |
pinMode(2, OUTPUT); | |
} | |
void loop() { | |
digitalWrite(2, LOW); | |
delayMicroseconds(2); | |
digitalWrite(2, HIGH); //超音波出力、START | |
delayMicroseconds( 10 ); | |
digitalWrite(2, LOW); //超音波出力、STOP | |
duration = pulseIn(3, HIGH); | |
if (duration > 0) { | |
duration = duration/2; | |
distance = duration*340*100/1000000; | |
y = 0.9 * old_y + 0.1 * distance; | |
Serial.println(y); | |
old_y = y; | |
} | |
delay(100); | |
} |
・結果:
完璧です♪
ノイズはすべて消えていてバッチリのデータが取得できています。
いかがでしたでしょうか?
手間・故障のリスク・精度のどれをとってもデジタルローパス・フィルタの方が優れていることが確認できました。
ちなみに、今回はただのコンデンサを使ったためそこまで危険性はありませんでしたが、より電気容量を増やすために電解コンデンサを使うときには+とーを逆にすると爆発するので注意をしてください!!
あと、作り終えてから思ったのですが、loop()の部分が少し見にくいので超音波センサ関連の部分は関数にして外に出すべきだったかも・・・(笑)
最後に例のソフトの練習状況です↓
最後までお読み下さり、ありがとうございました。
▲▲▲アリガ島▲▲▲
「未定」
[…] サとArduinoの途中にはアナログローパス・フィルタを作っています *アナログローパス・フィルタについての昔の記事↓ アナログローパス・フィルタとデジタルローパス・フィルタの比較 […]
[…] 今回で使用する技術についての過去の記事↓ ①アナログローパス・フィルタとデジタルローパス・フィルタの比較 […]
[…] 今回で使用する技術についての過去の記事↓ ①アナログローパス・フィルタとデジタルローパス・フィルタの比較 […]