| 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_FILEif (rt_UpdateTXYLogVars(S) != NULL) {fprintf(stderr,"rt_UpdateTXYLogVars() failed\n");return(1);}#endif#ifdef STETHOSCOPEScopeCollectSignals(0);#endifMdlUpdate(FIRST_TID);<code continues ...>
StethoScopeの使用法に関する詳細は、第12章「Tornadoをターゲットとするリアルタイムアプリケーション」を参照してください。
| パラメータと信号のインタフェース | model_pt.cによるパラメータチューニング | ![]() |