リアルタイムで外部測定器から入力したデータを折れ線グラフに表示する
プログラムを作成しています。
大まかな開発環境は以下の通りです。
OS: Windows XP
Visual C++6.0 (MFC使用)
現在のプラグラムでは、メモリDCに描画したグラフをデバイスコンテキストに
転送していますが、StretchBltを使用すると、プロット(折れ線)がひずんでしまい、
きれいに描画できません。
StretchBltについて調べましたが、この関数では限界があるため、
使用するのをやめました。
また、単純に物理ファクタを変更すると、データ収集量に比例してCPUへの負荷が
相当なもの(100%)になります。
CPUへの負荷が重くなりすぎず、グラフを伸縮する方法がありましたら
教えていただけないでしょうか?
まず、モニタ画面はせいぜいX=2000ピクセル程度だと仮定すると
グラフのプロット点は1000あれば十分だと言えます。
サンプリング数が1000を超えたらスクロールするようにすれば
グラフ描画の線の本数は999本になります。
この程度なら今のPCは軽く描画できるはずです。
この場合、縦横の拡大率とオフセット演算を行っても余裕のよっちゃん
のはずで、CPUが100%になることはないはずです。
これでも100%になるようなら別の原因を疑うべきだと思います。
回答ありがとうございます。
X軸(時間軸)に関しては、スクロール機能を持たせていますので、
画面上に描画しているプロット数は、1000にも満たないと思います。
しかし、今回のプログラムでは、過去のデータもスクロールで閲覧可能にしていますの
で
画面上に描画されていないデータを考慮すると、相当数のデータが存在しています。
1秒間隔で24時間のデータを30チャンネルで収集した場合、260万ほどのデータが
蓄積されますので、この時にY軸の伸縮を行うと、CPUがとても重くなってしまいま
す。
これは仕方ないんでしょうか。
ものの考え方によりますが、「表示しているデータは元のデータの
一つの表現結果にすぎない」と考えるべきではないでしょうか。
従って、拡大縮小などの「表現上」の修飾は、「表示しているデータ
に対してのみ行う」べきだと考えます。
260万もの、全てのデータに対して無用な演算を施すべきでは
ありません。
なんとなくですが、[描画している]=[画面に見えている]と考えていませんでしょうか?
実は画面に見えていない部分に、
MoveTo(), LineTo(), Rectangle(), BitBlt(), StretchBlt(), ...
などをしても、きちんとCPUを消費し、処理時間がかかっています。
ただ、最終的に画面に表示される直前で捨てられている(クリッピング)だけです。
それに、
MoveTo(), LineTo(), Rectangle(), BitBlt(), StretchBlt(), ...
には座標値の指定が必要なはずですが、座標値の取得処理(場合によっては計算処理を含
む)をあなたのアプリケーションで行っているはずで、その時間も取り戻せません。
結論としては、画面に見えていない部分は、何の処理もしないことです。
(正確には無効領域だけを描画、スクロール時は画面全体が無効領域とはなりませんの
で、見えているところ全部でも無駄な描画が存在します)
それだけで、(X軸が長い場合には)劇的に速くなります。
なお、厳密にどこまでが画面に見えているかの判断は難しいので、確実に画面外のみの
描画になる場合だけ、処理をやめれば十分です。
簡単に書いてしまうと書く必要のない部分は処理しない
する必要のない処理はしないと言うのが高速化の基本です。
あと、一回しておけば良い処理は結果を保存して何回もしないとか。
画面外にはいっさい書かないとまでする必要はないでしょうけれど、
明らかに画面外とわかるものまで処理するのは時間の無駄になります。
皆さんありがとうございます。
高速スクロール時の負荷を下げたいという考えもありましたが、それはあきらめて
実画面上のグラフ部分だけ処理するようにプログラムを作成してみます。
ただ、グラフの時間軸を圧縮してものすごいデータ数を処理する必要が有る場合は、
データの間引きか何かをした方がいいかもしれないですね。VGAのディスプレイに
何万ものポイントは表示されないですし。
>ただ、グラフの時間軸を圧縮してものすごいデータ数を処理する必要が有る場合は、
>データの間引きか何かをした方がいいかもしれないですね。VGAのディスプレイに
そのような場合は、間引くのではなく、その間のサンプルデータ群の
1.ピーク(最大/最小値)をとって代表値とする
2.平均値をとって代表値とする
のようにしたほうが、違和感が和らぎます。
検討してみてください。