Arduino(?)のAnalog入力のノイズをソフトウエアで軽減(?)してみる
先週、こんなん作りました。
例によって、MIDIコントローラーです。
コレはATTiny44をつかっているのですが、ArduinoのISPを使って開発していますので、まぁ、Arduinoみたいなモノ、ということで、タイトルはArduino(?)とさせていただきました。
現在、コード整理中なので、整理が終わったら、MIDI IFの部分などを含めて公開したいと思いますが、今回は、analogRead()のノイズを軽減について試行錯誤している現状を先行で公開します。
AnalogRead()で取った値をそのままMIDI送信するのはNG
MIDIコントローラーのツマミから取りたいのは、0〜127の値(MIDI CCの値)です。
analogRead()
で取得して、そのままMIDI送信すれば良いように思いますが、ここで問題が見つかりました。
- 問題①:凄い勢いでMIDI送信しっぱなしになる。
- 問題②:ノイズで取れる値がフラフラする
MIDIコントローラは、ツマミを回した時だけ、データを送るように作るべきです。
というわけで、いろいろ改善してみました。
問題①への対策:前回データと変化検知する
まず、ツマミを回してなくてもデータを送ってしまうのはやめたいので、変化検知したときだけデータを送信するようにしました。
前回データを覚えておいて、analogRead()で取得した値と比較して、違っている時だけ送信するのです。
問題②への対策1:先にビットを落とす
analogRead()で取得するデータは10bitなので、必要なbit粒度に落とします。
今回は7bitに落としたいので、3bit左へシフトします。
問題②への対策2:間隔を空けて取るようにする
10msくらい間を置いて取るようにしました。
しかし、これでも、いくらかマシになりましたが、まだフラついています。
12,11,12,12,11,12,....
こんな感じでフラフラ取れてしまいます。
これではすごい頻度で変化検知してしまいます。
問題②への対策3:変化検知を強化する
そこで、変化検知を強化しました。
具体的には、
- 「前回データ」は「前回
analogRead()
したデータ」ではなく、「前回変化検知したデータ」にする - 「前回データ」だけでなく、「前々回」「前々前回」と3つ覚えるようにする
- 「前回データ」だけでなく、「前々回」「前々前回」とも異なる値じゃないと変化検知させないようにする
- スパイク的なノイズに反応しにくくするため、行って戻っているような時、例えば、 3(今回), 2(前回), 1(前々回), 2(前々前回)となっている時は、まだ変化検知させない。
という風にしてみました。
コード(抜粋)
byte valbk[] = {0, 0, 0}; // 「前回」「前々回」「前々前回」
int vol = 0; // analogRead()では10bitで取れるので。
byte val = 0; // 「今回」データ。10bitを7bitに変換する
void loop() {
vol = analogRead(5); // 5ピンをAnalog入力とする
vol >>= 3; // 10bit→7bit
val = (byte)vol; // 型変換しとく
if(chkchange(channel,val)){
// MIDI送信処理
valbk[2] = valbk[1]; // 「前々回」を「前々前回」へ
valbk[1] = valbk[0]; // 「前回」を「前々回」へ
valbk[0] = val; // 「今回」を「前回」へ
delay(10); // 変化検知したら、少し間をあける
}
delay(5);
}
boolean chkchange(byte channel,byte val){
byte chk1 = valbk[0];
byte chk2 = valbk[1];
byte chk3 = valbk[2];
if((val != chk1)&&(val != chk2)&&(val != chk3)&&(chk1 != chk3)){
return true;
}
if((val != chk1)&&(chk1 == chk2)&&(chk1 == chk3)&&(chk1 == 0)){
return true;
}
return false;
}
まとめ
本当に回した時だけ値を受けとるために
- 最終的に使うビットに落としてから変化検知する(今回は10bit→7bit)
- 間隔を開けてanalogRead()
- 変化検知は過去数回のものと比較する
これでかなりマシになりましたので、この状態で調整を続けています。
でも、もっと良い方法があったら知りたいです。
誰か教えてください!