この記事で扱っていること
- 解析値を表で表しながら測定を行う方法
を紹介しています。
注意:すべてのエラーを確認しているわけではないので、記事の内容を実装する際には自己責任でお願いします。また、エラー配線は適当な部分があるので適宜修正してください。
データを測定している間、ただただデータの推移を眺めているだけでなく、そのときどきに表示されているデータの簡単な解析値を表わせると便利だと思って作ってみました。
LabVIEWに備わっている解析の関数はたくさんあるのですが、このサンプルでは簡単な値である
- 最大値
- 最小値
- ピークトゥーピーク
- 平均
- FFT
の5つの値から好きな値を表示させる機能を設けています。また、複数のチャンネルがあった場合でも対応できるようにしています。
さらに、測定が始まってから数え始めた、各項目の最大、最小履歴も表示するようにしました。
どんな結果になるか
フロントパネルはいたってシンプルです。どのような測定器を扱った場合でもいいように汎用性を持たせていますが、サンプルとして見せるために適当な波形を発生させる関数を使用しています(例としてDAQを使用した際の実装を最後のセクションで紹介しています)。
プログラムを実行すると、グラフに測定データが映し出されます。そして、リング定数からどのチャンネルでどの測定値を表に表示させるかを選択し、追加のボタンを押すことで表にその項目を追加できます。
以下の図ではグラフが一つのプロットしか見えていませんが実際には全く同じ2つめのプロットが裏にあるのでチャンネル数は2つとなっています。
また、表の項目を選択した状態で削除ボタンを押すとその項目を表から削除することができます。
プログラムの構造
イベントストラクチャで各ボタンが押されたときの挙動を決めつつ、ベースは生産者・消費者デザインパターンで組んでみました。
イベントは、フロントパネルにあるボタンの数の分だけ用意したので3つです。このプログラムの肝になっているのはmeasure_parameter_fgv.viという機能的グローバル変数です。
この機能的グローバル変数が、表にどのような項目を表示させるかを決定しています。
生産者消費者に入る前には機能的グローバル変数の初期化やチャンネル(リング制御器)へ値を入れています。
生産者消費者の方では単純に生産者ループで測定したデータを消費者ループに渡し、消費者ループでは機能的グローバル変数の中で読み取りの設定がされた項目を表に表すにようにしています。
では肝心の機能的グローバル変数の中身を以下に紹介していきます。
まずは、グローバル変数の初期化です。このグローバル変数の中には、
- 最新の波形に対する解析データと、それまでの解析データに対する各項目の最大、最小のデータを保存した3次元配列
- 選択されたチャンネル項目の情報を保存した1次元配列
の情報を扱っています。3次元配列は、Excelで言うところのシートにあたる要素番号で最新の波形に対する解析データ、履歴最大のデータ、履歴最小のデータの計3シートあります。また各シートについてはチャンネル数×解析の項目(このサンプルで言えば5つ)があるので、この分の配列を配列初期化で用意しておきます。
メインのVIの方で新しいチャンネル項目が追加されると次のitem_addのステートが実行されます。ただし、表で表した際に項目の重複を許さないために、1次元配列から重複を削除の関数を使用しています。
また削除の際には表で選択された項目をその配列から削除するようにするのがitem_deleteステートです。
そして、メインのVIの消費者ループで実行されるのが次のitem_readステートです。ここでは、さらに別の3つのサブVIを使用しています。
このステートでは
- analysis.viによって、メインVIから渡された波形データに対し最大やFFT等の解析を行いその結果を3次元配列のシート0の中に入れる
- history.viによって、3次元配列の中からシート0(analysis.viで取得した、最新の解析値)とシート1(履歴最大値を集めたもの)やシート2(履歴最小値を集めたもの)を比較し、シート1と2のデータを更新する
- extract.viによって、それぞれのシートの項目の中で、選択されたチャンネル項目のデータだけ抜き出す
- Forループで表の項目を作成
という操作を行っています。
それぞれのサブVIを以下に紹介します。
analysis.viでは解析を行っています。この部分の解析関数を変えれば、このサンプルで紹介した以上の解析項目を追加することができます。
history.viではシート0とシート1あるいはシート2の項目を比べ、3次元配列のシート1とシート2の情報を更新しています。
extract.viでは指定されたシートについて、指定されたチャンネル項目の内容を抽出しています。
measure_parameters_fgv.viに戻って、Forループを使用することで各シートから抽出した値を表形式に成形しています。
これらを組み合わせてこのプログラムが完成します。
DAQを使用した実装の例
試しにDAQを使用した際の例を示します。とはいっても、適当な波形を使用していた部分をDAQmx読み取りの関数に置き換えるだけなので特別難しくはありません。
生産者ループには待機関数はもはや不要です。
メモリ不足のエラーが起きる場合
今回のサンプル、実は高速サンプリングには対応できない可能性が高いです。(可能性、という表現にしているのは、プログラムを実行している環境にも依るところがあると考えられるからです)
もう少し厳密にいうと、サンプリングレートに対して一度に表示するデータ点数が少ないとメモリ不足エラーが起きます。これは、消費者ループ側がそこそこ処理があるため、生産者ループからエンキューされる速度に追い付かず、キューにデータが際限なくたまってしまうことでメモリ不足のエラーが起きます。
これを防ぐには、消費者ループがおおよそどの程度で回ることができるかを知っておくことが重要です。
ティックカウントを使用してループごとの速度を調べて、サンプリングレート×サンプル数がその速度よりも小さい値とならないようにします。
例えば、私の環境では消費者ループの速度は毎回50 ミリ秒以内には収まっていたので、サンプリングレートを仮に10 kHzとすると、サンプル数は500以上にする必要があります。
とはいえ、人間の目で見て50 ミリ秒なんて追えないと思うので、例えばサンプリングレート10 kHzにしているときにサンプル数は1000程度にすることになると思うので、消費者ループは十分生産者ループに追い付けます。
信号を測りながらその信号の性質を知るうえで、今回のサンプルで示しているような簡単な解析値を逐次確認していけるとその場で特徴をつかみやすくなると思います。
ここまで読んでいただきありがとうございました。
コメント