回転数信号を拾って、それを元に正確な Digital Rev Counterや、Shift Up Point Indicatorや、その他諸々のアイテムを製作しようというコーナーです。
ある程度まとまってからWebpageにしようとすると、結局面倒くさくなってそのまま埋もれてしまったりするので、思いついたコトをその都度ノートにだらだらと書き留める感覚で同時進行形でアップしていく予定...(??)
先ずは、単純に表示部分が無い回転数計測モジュールを作ります。
方針は、
です。
なので、ごちゃごちゃとゲートICを組み合わせたロジック回路などは作らずに、PICというワンチップマイコンで行きます。
センシングする信号は何にしましょうか?
思いつくモノを挙げます。
IGfが一番適当かな?
但し、IGfはクランク角度に対する位相が一定ではありませんから、メーターを高速応答させようとした場合、真の回転数に対し測定値がふらつく筈。
応答を遅くして測定値を安定させると過去の履歴を引きずるので、回転数一定の時は正確に示す代わりに、回転数が変化して行く状況ではやはりその瞬間の真の回転数に対し誤差が生じる。
応答を早くしようが遅くしようが、どちらにしても誤差要因が増えるんですよね(^^;)。
一方、カムシャフトポジションセンサ(or クランクアングルセンサ)は位相は固定。
だから、精度を得るにはこちらが理想的なんですけど、この信号は車種によってパルスの出方が色々なんですよね。
光学式かピックアップ式かでも全然違う。
それに合わせて入力部を切換えなければいけない。
残るオルタネーターノイズは、エンジンシ回転数に周波数が比例するノイズが、シガーソケットから電源取ればもれなく付いてくる(笑)ので、適当にフィルタでノイズ成分を抽出してやれば良い。 電源をつなぐだけで別途信号をセンシングしなくても良いので、一番お手軽。 でも精度は×。
結局、IGfで行くことにしましょう。。
クランク一回転で何パルスかさえスイッチで設定するようにすれば、他の車種にもそのまま使える訳ですからね。
応答速度と精度の問題は、ソフト側でなんとかします。
IGf信号は各気筒の点火に合わせてパルスが出ますから、クランク1回転に付き2パルス。
ある一定時間のパルスの数を数えれば、それから回転数が求められます。
理論上パルスの周期を測定しても求められますが、回転数に対して反比例の関係にある為、割り算しなければいけないのと、カウンタの桁数が不足するので×。
回転数をN[rpm]、カウント期間をP[sec]、カウント値をnとすると、
N = 30 × n / P [rpm]
カウント期間を30秒にすると、1カウント=1rpm (笑)
3秒にすれば、1カウント=10rpm
0.3秒にすれば、1カウント=100rpm
と、この様に分解能と応答速度とはトレードオフの関係にあります。
3秒はいくらなんでも遅すぎるから、0.3秒が妥当なところか?
しかし、人間が見る為の表示だけならともかく、内部データの処理に100rpmではちょっと荒い気がする。
さらに言うと、シフトアップポイントインジケーターに使うには、0.1秒刻みぐらいで処理したい。
しかし、分解能が300rpmでは全くお話しにならない。
0.1秒データ更新で、50rpm程度の分解能はどうしても欲しい。
さあ、どうする(笑)?
仕事しているフリをして考え出した案です。 モジュールを2つ用意します。
上記によって、0.1秒毎に過去0.3秒間の平均回転数が100rpmの分解能で計測されます。
この計測値をAとします。
そして、これに加えて。
これによって、0.1秒毎に過去0.6秒間の平均回転数が50rpmの分解能で計測されます。 この計測値をBとします。
シフトアップポイントインジケーターの様な、分解能よりも高速応答が求められるアプリケーションには、当然Aを用います。
んで、回転数のディジタル表示などには、回転数が大きく変化している状態ではAを、あまり変化していない状態ではBを、という具合に適宜選択して表示させます。
具体的には、毎回AとBの差分を取ってそれがある一定値以内であれば、回転数があまり変化していないと判断できるので、より分解能の高いBを選択してやれば巧く行くのではないかと考えています。
もっと分解能を上げる為に、カウント期間3秒のモジュールも用意して、分解能10rpmまでやろうかとも思ったんですが、語長8bitなので、わずか2,560rpmでオーバーフローしてしまうことに気が付いてボツ。 分解能50rpmなら12,800rpmでオーバーフローだけど、B型は絶対そこまで回らんので大丈夫。(笑)
ところで、PICマイコンにはカウンタは1つしかありませんので、上記の複数のカウンタというのは、あくまで考え方であって、実際にはソフトによって仮想的に用意します。
これまで単位時間あたりのパルス数を計測する方式で構想していたのですが、ある日のこと、パルス周期を計測する方式で巧くやる方法を思いついたので、こちらに方式を変更します(^^;)。
回転数をN[rpm]、IGfパルス周期をt[msec]とすると、
N = 30000 / t
これから、500rpmのとき、t = 60[msec]
8000rpmのとき、t = 3.75[msec]
8100rpmのとき、t = 3.7037[msec]
です。
ということは、分解能100rpmとすると、8100rpmと8000rpmとの周期の差が 0.0463msec なので、下は500rpmまで測ろうとすると、60 / 0.0463 = 1295.896 となり、255までしか数えることのできない8bitカウンタには収まりません。
16bitカウンタに拡張すればカウントはできますが、ちょっと面倒なのと、それに割り算処理が必要なので敬遠していたワケです。
ところが、IGfパルス周期を測定しながらも、カウンタは8bitで済んで、尚且つ割り算も要らないアルゴリズムを思いつきました。
仮に測定上限を10000rpmとします(笑)。 分解能は100rpmとして、回転数とIGf周期とのテーブルを作成しますと...
| N [rpm] | t [μs] | Δt [μs] |
|---|---|---|
| 9950 | 3015.075 | |
| 9850 | 3045.685 | 30.00075 |
| 9750 | 3076.923 | 31.2378 |
| 9650 | 3108.808 | 31.88521 |
| 9550 | 3141.361 | 32.55297 |
| : | : | : |
Δtがミソでして、プログラムコードの中にこのΔtのテーブルを用意しておきます。
んで、先ずIGfパルスが一発来たら、カウンタを100にセットして、3015.075μsec待ちます。
[ループの先頭]
次のIGfパルスが来ていたら、ループを抜ける。
パルスが来ていなかったら、カウンタを1マイナス。
次のテーブルのΔtを読んで、その時間だけ待ちます。
ループの先頭に戻る。
以上の処理を抜けてきた時点でのカウンタ値×100とすれば、それがそのまま回転数となるので、割り算が要らないという仕組みです。
但し、IGfはクランクアングルに対して位相が変動するので、数回測定してその平均を取る処理を入れることになると思います。 それでも、クランク2〜3回転毎の回転数がきっちり計測できますので、申し分の無い応答速度が得られる筈です。
さて、以上のようなアルゴリズムでコーディングし回路を試作して実装した所、信号発生器の信号をIGf信号に見立てての机上実験では狙い通り動作しましたが、いざ実車に搭載して実験してみるとノイズによる誤動作が頻発しました。
実際のIGf信号波形というのは、正規のパルスに加えて色々なノイズが乗っていて、そのノイズを一つのIGfパルスと見間違えて、見当違いの回転数がはじき出されてしまいます。
その対策として、波形成形回路に定数をようく吟味したローパスフィルタを入れます。
んが、頻度はぐっと低くなりはしましたが、それでもごく希に誤動作します。
そこで、ソフトの方でもノイズを取り除く処理を行うことにしました。
誤動作する仕組みは例えばこんな感じです↓
という訳で、例えばシフトポイントインジケーターなどでみると、設定回転数とは全然違うところで一瞬ランプが光るという現象となります。
これを無くす為には、どうしたらよいのでせう?
過去4回の測定値を平均するという処理を行っていますけれど、5000rpm、5000rpm、5000rpmの所に誤って10000rpmが飛び込んで来たりすると、平均が6250rpmと1250rpmもジャンプしてしまいますので、平均化処理は効きません。
平均を取るデータ数を増やせば、今度は応答が遅くなっちゃいますし。
誤ったデータというのは異常に高い値を示すので、そいつを無視するように仕組めれば良さそうです。
そこで考えたのが、スポーツ競技なんかでよくやっている5ジャッジの内最大と最少の得点を捨てた3つを採用するという方式のマネ。
低い方の誤測定は原理上あり得ないので、過去5回測定の内から最大値を捨てた4データから平均を取るという処理にしました。
5回中1回ならノイズでデータが狂っても最終的な測定値は影響を受けません。
もし2回以上ノイズが飛び込んだら... その時はごめんなさいっちゅうことで...(^^;)
つづく...