3.1 AprocS の概要
AprocS は Aproc-1/-1Plus/-2 を使った信号処理システムを開発・運用するためのツールです。
3つのウィンドウ @ A B を使って、所望の機能を効率よく実現できます。
プログラムをコマンドファイルに変換して、C/C++など他言語のシステムから利用することもできます。
この章では 例題で AprocS の使い方を説明します。 Aproc-1/-1Plus/-2 をお持ちでなくてもシミュレーション可能です。 説明に沿って操作してみてください。 → AprocSのダウンロード はこちら
→ 例題(1)正弦波の発生
→ 例題(2)信号のフィルタ
→ 例題(3)フィードバック制御
→ 例題(4)C言語による Aproc-X の運転
3.2 例題(1)正弦波の発生
Aproc-1/2 に任意周波数・任意振幅の正弦波を発生させます。
【手順 1】 スタートメニューから AprocS を起動し、 「新規プロジェクト作成」ボタン を押します。
Aproc-1/2 を接続していないと継続を問われますが、「はい」ボタンを押して続けます。
【手順 2】
このリストをソースコードエリアへ入力します。緑色の部分はコメントなので入力は不要です。
1 2 3 4 5 | proc { wave = w_sin( period, 0, amp ); // 正弦波発生 Aout( 0, 0, 1, wave ); // アナログ電圧出力 } |
赤い文字は予約語です。以下の意味があります。
proc | : | 処理の記述を始めるときの決まり文句です。 運転時には、これに続く{ }に囲まれた部分が一定周期で実行されます。 |
w_sin | : | 正弦波を発生させる関数の名前です。 |
Aout | : | アナログ電圧を出力する関数の名前です。 |
それ以外の単語 wave, period,amp は英数字で作られた任意の名前です。ここでは以下の意味になります。
wave | : | 発生させる正弦波信号の名前です。 |
period | : | 正弦波の周期を表すパラメータです。 |
amp | : | 正弦波の振幅を表すパラメータです。 |
第3行は、周期 period、振幅 amp の正弦波を発生し、それを信号 wave に代入します。
第4行は、信号 wave の値を チャンネル0番へ スケール1で(ボルト単位の電圧として)出力します。
ブロック図です。緑色が関数を表しています。
【手順 3】 「プロジェクトに名前をつけて保存」 ボタンを押し、 好きな名前で保存します。
ここでは sinwave という名前にしました。
【手順 4】 「実行コード生成ボタン」 を押します。
メッセージが表示され、オペレーションウィンドウ(操作パネル)が現れます。
【手順 5】 「パラメータ」のエリアに、以下の黄色い部分の数値を入力します。
分類 | 項目 | 数値 | 単位 | 説明 |
---|---|---|---|---|
システム パラメータ |
演算周期 | 1 | ミリ秒 | 1サイクルの時間です。 |
記録周期比 | 1 | − | データを記録するときの頻度です。 | |
記録時間 | 1 | 秒 | でデータの記録時間またはシミュレーション時間です。 | |
ユーザー パラメータ | period | 0.2 | 秒 | 発生する正弦波の周期です。0.2秒なので5Hzになります。 |
amp | 1 | − | 発生する正弦波の振幅です。出力スケール=1なので 1V です。 |
【手順 6】 「シミュレーション」 ボタン を押します。
結果がディスプレイウィンドウに現れます。パラメータを変えて再計算すれば異なる波形になります。
「表示データの保存」 ボタン を押すと、
このデータをCSVファイルとして保存できます。
【手順 7】
「運転開始」 ボタン を押します。 (Aproc-1/2接続時のみ有効)- アナログ出力端子チャンネル0番に正弦波信号が出力されます。 オシロスコープで確認してください。
- オペレーションウィンドウに、経過時間と現在の信号値が表示されます。
- ステータスバーに、1周期の演算に要した時間が表示されます。
【手順 8】 運転状態のままパラメータを変更してみます。 (Aproc-1/2接続時のみ有効)
period の値を変更してENTERキーを押すと、信号の周期がその値に変化します。
amp の値を変更してENTERキーを押すと、信号の振幅がその値に変化します。
マウスで調整することもできます。
トラックバーを動かすと、選択されているパラメータ値が増減し、波形も変化します。
【手順 9】
「記録開始」ボタン を押します。 (Aproc-1/2接続時のみ有効)
【手順 10】
「プロジェクトを保存」ボタン を押してパラメータを保存します。現在のソースコードやパラメータの値がプロジェクトファイルに保存されます。
3.3 例題(1)の続き −信号の追加−
次に、信号を増やして3相交流波形を生成してみましょう。
【手順 1】 ソースコードエリアに、以下の黄色い行を追加します。
|
|
3.1、3.2行目で 1/3 は 1÷3 という式を表します。「/」 は除算の演算子です。
関数 w_sin( ) の2番目のパラメータは、正弦波の位相角で、単位は「回転」です。
1回転は360度なので、±1/3 回転は ±120度になります。
3.1行目で wave1 は、waveよりも120度位相が進み、
3.2行目で wave2 は、waveよりも120度位相が遅れます。
4.1行目で wave1 をチャンネル1へ、
4.2行目で wave2 をチャンネル2へ出力します。
ブロック図です。
【手順 2】 ボタン を押し、別の名前のプロジェクトとして保存します。
3phase.wfp という名前にしました。
実行コードの生成に成功するとオペレーションウィンドウ(操作パネル)が現れます。信号が3つになります。
No | 状 態 | 説 明 |
---|---|---|
0 | 初期画面では wave だけが | |
1 | wave1 をフレームの中へ | |
2 | フレームに wave1 が追加されます。 wave2 もドラッグしてください | |
3 | wave2 が追加されます。 |
計算結果がディスプレイウィンドウに現れます。
グラフをクリックするとカーソルが現れ、マウスにくっついて動きます。もう一度クリックすると停止します。
別の位置でクリックすると、第2のカーソルが現れます。
右クリックするとカーソルは消えます。
→ カーソル操作の詳細はこちら
カーソルを使うと、任意時刻の信号の値や2点間の時間差、およびその逆数(周波数)をすばやく
知ることができます。
【手順 6】 「運転」ボタン を押します。 (Aproc-1/2接続時のみ有効)
アナログ出力の ch0〜2 へ、互いに120度位相の異なった正弦波が出力されます。
【手順 7】 「記録開始」ボタン を押します。 (Aproc-1/2接続時のみ有効)
3.4 例題(2)信号のフィルタリング
次は、信号を入力し、それをフィルタに通して出力する例題です。
ブロック図はこうです。
【手順 1】
|
赤い文字の予約語のうち、新たなものは以下です。
Ain | アナログ入力の電圧を数値化する関数です。この例ではチャンネル0 の電圧を、
オフセット電圧 0V、1Vあたり1の比率で数値化し、信号 input へ代入します。 |
bqLpf | 2次ローパスフィルタの関数です。
input が入力で output が出力、freq は固有周波数、damp はダンピングファクタです。 |
まず シミュレーションで確認のため、入力の代わりに「 試験信号 」を加えます。
【手順 2】 黄色い部分を追加します。
|
3行目文を「//」でコメント文にして無効化し、「 試験信号 」を 2.1行目に追加しました。
2.1行目の予約語 w_sqr は矩形波を、
gauss は正規雑音を生成する関数です。
信号 input はこれら2つの和となります。ブロック図で描くとこうです。
【手順 3】 「プロジェクトに名前をつけて保存」ボタンを押し、 好きな名前で保存します。
ここでは gauss.wfp という名前にしました。
【手順 4】
「実行コード生成」ボタン を押します。オペレーションウィンドウ(操作パネル)が現れます。
【手順 5】 「パラメータ」のエリアに以下の黄色い部分の数値を入力します。
分類 | 項目 | 数値 | 単位 | 説明 |
---|---|---|---|---|
システム パラメータ |
演算周期 | 1 | ミリ秒 | 1サイクルの時間を指定します。 |
記録周期比 | 1 | − | データを記録するときの頻度を指定します。 | |
記録時間 | 4 | 秒 | データの記録時間またはシミュレーション時間を指定します。 | |
ユーザー パラメータ |
freq | 100 | rad/s | 2次ローパスフィルタの固有周波数です。 100rad/s=15.9Hz です。 |
damp | 0.7 | − | 2次ローパスフィルタのダンピングファクタです。 |
編集を終えたら、 を押して保存しておきましょう。
パラメータの設定を終えたウィンドウです。赤い線で囲った部分が入力した部分です。
【手順 7】 「シミュレーションボタン」 を押します。
こんな表示が現れます。フィルタを通すことによって、雑音のレベルが小さくなりました。
シミュレーションで確認できたので、次は実運転になります。こんどは電気信号の入力が必要になりますので、 Aproc-1/2 に試験用の電気信号を発生させて、それを入力とします。
【手順 8】 以下のようにプログラムを変更します。黄色い部分が変更箇所です。
|
元の2.1行目の信号名を test に変え、これを 2.2行目でチャンネル2番へ出力します。
3行目は 「//」 を除いて元に戻します。input はアナログ入力第0チャンネルからの入力になります。
ブロック図で描くとこうです。
【手順 9】 アナログ出力第2チャンネルの信号をアナログ入力第0チャンネルへ接続します。
Aproc-1の場合 | |
Aproc-2の場合 | |
アナログ出力第2チャンネルには雑音が加算された矩形波が出力されますので、
シミュレーションではなく、現実の電気信号を使った試験を行うことができます。
【手順 10】 「記録開始」ボタン を押します。
ディスプレイウィンドウに、シミュレーションと同様の波形が現れます。
オシロスコープで確かめてください。
この試験がうまくいけば、アナログ入力第0チャンネルへ加えた任意の信号がフィルタされて、
アナログ出力第0チャンネルに出てきます。
3.5 例題(3)フィードバック制御
物体の温度を自動制御するシステムを作ります。
このブロック図は、温度センサとヒータで物体の温度をフィードバック制御するシステムです。
Aproc-1/2 は、緑色部分の役割を担います。すなわち、
A 温度センサの信号を入力し、
B ドライバへの指令を作成し、
C それを出力します。
【手順 1】 「新規プロジェクト」ボタン を押し、 このリストをソースコードエリアへ入力します。
1 2 3 4 5 6 7 8 9 10 |
command = "patternTemp.csv"; // 指令温度データファイル proc { cmd = polyLine( 6, command ); // 温度指令値を生成 Temp = Ain( 0, 2.5, 40 ) + 20; // 温度センサ:感度40[℃/V]、20℃で2.5V err = cmd - Temp; // 誤差算出 if err > Emax { Qout = Qmax; } // ヒータON elsif err <-Emax { Qout = 0; } // ヒータOFF Dout( 0, Qmax/2, Qout ); // デジタル出力 } |
赤い文字は予約語です。以下に主要な行の意味を説明します。
1行目 | 温度指令のデータファイル名 patternTemp.csv を command という定数で宣言します。 |
4行目 | polyLine が生成した折線信号を cmd へ代入します。
データファイルの作成は 【手順3】 |
5行目 | 温度センサを 0ch から入力し、信号 Temp へ代入します。
センサ感度(の逆数)が 40[℃/V] 、2.5V時の温度が20℃と仮定します。 |
6行目 | 指令 cmd と温度 Temp の差を 誤差 err とします。 |
7、8行目 | err がパラメータ Emax よりも大きければ Qout=Qout (出力オン)、
-Emax よりも小さければ Qout=0 (出力オフ)とします。この2行は、
関数 hysteresis を使って書くこともできます。
if、elsif については → 制御文 を参照してください |
9行目 | Doutは、 Qout の値が Qmax/2 より大ならHigh を、それ以外では Low を出力します。 |
|
|
シミュレーションでは、温度センサの代わりになる信号が必要です。
そこで、第5行の先頭に「//」をつけて、アナログ入力を無効にし、代わりに第5.1行、第5.2行を追加します。
この2行は、指令熱量 Qout が加えられたとき物体の温度変化を予想する数学モデルです。
ここで新たに使われた信号やパラメータには以下の意味があります。 →数学モデルのつくりかたはこちら
dT | : 温度の変化率 |
cond | : 外気と物体表面間の熱コンダクタンス |
Temp0 | : 外気温度 |
Cap | : 物体の熱容量 |
integral は、信号 dT を積分して温度 Temp を計算する関数です。
第1.1行、第1.2行は Qout と Temp が信号であることを明示するための記述です。 これが無いと、Qout と Temp は第5.1行に初めて現れることになるので、信号ではなくパラメータと解釈されてしまいます。 また、Temp は初期値として20℃を設定しています。 →宣言部
実行コードの生成に成功すると、オペレーションウィンドウが現れます。
以下の手順で操作してください。 → グラフ編集の詳細はこちら
1 | 初期画面ではctrlだけがグラフ枠(フレーム)にあります。 信号 Temp を右側の空いたところへドラッグします。 新しいフレームが作られ、そこに Temp が入ります。 | |
---|---|---|
2 | Temp の入ったフレームへ cmd をドラッグします cmd が追加されます |
|
3 |
フレームの Qout を 右クリック して 「下へ移動」 を選ぶと 上下のフレームが入れ替わります。 |
|
4 | err を2つのフレームの間へドラッグします
フレームの間に新たなフレームができます
|
|
5 |
これで3つのフレームに4つの信号が登録されました。 dT もどこかに追加すれば表示されます |
システムパラメータとユーザパラメータに数値を入れます。
thermal という名前にしました。
図のようなグラフが現れます。温度 Temp が指令 cmd に追随して変化していることが確認できます。 ヒータは加熱することしかできないので、温度を下げるとき誤差が大きくなりました。
これは 10秒〜35秒間の拡大図です。
Emax を小さくするとすると誤差は小さくなりますが ON/OFF の頻度が増加します。
また、感度が高くなってセンサノイズの影響を受けやすくなります
以下の作業が必要です。
プログラムをシミュレーション用から実運転用に戻します。
第5行のコメント記号「//」を外し、数学モデル(第4.1行、第4.2行)を削除します。リスト6行目(アナログ入力)のスケール値25[℃/V]、オフセットoffset=0 を実際の温度センサに一致させます。 同様にヒータON時の発生熱量 Qc の値も実際のヒータに一致させます。
温度センサの電圧をAproc-1/2のアナログ入力チャンネル0番へ、 デジタル出力チャンネル0番の信号をヒータをON/OFFするドライバの入力へ接続します。 → コネクタピン番号はこちら
3.6 数学モデルの作成例
例題(3)で、フィードバック制御のシミュレーションを行うためには、 制御を加えたときの温度を計算で推測する必要があります。 つまり、図の緑色で網掛けした部分をプログラムに含めなければなりません。これを数学モデルと言います。
本来は、ドライバ、ヒータ、温度センサも数学モデルに含めるべきですが、 プログラムではヒータON時の Qout の値はユーザパラメータ Qmaxで 1000[W] と設定していますし、 温度も、センサのスケールが 25[℃/V]として入力していますので、 Qout が物体に加わる熱量であり、Temp が物体の温度になっています。 よって、Qout と Temp の関係を考えれば良いことになります。
ここでは、温度 T0 の外気中に置かれた物体にヒータが埋め込まれていると仮定します。
ヒータの発熱量を Qout 、物体の熱容量をC、外気と物体表面間の熱コンダクタンスをηとすると、
物体の温度は次の微分方程式で記述されます。
そこで、この右辺を積分することにより温度が計算できます。そのプログラムは次の2行になります。
dT = Qout - cond * ( Temp - Temp0 ); |
Temp = integral( dT,Temp, Cap,100,0 ); |
これが、例題4【手順2】のシミュレーション用プログラムです。
第1行が微分方程式右辺の計算です。これを信号dTに代入して第2行で積分します。 integral は第1引数の信号dTを積分する関数で引数 100、0 は積分の上下限です
信号名/パラメータ名と数式の記号との対応は以下となります。
dT | ← | dT/dt |
cond | ← | η |
Temp | ← | T |
Temp0 | ← | T0 |
Cap | ← | C |
3.7 C言語によるプログラムの作成例 ( AprocS バージョン 2.0 以降の機能です )
(1) 概要
ユーザが Aproc-1/-1Plus/-2 をご自分のシステムの1部として利用できるよう、
C言語などで使えるDLL(実行時にリンクするライブラリ)を提供しています。
DLLを使ったシステムの構成図です。
AprocS で作成した信号処理プログラムをコマンドファイルとしてAproc-X へ転送し、
ユーザプログラムの指令によって信号を記録したり、パラメータ値を変更したりできます。
(2) ライブラリに含まれる関数
ライブラリは aproc.dll aproc.lib aproc.h という3つのファイルで構成されます。
その本体 aproc.dll は C言語で作成されたDLLファイルで、以下の関数を含みます。
unsigned initUSB()
USBに Aproc-1/-2/1-Plus のいずれかが接続されていれば、パソコンとの通信を可能とします。
文字列 *filename で示されるコマンドファイルの内容をシグナルプロセッサへ送ります。 転送が正常に終わると Aproc-X はその条件で運転を開始し、指定した周期でモニタ信号をPCへ送り始めます。
Aproc-X を待機状態とします。運転中なら処理は中断されます。
id で識別される AprocS プログラムのパラメータ値を value の値に置換します。
id の値は AprocS が生成したヘッダファイルに定義されています。
Aproc-Xから 演算周期×記録周期比 の周期で送られてくるデータを取得し、有意な受信データがあれば1を、無ければ0を返します。この関数の引数は以下です
引数 | 説明 |
---|---|
numSignal | AprocSのオペレーションウィンドウで「変数一覧」にチェックのついた信号の数です。 生成されたヘッダファイルでは NUMSIGNAL として定義されています。 |
*signal | 受信した信号を格納する配列のアドレスです。 要素数 NUMSIGNAL の float 配列として宣言しておきます。 |
*countTime | Aproc-Xでくり返されている制御演算の回数です。これに設定した演算周期を掛けると経過時間に相当する値となります。 演算周期は生成ヘッダファイルで DTMSEC としてミリ秒単位で定義されています。 |
*duty | 1周期に要した演算時間が 2.5us単位の整数値で送られきます。その値です。 |
Aproc-X から受信したデータを破棄します。本関数は AprocS 2.14 以降に追加されています。
Aproc-X が送信するタイミング(レイテンシタイマの待ち時間)を調整します。 引数 late のデフォルトは16(単位ミリ秒)ですが 2(ms)まで短縮できます。 本関数は AprocS 2.2 以降の追加です。
(3) AprocS が生成するデータ
プログラムウィンドウのメニュー「実行 → 指令ファイルの生成」でファイル名を指定すると AprocS はコマンドファイル xxx.cmd とヘッダファイル xxx.h を生成します。 xxx は指定したファイル名です。
ファイル名 | 説明 |
---|---|
xxx.cmd | 実行コード、パラメータ値、モニタする信号などを含むデータファイルです。 |
xxx.h | 信号やパラメータのアドレスなどを定義したC言語用のヘッダファイルです |
(4)コンソールから AprocX を操作するプログラムの例
正弦波と三角波を発生させるプログラムを Aproc-X へロードし、その状態をモニタするとともに、
周波数、振幅、位相差をキーボードで変更するC言語のプログラムを紹介します。
proc { Sin = w_sin( 1/freq, 0, amp ); // 正弦波発生 Tri = w_tri( 1/freq, phase, amp ); // 三角波発生 Aout( 0, 0, 1, Sin ); // CH0へ正弦波を出力 Aout( 1, 0, 1, Tri ); // CH1へ三角波を出力 } |
これは正弦波と三角波をアナログ出力するプログラムです。
Aproc-X が信号をパソコンへ送信する周期は 演算周期×記録周期比 となります。
記録時間は無視されますので任意です。
プログラミングウィンドウのメニューから「実行 → 指令ファイルの生成」を選び、ダイアログでファイル名 (この例では "sample" とします。拡張子は不要です)を指定すると コマンドファイル sample.cmd とヘッダファイル sample.h が同じフォルダに生成されます。
ヘッダファイル sample.h の内容です。ただし、コメントは実際にはありません
#define FILE_CMD "sample.cmd" // コマンドファイル名 #define ID_Sin 0 // 信号 Sin のアドレス #define ID_Tri 1 // 信号 Tri のアドレス #define ID_freq 1 // パラメータ freq のアドレス #define INI_freq 10 // パラメータ freq の初期値 #define MIN_freq 1 // パラメータ freq の下限値 #define MAX_freq 20 // パラメータ freq の上限値 #define ID_amp 2 // パラメータ amp のアドレス #define INI_amp 2.5 // パラメータ amp の初期値 #define MIN_amp 0 // パラメータ amp の下限値 #define MAX_amp 5 // パラメータ amp の上限値 #define ID_phase 3 // パラメータ phase のアドレス #define INI_phase 0.25 // パラメータ phase の初期値 #define MIN_phase 0 // パラメータ phase の下限値 #define MAX_phase 1 // パラメータ phase の上限値 #define DTMSEC 1 // 演算周期[ms] #define CYCLE 20 // 通信周期比 #define NUMSIGNAL 2 // 信号の数 |
Visual C++ 2008 Express で作成したサンプルプログラムのリストです。
朱色はライブラリaproc.dll の関数または生成ヘッダ sample.h に定義された定数です。
#include <stdio.h> #include <conio.h> #include <windows.h> #include "sample.h" // AprocSが生成したヘッダファイル #include "aproc.h" // AprocSに添付されたヘッダファイル #pragma comment( lib, "aproc.lib" ) // aproc.dll をリンクすることを宣言します // aproc.lib も AprocS に添付されています int main() { if( ! initUSB() ) // USB初期化 { printf( "\nエラー:USB接続できません" ); Sleep(3000); return 0; } if( ! loadProject( FILE_CMD ) ) // コマンドを転送し、運転を開始する { printf( "\nエラー:起動できません" ); Sleep(3000); return 0; } float amp = (float)INI_amp; // パラメータ amp の初期値 float freq = (float)INI_freq; // パラメータ freq の初期値 float phase = (float)INI_phase; // パラメータ phase の初期値 float signal[NUMSIGNAL]; // 受信したモニタ信号を格納する配列 unsigned countTime; // サイクル数 ( 経過時間 ) unsigned duty; // 実演算時間 ( 2.5us単位 ) while(1) { // 受信データがあればサイクル数、演算デューティー比、モニタ信号値、 // および現在のパラメータ値を表示します。 if( monitorS( NUMSIGNAL, signal, &countTime, &duty ) ) { double time = (double)countTime * (double)DTMSEC * (double)0.001; double duty100 = (double)duty / (double)DTMSEC * (double)0.25; printf( "\n%9.3fs(%4.1f%c) SIN:%6.3f TRI:%6.3f AMP:%5.2f FRQ:%5.2f PHS:%5.2f", time, duty100,'%', signal[ID_Sin], signal[ID_Tri], amp, freq, phase ); // キー入力があればパラメータを更新します。 // オシロスコープで、アナログ出力 ch0 と ch1 を見ながら操作してください。 // 'q'を押すと終了します。 if( kbhit() ) { char cmd = getch(); switch( cmd ) { case 'a' : amp *=1.125; updateP( ID_amp, amp ); break; case 'A' : amp /=1.125; updateP( ID_amp, amp ); break; case 'f' : freq *=1.125; updateP( ID_freq, freq ); break; case 'F' : freq /=1.125; updateP( ID_freq, freq ); break; case 's' : phase +=.03125; updateP( ID_phase, phase ); break; case 'S' : phase -=.03125; updateP( ID_phase, phase ); break; case 'h' : Sleep(5000); break; // 5秒間受信停止し、直ちに再開する case 'p' : Sleep(5000); purge(); break; // 5秒間受信停止し、パージ後再開する case 'q' : Sleep(3000); standby(); // 運転停止し、待機状態になる return 0; default : break; } } } } } |
Aproc-X を接続してこのプログラムを起動すると、コンソールウィンドウ(DOS窓)に Aproc-X の信号とパラメータが表示されます。キーボードで 「a」 「A」 「f」 「F」 「s」 「S」 のいずれかを押すと それに応じて波形の振幅、周波数、位相差が変化します。 終了するには 「q」 を押します。
キー入力 「h」「p」は 関数 purge() を使用することにより、停止中の受信を無視できることを示します。
この例ではマイクロソフト社のコンパイラを使ってサンプルプログラムを作成しました。 C++Builder や Delphy など旧ボーランド社のツールを使う場合は aproc.lib の書式を変換する必要があります。
改訂:2018年11月7日