この記事で扱っていること
- グラフの全体を見ながら部分的にズームする方法
を紹介しています。
注意:すべてのエラーを確認しているわけではないので、記事の内容を実装する際には自己責任でお願いします。また、エラー配線は適当な部分があるので適宜修正してください。
LabVIEWで使用できるグラフ表示器は、標準機能として拡大機能が備わっています。
ただ、当然のことながら拡大機能を使うことによって全体の様子は見えなくなってしまうので、そこが不便に感じることもままあると思います。
そこで、二つのグラフ表示器を配置し、片方は波形全体を表示してもう片方はその波形の一部を拡大表示するように組めば、全体を見ながら部分的に拡大させることができます。
今回のプログラムではグラフのカーソル機能を用いて、「どの部分を拡大しているか」を表示させることで使い勝手を良くしています。
どんな結果になるか
波形データを既に取得している前提として、その波形データのファイルを指定するパス制御器や二つのグラフ表示器以外に、どの部分をズームさせるかを指定するための数値制御器(一つはスライダ形式)を置いています。
プログラムを実行しファイルを選択すると、そのファイルから読みだしたデータをグラフに表示します。
上のグラフでは全体像を、下のグラフでは、上のグラフの指定領域を拡大して表示します。(領域は上のグラフで赤い線で挟まれた部分)
拡大表示する領域の位置や幅は自由に調整ができます。
これにより、全体像を確認しながら部分的に好きな位置を拡大表示させることができます。
プログラムの構造
今回は敢えて生産者消費者のデザインパターンを採用しています。
別に生産者消費者のデザインでなければ組めないということはないですが、こうすることで、後述するハードウェアを使用したプログラムにもとてもよく似た形のプログラムで対応できるようになるためです。
ただしファイルから読みだす方法の場合、生産者ループからデータがエンキューされないと消費者ループが動かなくなってしまうため、これを避けるためにデキュー関数のタイムアウトの設定を活用し、エンキューされなくても定期的に消費者ループが動くようにしています。
ループに入る前に、データ全体を表すグラフの方でカーソルについてのプロパティを設定しておきます。
特にカーソルリストのプロパティを設定しておかないと、上側のグラフで拡大表示の領域を表せなくなってしまいます。
生産者ループの方ではファイルの読み出しを行いますが、ファイルパスが変わったときだけ消費者ループにデータを渡すような仕組みとしています。
そのために、シフトレジスタを使用して、ファイルパスの値が変わっているかどうかを逐次確認しています。
消費者ループの方では、受け取ったデータ(今回は波形データにしています)をそのまま使用するかあるいはフィードバックノードで以前に受け取っていたデータを使用するかを最初に決めています。
デキュー関数のタイムアウト?出力の値とフィードバックノードの有効化端子を使用することで新しいデータが来たかを判定しています(この仕組みにしないとタイムアウトの場合には空の波形データが処理されてしまうことになる)。
肝心の処理の中身は以下の図のケースストラクチャに書いてある通りで、部分配列を使用したりグラフのアクティブカーソルプロパティおよびカーソルのX位置プロパティを以下の図のように指定することで、拡大位置を表示できるようにしています。
ハードウェアでデータ集録をする想定の場合
上で紹介したプログラムは、ファイルからデータを読み込んでいましたが、同じプログラム内でハードウェアの操作も含めて行う場合でも、生産者ループの中身を少し変えるだけで応用が効きます。
ようは生産者ループをファイル読み取りではなくハードウェアから読み取った値を使用するように書き換えるだけ、ですね。
今回の例では、NI社のDAQデバイスを使用していることを想定していますが、サードパーティの計測器であっても、データを取得する関数を以下の図と同じような形で配置すれば同様なことが行えるはずです。
なお、実際の測定は1つのチャンネルだけの測定ということはなく、複数のチャンネルの測定を行うものと思います。
そんな場合に、指定した特定の1チャンネルのみ拡大表示を行うということもできます。
やっていることは単純で、どのチャンネルを拡大するかという指定である数値制御器の値を用いてデータの配列から指標配列処理によって特定のデータのみを抽出して表示させてやるだけです。
よりパフォーマンス重視のプログラムにする場合
ファイルから読み取る場合であれ、ハードウェアから読み取る場合であれ、さらにパフォーマンスを重視する、具体的には「無駄な繰り返しを起こさせない」ようにするためには、イベントストラクチャを使用するという選択肢があります。
イベント登録を駆使すれば、イベントストラクチャを使った生産者ループ一つで対応することはできますが、馴染みのない方も多いかなと思うので、ここでは敢えて愚直に生産者ループを二つにして対応する方法を紹介します。
ただし、二つの生産者ループで別の種類の値を扱うことになるため、キューで扱うデータタイプは文字列とバリアントを組み合わせたクラスタとしています(キューメッセージハンドラデザインパターンを知っている方にとっては馴染み深いと思います)。
イベントストラクチャが入ったループでは、今回4つのイベントを定義しています。
各イベントが実行されると、それらに対応する値を消費者ループで扱うために、列挙体とその列挙体項目に関連したデータをまとめてキューで送っています。
イベントストラクチャが入ったループ以外にあるもう一つの生産者ループは、既に紹介した、ハードウェアからのデータを取得しているだけなので説明は省略します(ただし、stateとして「update wave」という列挙体項目とともに波形配列データを消費者ループに渡しています)。
消費者ループでは、生産者ループによって指定されたstateに応じてケースストラクチャの中身が実行されていきます。
以下の図で示したupdate displayは、他のstateが実行された後に実行されるようにしており、何かしらパラメタ(例えば「始まり位置」)が更新されると常にこのupdate displayが実行されることで、パラメタの変化による表示の更新を行います。
消費者ループでの各stateの中身は以下を参考にしてみてください。
update display以外の全てのケース内で、update displayのstateをエンキューしているのがわかると思います。
なお、上に書いたように、イベントストラクチャを使用することで、DAQハードウェアで測定したデータをLabVIEW側で取得するという動作もイベントに登録することができます。
イベント登録に興味がある方は、LabVIEWのツールバーの「ヘルプ」から「サンプルを検索」で開くNIサンプルファインダにて「電圧(イベント付き) – 連続入力」を参照してみてください。
本記事では、グラフの全体を見ながら部分的にズームする方法を紹介しました。
アプリケーションの目的によって、結果をどのように見たいか(見せたいか)というニーズは変わると思います。
グラフ表示器に元からある機能としてのズーム機能では不便だ、というときに参考になればうれしいです。
ここまで読んでいただきありがとうございました。
コメント