音響パルス間隔測定機の実装へ
実用化に程遠い計測成功確率(10/2/08)
前の記事のコメントを見ていただければわかるように、Tiny861のADコンバーターの入力インピーダンスが60Ωしかないと騒いでいた事件は、kugaさんの一言で一気に解決した。LEDのノイズをさけるため慌ててAD入力のピンを移動した際、ポートの入出力方向を決めるレジスターDDRを出力(1)にしたまま動かしていたのである。MCUのこういう多目的の入出力ポートは、特定の機能を持たせたときはDDRは無関係になるという誤った先入観があって、全く無頓着だった。最初の頃は、Web記事に忠実に、真面目に設定していたと思うが、慣れてくるにしたがって横着したのが良くない。
あのコメントを見て、慌ててDDRを修正し動かしたら、ぴったりハイインピーダンスになり、10KΩ以上の抵抗を入れたLPFでも全く電圧降下なしにオペアンプからの出力がピンに出てくるようになった。いやありがたい。これでオペアンプのゲインを増やさなくて済む。それにしてもブログを開設して始めてのコメントらしいコメントがこんな大当たりのコメントだったのに感激する。kugaさんありがとうございました。それにしてもADコンバーターが出力ポートにしておいても動くとは全く考えもしていなかった。良い勉強になった。
しかし、その後の間隔測定は順調とはいえない。絶対値でなく前後の差で劇的に成功率が高くなったとはいえ、少し長く測っているとやっぱり時々間違える。しかも、誤り率が波形の正確な電子式で特に多い。入力ピンがハイインピーダンスになって出力電圧が上がりLPFで自由に波形を整形できるようになったが、電子式に最適になるようにすると、機械式がおかしくなり、機械式に合わせると、電子式がエラーだらけになる。とてもまだ実用になるレベルではない。
大体、電子式の音響波形を見ていると正確な方形波であり間違えようがないと思うのだが、これがミスするのである。サンプリング周期を1msから0.25msに早くしたり、平均をとる回数を3回から10回、20回と増やしてもパルスの立ち上がりで短いパルスと長いパルスの2つにとってしまう。
紙にパルスの状況とサンプリングのタイミング図を散々書いて調べた結果、やっとその原因がわかった。要するに、急速にパルスの立ち上がる区間にたまたまサンプリングの周期が入ると、その前後の値はちょうどピークの1/2づつの差が出来て、閾値の設定が非常に微妙になり、閾値が大きいと2つとも逃すし、小さいと2つとも拾ってしまう。どのタイミングにサンプル期間が来るかはわからない。
これは、この方式では構造的な問題で、閾値をどれだけ追い込んでも、サンプリングの巾を変えても解決できない。2点ではなく、3 点で評価すれば解決しそうだが、それほど複雑なロジックが必要なものとも思えない。もっと簡単なロジックがあるはずだ。機械式がまだ正確なのは、パルスが立ち上がった後すぐ大きく変化し、電子式のように前後がちょうど1/2になるタイミングになることが少ないからだと思われる。
リズムキャプチャーと命名(10/4/08)
パルス判定ロジックは暗礁に乗り上げたが、まあ、これはソフトウエアで解決する話だ。測定データは完全に数値化ができているし、こればかりに時間もとっていられない。先に進むため、そろそろ実装に向けて作業を開始することにした。
まず、正式な名前を考える。これまでリズムメーターと呼んできたが、どうも実態をあらわしていない。そこで、音響パルスのリズム間隔をキャプチャーする(つかまえる)「リズムキャプチャー」という名前にすることにする。これならば、このあいだのコメントにあったように、電子メトロノームと誤解される心配もない。
アナログ関係はあとはゲインの調整用の可変抵抗器をどこかにつける必要があるだけでもう余り心配はない。懸念されたLEDのノイズはブレッドボードと電源スイッチの間の接触不良が大きな原因であることがわかった。しっかり差し込むとノイズは殆ど無視できるほど下がった。電源のレギュレーションをここで悪くさせていたのか、高周波でも出ていたのかもしれない。パスコンを色々な所に挟んでノイズ対策をしていたが改善せず、放置してあったのだけれど助かった。
プログラムはこれまでスイッチでタイミングを測っていたコードを流用していたが、あとからコードを追加したため構造が複雑になってしまった。最初から作り直すことにする。今度は、持ち運べるようにLCDに表示するコードも必要だ。Tiny861 はフラッシュが8kもありプログラムはいくらでも増やせるが、入出力ポートは意外に少なく、LCD表示をしようとするとピンが足らない。ISPの3つのピンは使えないわけではないが、デバッグ用のUARTに残しておきたいし、LEDも今の3つはともかく、2つくらいは欲しいし、スイッチは測定開始終了の指示のため必須なのでこのピンもいる。結局、LEDの数を2つに絞ってピンアサインは何とか納まった。
次は、実装である。手持ちのケースやLCD、電池ケースなどを並べてレイアウトを考える。アナログ増幅のため、電源は最低でも5V近くは欲しい。するとバッテリーはやはり3つは必要で、バッテリーだけでケースの半分を占めてしまうが仕方がない。ゲイン調整のVRを何処に置くか、LCDの配置をどうするか。保守性を良くするためLCDは基板につけて、上蓋に固定するのは避けたいが、位置あわせや、見栄え良く仕上げることが難しいし、耐久性が心配だ。いやいや悩むことが沢山ある。しかしこれも電子工作の醍醐味のひとつである。
埋もれていたバグを見つける(10/5/08)
リズムキャプチャーのソフトを作り直す話である。このプログラムはイベントドリブンで、一番主要なイベントは0.25ms毎のタイマー割込みである。このときにADCを動かし音響入力を測定する。回数を数えておいて一定の間隔でADCからの出力を平均化し、前回の数値と比較して閾値を越えればフラグを立てる。別のところでも数をかぞえていてこれはLEDを点滅させるのに使う。次の割込みでさっきのフラグを見て別のタイマーを止め、これまでの時間を測る。これがリズム間隔となる。このタイマーはただちにスタートし次の間隔を測り始める。
このイベント以外に不定期に発生するイベントが2つある。ひとつは測定開始・終了を制御するスイッチ割込みと、リズム間隔を測るタイマーがオーバーフローすると(4秒余り)、タイムアウトして計測を中止し初期状態に戻すタイマー割込みである。この2つはさっきの0.25msの割り込みとは全く独立していつ起きるかわからないイベントである。
そう難しい構造ではないが、プログラムの中のフラグやスイッチはなるべく少なくしたい。良い加減に作っていくとスパゲッティになる。久しぶりに擬似コーディングを紙の上でやった。擬似コーディングという言葉に聞きなれない人も多いだろうが、要はいきなりソースコードを書いて行くのではなく、普通の言葉でプログラムの動作をステートメント風に箇条書きに書いて矛盾がないか確かめる方法である。if文やwhile文の条件文も日本語で書く。こうするとロジックが理解しやすい。
もうひとつ肝腎なことは、自分が使う立場になってソフトウエアの仕様を完全に決めてから開発に入ることだ。操作面(業務要件)から入るのは、大規模ソフトウエアのときと変わらない。中途半端に仕様を決め開発に入ってしまうとあとで痛い目に会う。特に何か処理をするときのことは一生懸命考えるが、それが終わったあとどうするかまではなかなか考えておかない。これをつめておかないと丈夫なソフトウエアにはならない。
今度のリズムキャプチャーの操作仕様をまとめてみた。まず、電源を入れるとウエルカムメッセージが出て、電源が入ったことが確認できる。スイッチを一度押すと、測定が始まる。リズム音を検知するとLEDが点灯し測定に入ったことがわかる。最初は測定値だけだが、何回か測定が進むと平均値のメトロノーム数(一分間の拍数)が出る。測定中にスイッチを押すと無条件に測定を中止し、もう一度押すと測定を再開する。拍の間隔が5秒以上になるとタイムアウトとして初期の状態に戻り、測定中を示すLEDが消える。
以上のことをなるべく構造を簡単にしてプログラムしていくわけである。まあ、これ以外に気を遣う事は山ほどある。割込みルーチンの中にはなるべく複雑な処理をいれない。これはレジスター退避などを少なくしてフラッシュメモリを節約するためもあるが、処理をなるべくメインルーチンでひとまとめにしてあるほうが、デバッグの時に余計な心配をしないで済む。それに余り長い間割込みルーチンに入っていると、別の割込みが入ってフラグが変わってしまい、わけのわからないバグに悩まされる。このあいだのI2Cドライバーのときも非同期にプログラムが2つ動いていてこれにやられた。
今度のソフトは最初、3つのフラグを使っていたが、擬似コーディングを重ねて、ひとつ減らすことが出来た。しかし、フラグを減らすことばかり気を取られていると、構造がかえって複雑になり、デバッグに苦労することになる。何事もバランスが大切だ。
などと能書きを垂れつつ、やっとソフトが完成した。これまではスイッチをメトロノームの音響パルスに見立てたテストプログラムだが、今度は実装を前提にした本格版である。公開にそなえてコメントもなるべく入れる。
と、これが動かないのである。かなり自信を持って組み上げたはずなのだが、開始のスイッチを入れてもうんともすんとも言わない。やれやれ、テストステートメントを挿入し動きを追跡する。スイッチで開始フラグが立つのだがスイッチを押してもフラグが立っていない。さらにテストステートメントをスイッチ割込みのところまで増やしてテストする。
なに、割り込みが2回も起きている。スイッチはトグル(0なら1、1なら0)なのでこれでは永遠にスタートにならない。チャタリングなのか。待ち時間を増やす。これでも解決しない。しかたがない。ロジックアナライザーを持ち出す。マイクロスイッチのチャタリングは1ms以内でそのあと全く起きていない。しかし、フラグは暫くして(20msほど)、元に戻る。なんだ、なんだ、これは。
暫く考えて、原因がわかった。スイッチは10数回チャタリングを起こしていて割込み要求を上げ続けるが、割込みルーチンに入ったところで処理されるのは最初の割り込みのときだけで、残りはペンディングになったままだ。割込みルーチンを出たところでまた割り込みがかかる。やれやれ、この前もこんなことがあった。ルーチンを出る前に割込み要求フラグをクリアすることで解決した。しかし、このコードは散々他のプログラムで使っている。何故今まで起きなかったのだろう。
今までのプログラムは2回以上割込みルーチンを通過しても問題のないことしかやっていなかった(クリアなどを何回やっても変わらない)からだと思う。こんどはトグルスイッチの機能を持たせたので埋もれていたバグが顔をだしたというわけだ。いやいやプログラムの世界も奥が深い。
オシロで波形が見えるのも考え物(10/7/08)
パルス判定ロジックの問題が解決した。なまじ全ての音響パルスの姿が見えたためにアナログ的な判定ロジックをあれこれ考えていたが、そんな難しく考えることは不要だった。
オシロの波形を見ながら、何故人間はこれはパルスだとすぐわかるのに、機械ではうまくいかないのかと考えていた。人間はパルスが起きた後の全体の波形を見られるから、パルスと認識できるが、機械は次から次に発生してくる音の大きさだけで判断しなければならない。非常にせまい視野で、これがパルスだと判断する必要がある。
判定ロジックをWebに相談しようにも検索キーワードの見当がつかない。学問のどの分野に入るのかもわからない。2点(前後)の比較だけでは無理なのだろうか。だが、3点なら間違いなく判定できるかは保証の限りではない。どうもこの方法(相対差で判断する)では3点でも完全ではないような気がする。
最初、パルスの大きさの絶対値でうまくいかず、相対差でやってうまくいったため、これにこだわっていたが、もういちど絶対値比較の方法を考えてみることにした。ADコンバータでなくコンパレーターでこのデータを考えてみたのである。
デジタル化したチャートを手書きで描いてみて、頭に電灯が点った。なんだ、こいつはスイッチのチャタリングと同じだ。沢山デジタルパルスが出ているが、パルスグループの次の間隔は短くても300ms以上ある(拍数で200以上)、パルスのブロックは精々50ms。
オシロのアナログ波形にこだわりすぎていた。閾値を越えるパルスを観測したら、そのあとのパルスは無視し、パルスのおさまる時間(50ms)から観測を再開すれば、次のパルスを間違いなく捉えられる。なんだ、なんだ。どうしてこれに気がつかなかったのだろう。
早速、コーディングする。ADCの値を比較するのは1ms単位なので、カウンターを入れて、パルスを観測した後50回までは、パルスが来ても無視するようにする。
やった、やった。3つのメトロノームとも百発百中。全くエラーを出さずに間隔を表示する。素晴らしい。いやそれにしてもここまでの道のりは長かった。オシロでそれぞれのメトロノームの音響波形がそれこそマイクロセカンドのオーダーで観測できるものだから、ついこれにこだわっていたが、あまり細部が見えるのも良し悪しであることを学んだ。
| 固定リンク
「電子工作」カテゴリの記事
- 生存証明2(2022.10.19)
- 生存証明(2022.01.23)
- パソコン連動テーブルタップの修理を諦めて自作(2021.02.16)
- 半年ぶりのブログ更新に漕ぎつけた(2019.09.19)
- 研究所活動は停滞したままでCCDカメラ顕微鏡導入など(2019.02.08)
コメント
ADCの想像があたってよかったです。
UARTなどの機能のを使う場合、ポート設定に関わらず
PIN機能が強制設定されるCHIPが多いですよね。
ADのポートが出力に設定できると、外部に接続した積分用の
コンデンサを強制放電させたり、面白い応用もできそうです。
投稿: kuga | 2008年10月 8日 (水) 17時27分