測定値のグラフ表示
測定値をリアルタイムにグラフとして表示したい場合は、TChartの利用が便利です。
高速に表示する為、DirectXを利用して、自前で作成したとしても、モニターに出力できるのは、一秒間に60コマ、最大にしても、70コマ程度です。
苦労して、プログラムを作成してもあまり報われません。
グラフの描画時間としては、15ミリ秒程度であればそれ以上はあまり必要ないことになります。
実用としては、1秒に30回程度更新できれば問題でないでしょう。
どうしても、高速にサンプリングしたデーターをリアルタイムに表示するためには、オシロスコープのような専用の測定器を使用しオシロスコープにリアルタイムに表示、データーをパソコンに転送するような事をする必要がありますが、オシロスコープの高速サンプリングデーターを連続して転送することは不可能です。
オシロスコープ、データーロガー等の使用に慣れていない人に操作をさせ、そのデーターをパソコンに持ってきて、データーの処理をさせる場合は、測定器を通信により制御するようにし、トリガー条件、入力条件、速度等をパソコンで設定、データーをサンプリングするのが良い方法でしょう。
特に、測定方法が決まっている場合で、測定器の取り扱いを良く知らない人に使用してもらう場合、作業のミスを防ぐ事が出来ます。
しかし、高価な測定器を使用せず、安価なADコンバーター、速度を余り必要としない測定、測定間隔が0.5ミリ秒から数ミリ秒程度のデーターをサンプリングして、パソコンの画面に、グラフとして表示する場合の方法について検討します。
通信方法は、GPIB、LAN、USBを使用か、RS232Cの場合は、速度115Kとなりますが、現在安価な測定ユニットの場合は、USB 或いは RS232C通信が一般的です。
測定データーのサンプリング方法として、ハンドシェイクの、コマンド応答で、一つずつ送ってもらうか、測定ユニットの内部メモリーを利用して、メモリーからまとめて送ってもらう、或いは連続測定として、測定を開始させデーターを垂れ流して゛送ってもらうかです。
ハンドシェイクで、一つずつデーターを測定する場合は、タイマーで測定間隔を決め、コマンドを送信する事になります。
タイマーの分解能は、1ミリ秒以下にはなりませんので、コマンド送信、受信処理は、それ以下にはならないことになります。
垂れ流し的に送ってもらう場合は、パソコンの割り込み処理、或いはスレッドの処理速度となります。スレッド処理の場合、CPUの発熱や他のスレッドの処理を考慮し少なくても1ミリ秒程度のスリープ時間を与えるので、やはりそれ以下での処理は困難になるかと思われます。
測定ユニットのメモリーを利用して、一定の測定回数毎にデーターを転送してもらう方法であれば、可なり高速での測定が可能となりますが、リアルタイムに処理をする事は出来ません。
その場合のパソコンでのグラフの表示は、一度に送ってもらったデーター分一度に更新する事になります。
1秒に60コマの表示であれば、1コマは約16ミリ秒なので、サンプリングが、1ミリ秒であれば、転送する一回のデーター数は16個以上にすれば良いことになりますが、一度に転送する個数が少ないほうがグラフの表示が滑らかになりますが、グラフの表示時間、転送時間を考慮して設定する必要があります。
T
Chartへのデーターの書き込み方法としては、単純にAddXYでデーターを追加する方法がありますが、この場合データーが多くなってくると、グラフが詰まって何を表示しているのか分からなくと同時に描画速度が遅くなります。
そこで、データーの数が一定の数以上になったら、Chartの中に確保された、配列データーをシフトし、最後に最新の値を書き込み、表示させます、これでグラフが流れるように表示されます。
サンプリング速度が速い場合は、シフトを二個以上行い、新しいデーターも二個以上書き込むような方法をとり、サンプリング速度に追いつかせます。
しかし、本当に早いと、画面の表示コマ数/秒の関係で、チラついた画面となり見づらい画面となります。
その場合、
表示するデーターの数を500個程度とし、その個数毎に表示を変更するほうが見やすくなります。
何個表示するかは、グラフ表示の横軸のドット数にあわせるか、表示する個数にあわせて、横軸のドット数を決めます。画面のドット数以上のデーターを表示させようとしても、正しく表示されません。
次の例は、DatNo 分の配列変数をグラフに追加する部分です。
ダウンロードプログラム中の TChartSample0
が、使用例です。
var AiData: array of Double //-------------------------------------------------------------------------------------------------- // TCart グラフ出力 チャンネル数一個のみ対応 //-------------------------------------------------------------------------------------------------- procedure TMainF.thartout(DatNo:integer); var II: integer; begin if Series1.Count <= 200 then begin // グラフ横軸数 設定値以下だったら追加 for II := 0 to DatNo -1 do begin Series1.AddXY(series1.Count, AiData[II]); // series1.Count は ADDXYで自動的にカウントアップされる end; end else // 設定値を越えたらスクロール処理 begin for II := 0 to Series1.Count - DatNo - 1 do // DatNo 分左シフト Series1.YValue[II] := series1.YValue[II + DatNo]; for II := 0 to DatNo - 1 do // 新データーDatNo分上書き Series1.YValue[II + Series1.Count - DatNo] := AiData[II]; end; end;
TChartSample0を実行した画面が左図ですが、追加データー数が、配列変数で一度に追加されるデーター数で、Timer時間set の時間が、配列データーを追加する時間間隔です。
タイマースタートストップ ボタンをクリックすることで、タイマーが開始したり停止したりします。
右下のButtonとBirbtnは、表示のテスト用に単に配置しているだけで、クリックしても何も変化しません。
タイマーを開始した時 そのButtonとBitbtnをディスエブルにして、停止した時 イネーブルにします。
しかし、タイマーの時間を小さくしていくと、Buttonの表示がディスエブルの状態にならなくなります。
Bitbtnは、ディスエブルになります。
これは、画面のアニメーションがButtonに適用されており、Bitbtnには適用されていない為です。
画面のアニメーションは無効化することが出来ます。
まず[Windows]+[U]キーを押すか、[コントロール
パネル]の[コンピューターの簡単操作センター]をクリックして、[コンピューターの簡単操作センター]を起動する。次に、画面をスクロールして、一番下の[コンピューターでの作業に集中しやすくします]をクリックする。
[コンピューターでの作業に集中しやすくします]が開くので、一番下の方までスクロールして「時間制限と明滅画像を調整します」の[必要のないアニメーションは無効にします]にチェックを入れる。これで、アニメーション効果が無効化されます。
しかし、
実際には、パソコンのプログラム画面グラフ表示実行に余裕が無いために発生している現象なので、
無効化せずに、Button がディスエブル表示になるタイマーの時間が、このプログラムを実行している パソコンの性能の限界と判断した方が良いでしょう。
グラフの描画が忙しくて、アニメーションの実行が停滞してしまっています。
その証拠に、タイマーを停止した時、一旦ディスエブル表示になりイネーブル表示になります。
アニメーションを無効化すれば、CPUの負荷は可なり小さくなるのは確かですが、なるべくなら、アニメーションは有効にしておいて、実行が追いつかなくなった場合の最後の手段として取って置いた方が良いでしょう。
測定値をグラフに表示しながら、ある条件になった時、測定を止め、その前のデーターをグラフに表示したい場合があります。
現在のパソコンは沢山メモリーを搭載でるので、メモリーを有効活用します。
固定長の配列をとり、左図の様にリング状に使用します。
配列メモリーに測定値を順次書き込み、最後まで行ったら、先頭に戻り書き込みます。
グラフの表示は、測定中は、書き込んだ位置を先頭として、グラフに表示します、測定を停止した時は、グラフに表示する範囲を移動することで、過去のデーターを見ることが出来る様にします。
当然、配列の大きさを越える部分は残っていません。
ダウンロードプログラム中の TChartTest1 が実行例です。
グラフへデーターを追加するのをタイマーで行いますが、タイマーによって、特性がちがうので三種類のタイマーのテストが出来る様になっています。
測定器のイベントを利用する場合は、タイマーは不要となります。
Timer ボタンは普通のシステムタイマーでバラツキが大きく測定には向いていません。
分解能の最小値は約15ミリ秒程度ですし、バラツキも大きくなります。
WPRCTimerは、マルチメディアタイマーで、SendMessage を使用して、イベントを発生させそれを使用してデーターの追加をします。
MMTimerは、直接プロセスを呼び出します、データーの追加は、SendMessage
或いは、PostMessageを使用してデーターの追加を行います。
message を使用しないで、描画の更新をすると、エラーが発生するので注意が必要です。
MMTimerでPostMessageを使用してグラフにデーターを追加する場合は、データーを一旦配列メモリーへ入れ、配列番号をLParam、又は WParamで送信配列からデーターを取り出して、グラフに追加するようにします。
MMTimer使用時のみ SendMessage を使用するか PostMessage を使用するかの選択が出来ます。
SendMessageを使用して、タイマーの時間を小さくしていくと、小さい値を設定しても、グラフの表示時間より実際の実行時間が小さくならないことが分かります。
PostMessage 使用時は、1ミリSec迄タイマーの実行時間が小さくなります。
グラフが描画更新中は、書き込めないので、Postmessageのキューが溜まり、書き込み可能となった時、溜まっていたキューが一気に実行されます。
配列の大きさは、溜まるキューの数より大きくすれば良いことになります。
しかし、この方法は、他のmessage処理をを遅らせたりして余り良くありません。
やはり、グラフ描画更新時間分の測定データーは、配列変数に溜め、溜めたデーターをいっきに書き込むのを繰り返して、グラフ表示をした方が良いでしょう。
あくまでもサンプルプログラムなので、TChartの高速グラフ表示の検討用として下さい。
左図は、プログラム実行時使用するCPUのコアを指定できるプログラム実行例です。
サンプルプログラムの TChartTest です。
MMTimer使用時のみ三角波のグラフ表示と固定長表示、スクロール表示の指定が可能です。
三角波にしているのは、データーの欠落や、書き込みエラーがあった時に、グラフの状態から、直ぐに判別が可能だからです。
使用するコアにチェックをいれ”CPUの指定”ボタンをクリックする事で、プログラム実行時のコアの指定が出来ます。
指定を解除する場合は、全てのチェックを外し”CPUの指定”ボタンをクリックします。
指定をしなければ、全てのコアが使用されます、実際に起動した時は、どのコアで実行されるかは、システムしだいです。
本プログラムは、マルチCPU対応ではありませんので、どれか一つのコアで実行される事になります。
プログラムの作り方によっては、マルチコアで実行されると問題がでる場合の確認に使用します。
パソコンで、実行中のプロセスに対しては、タスクマネージャーで、使用するCPUコアの指定が可能です。
Vista、Win7では、タスクマネージャーを起動し、プロセス表示->プロセス選択->マウス右ボタンクリック->関係の設定で、Win8の場合はタスクマネージャーを起動し、プロセス表示->マウス右ボタンクリック->詳細の表示->プロセス選択->右ボタンクリック->関係の設定となります。
古いプログラムで、マルチコアで実行されると問題のある場合、これで問題の回避が出来ます。特にシングルコア時代のプログラムはマルチコアでの、実行順の保証がありません、画面の表示関係でトラブルが出る場合その問題を回避出来る場合があります。
しかし、同時に起動されるプロセスに対して、指定を増やすと、実行速度の低下を招く事になるので、トラブルの発生するプログラムに対してのみ指定をするようにします。
現在、CPUコアの指定をしないと問題のでるプログラムは殆どないでしょう。
プログラムによっては、CPUコアの指定をした方が実行速度が僅かですが改善される場合があります、空いているCPUコアを選択するルーチンが必要なくなる為ですが、そこまでして速度を上げる必要性は無いと思われます。
USB仕様のアナログ入力ユニットが数社から販売されていますが、データーサンプリングの設定方法、ユニットからのデーターの転送方法は、大体同じです。
CONTECのUSBユニットには、Delphi5によるプログラム例が添付されているので、此処で紹介します。
開発環境は、無料でダウンロードできるので、参照してみるのも良いのですが、USB対応のCONTECの製品が無いと動作確認は出来ません。
左図は、CONTEC社のADI16-4(USB)のサンプルプログラムにTChartを追加し実行した場合の例です。
CONTECの製品に添付されているサンプルソフトは、Delphi5用なのでXE3では少し修正が必要です。
修正は、簡単でDelphi5のAnsiCodeをUniCodeに変更するだけです。
PCharを全てPAnsiCharに変更し、CharをちAnsiCharに、StringをAnsiStringに変更すれば問題なく動作します。
サンプリングクロックは、大体600μsecが小さいほうの限界で、それより小さくすると、イベントが発生しなくなる場合があります。
但し、測定回数を指定して、測定終了イベントのみ使用して測定をすると、60μsec程度の値でも測定が可能です。
USB通信で、ソフトでイベントを発生させるので、あまり速いイベント処理は出来ません。