Real-Time Workshop User's Guide | ![]() ![]() |
ブロック出力による信号のモニタリング
すべてのブロックの出力データは、モデルコード内の各時間ステップでブロック出力構造体に書き込まれます。ブロック出力構造体の中の与えられたブロックの出力にアクセスするために、ユーザコードは、ポート毎に下記の情報をもっていなければなりません。
rtB
構造体のアドレスこの情報は、BlockIOSignals
データ構造体に含まれます。TLC コード生成変数BlockIOSignalsは、BlockIOSignals
データが生成されるかどうかを決定します。BlockIOSignalsが利用可能な場合は、BlockIOSignals
構造体の配列を含むファイルは、コード生成中に書き出されます。この名前は、model
_bio.c
です。
BlockIOSignalsはデフォルトで利用不可能です。model
_bio.c
の生成を可能にするには、システムターゲットファイルのConfigure RTW code generation settingsセクションで%assign
ステートメントを使います。
%assignBlockIOSignals
= 1
あるいは、Real-Time WorkshopページのTarget configurationセクションのSystem target fileフィールドにつぎのコマンドを付加することもできます。
-aBlockIOSignals=1
モデルのサイズによっては、BlockIOSignals
配列は、かなりのメモリ使用量を消費します。
BlockIOSignalsとLocal Block Outputsオプション
Local block outputsコード生成オプションが選択されると、ブロック出力はrtB
構造体でグローバルに宣言されるのではなく、関数内でローカルに宣言されます(可能な場合)。model
_bio.c
内のBlockIOSignals
配列は、そのようにローカルに宣言された信号に関する情報を含みません(システムのすべての出力がローカルに宣言されていてもBlockIOSignalsを利用可能にするとmodel
_bio.c
を生成します。そのような場合にはBlockIOSignals
配列は、nullエントリのみを含みます)。
Signal Propertiesダイアログにとってテストポイントとして指定された信号は、Local block outputs オプションが選択されていても、rtB
構造体でグローバルに宣言されます。そのため、テストポイント信号に関する情報は、model
_bio.c
のBlockIOSignals
配列に書き出されます。
そのため、テストポイントを設定したりBlockIPSignalsを利用可能にすることにより、ユーザモデルの他の信号に対するLocal block outputs 最適化の利点を失わずに、ユーザコードと選択した信号とのインタフェースを行うことができます。
model_bio.cとBlockIOデータ構造体
BlockIOSignals
データ構造体は、つぎのように宣言されます。
typedef struct BlockIOSignals_tag { char_T *blockName; /* Block's full pathname (mangled by the Real-Time Workshop) */ char_T *signalName; /* Signal label (unmangled) */ uint_T portNumber; /* Block output port number (start at 0) */ uint_T signalWidth; /* Signal's width */ void *signalAddr; /* Signal's address in the rtB vector */ char_T *dtName; /* The C language data type name */ uint_T dtSize; /* The size (# of bytes) for the data type*/ } BlockIOSignals;
構造体の定義は、matlabroot
/rtw/c/src/bio_sig.h
にあります。model
_bio.c
ファイルは、bio_sig.h
を含みます。配列を参照する任意のソースファイルは、bio_sig.h
も含みます。
model
_bio.c
は、BlockIOSignals
構造体の配列を定義します。最後の要素を除く配列の各要素は、ブロックに対して1つの出力ポートを記述します。 最後の要素は、すべてのフィールドがnull値の場合の監視用の要素です。
下記のコードは、model
_bio.c
ファイルのBlockIOSignals
構造体の配列の例です。
#include "bio_sig.h" /* Block output signal information */ const BlockIOSignals rtBIOSignals[] = { /* blockName, signalName, portNumber, signalWidth, signalAddr, dtName, dtSize */ { "simple/Constant", NULL, 0, 1, &rtB.Constant, "double", sizeof(real_T) }, { "simple/Constant1", NULL, 0, 1, &rtB.Constant1, "double", sizeof(real_T) }, { "simple/Gain", "accel", 0, 2, &rtB.accel[0], "double", sizeof(real_T) }, { NULL, NULL, 0, 0, 0, NULL, 0 } };
そのため、ブロックは、出力ポートと同じ数のエントリをもちます。上記の例で、simple/Gain
構造体は、ブロックの出力ポート0にaccel
という名前の信号をもちます。信号の幅は2です。
BlockIOSignalsを使ってブロック出力を取得
model
_bio.c
配列は、rtBIOSignals
によってアクセスされます。配列の境界を超えることを防ぐために、下記のいずれかを行うことができます。
SimStruct
アクセスマクロssGetNumBlockIO
を使って、配列内の要素数を決定します。blockName
に対してテストします。その後、rtBIOSignals
配列にわたって繰り返し、blockName
とsignalName
またはportNumber
を基にモニタリングする信号を選択するコードを作成する必要があります。信号がどのようにモニタリングされるかは、ユーザが決定します。たとえば、すべての時間ステップで信号を修正することが可能です。あるいは、別々の低い優先度のタスクで非同期的に信号をサンプリングすることが可能です。
つぎのコードの例は、Tornadoターゲットのメインプログラム(rt_main.c
)から作成されています。コードは、StethoScope Graphical Monitoring/Data Analysis ToolがBlockIOSignals
を使ってどのようにTornadoターゲットの信号の情報を収集するかを示しています。つぎの関数rtInstallRemoveSignals
は、ScopeInstallSignal
を呼び出して、BlockIOSignals
配列からStethoScope Toolに信号を選択的にインストールします。メインのシミュレーションタスクは、その後ScopeCollectSignals
を呼び出して信号を収集します。
static int_T rtInstallRemoveSignals(SimStruct *S, char_T *installStr, int_T fullNames, int_T install) { uint_T i, w; char_T *blockName; char_T name[1024]; extern BlockIOSignals rtBIOSignals[]; int_T ret = -1; if (installStr == NULL) { return -1; } i = 0; while(rtBIOSignals[i].blockName != NULL) { BlockIOSignals *blockInfo = &rtBIOSignals[i++]; if (fullNames) { blockName = blockInfo->blockName; } else { blockName = strrchr(blockInfo->blockName, '/'); if (blockName == NULL) { blockName = blockInfo->blockName; } else { blockName++; } } if ((*installStr) == '*') { } else if (strcmp("[A-Z]*", installStr) == 0) { if (!isupper(*blockName)) { continue; } } else { if (strncmp(blockName, installStr, strlen(installStr)) != 0) { continue; } } /*install/remove the signals*/ for (w = 0; w < blockInfo->signalWidth; w++) { sprintf(name, "%s_%d_%s_%d", blockName, blockInfo->portNumber, (blockInfo->signalName==NULL)?"":blockInfo->signalName, w); if (install) { /*install*/ if (!ScopeInstallSignal(name, "units", (void *)((int)blockInfo->signalAddr + w*blockInfo->dtSize), blockInfo->dtName, 0)) { fprintf(stderr,"rtInstallRemoveSignals: ScopeInstallSignal " "possible error: over 256 signals.\n"); return -1; } else { ret =0; } } else { /*remove*/ if (!ScopeRemoveSignal(name, 0)) { ifprintf(stderr,"rtInstallRemoveSignals: ScopeRemoveSignal\n" "%s not found.\n",name); return -1; } else { ret =0; } } } } return ret; }
下記は、メインのシミュレーションループから得られる信号を収集するルーチンの例から引用したものです。
/*******************************************
* Step the model for the base sample time *
*******************************************/
MdlOutputs(FIRST_TID);
#ifdef MAT_FILE
if (rt_UpdateTXYLogVars(S) != NULL) {
fprintf(stderr,"rt_UpdateTXYLogVars() failed\n");
return(1);
}
#endif
#ifdef STETHOSCOPE
ScopeCollectSignals(0);
#endif
MdlUpdate(FIRST_TID);
<code continues ...>
StethoScopeの使用法に関する詳細は、第12章「Tornadoをターゲットとするリアルタイムアプリケーション」を参照してください。
![]() | パラメータと信号のインタフェース | model_pt.cによるパラメータチューニング | ![]() |