□ 参考ページ
自作ブロックライブラリをSimulinkライブラリに追加する
http://www.mathworks.co.jp/support/solutions/ja/data/1-9IUXR7/?solution=1-9IUXR7
ライブラリの EnableLBRepository プロパティを 'on' に設定
https://jp.mathworks.com/help/simulink/ug/adding-libraries-to-the-library-browser_ja_JP.html
簡単なマスクの作成
https://jp.mathworks.com/help/simulink/ug/how-to-mask-a-block.html
S-Function でメモリを割り当てて, アクセスする方法
https://www.mathworks.com/matlabcentral/answers/488429-how-to-allocate-memory-and-access-it-in-s-function
□ カスタムブロックの作成
フォルダ
C:\Program Files\MATLAB\R2020b\toolbox\simulink\simdemos\simfeatures\src
にアクセスするために, MATLAB を管理者権限で起動する (Windows 10)
Simulink で空のモデルに User-Defined Functions\S-function ブロックを配置する
ダブルクリックでブロックパラメーターのウィンドウを表示
S-Function 名を, system から timestwo に変更。編集
MATLAB で timestwo.c が開くので, 名前を付けて保存で GBLInport.c に変更
S-Function 名も, GBLInport に変更。適用, OK
Simulink を一旦閉じる。保存しなくて良い
(GBLOutport は GBLInport から作成)
GBLInport.c をエディターで編集
#define S_FUNCTION_NAME GBLInport
#define S_FUNCTION_LEVEL 2
#define MDL_INITIAL_SIZES
static void mdlInitializeSizes(SimStruct *S)
入力ポート数, 出力ポート数, 状態数, パラメータ数, 等の特性を指定する
ssSetNumSFcnParams でパラメータ数を指定する(4)
ssSetNumContStates と ssSetNumDiscStates で状態数を指定する(0)
入力ポート
ssSetNumInputPorts で入力ポート数を指定する(0)
出力ポート
ssSetNumOutputPorts で出力ポート数を指定する(1)
ssSetNumRWork と ssSetNumIWork でワークベクターのサイズを指定する(0)
ssSetSFcnParamTunable シミュレーション中にパラメータを変更不可にする場合は0にする(1)
ssSetOutputPortWidth でサイズは固定(1)
ssSetOutputPortDataType で型は動的(DYNAMICALLY_TYPED)
(サンプルと同じ設定)
ssSetNumSampleTimes(S, 1)
ssSetNumPWork(S, 0)
ssSetNumModes(S, 0)
ssSetNumNonsampledZCs(S, 0)
ssSetOptions を指定(0)
#define MDL_SET_OUTPUT_PORT_DATA_TYPE
static void mdlSetOutputPortDataType(SimStruct *S, int_T port, DTypeId id)
ssSetOutputPortDataType で型を id にする
#define MDL_INITIALIZE_SAMPLE_TIMES
static void mdlInitializeSampleTimes(SimStruct *S)
ssSetSampleTime
ssSetOffsetTime
index = 0
sample time and offset values = [CONTINUOUS_SAMPLE_TIME, FIXED_IN_MINOR_STEP_OFFSET]
#define MDL_INITIALIZE_CONDITIONS
static void mdlInitializeConditions(SimStruct *S)
処理無し
#define MDL_START
static void mdlStart(SimStruct *S)
Simulink はシミュレーションの開始で, オプションとして, 本関数を実行する
ユーザーデータのセットアップや状態の初期化を行う
char buffer[256];
mxGetString( ssGetSFcnParam(S,0), buffer, 128 ); //mxGetString は mxChar* から char* への変換。ssGetSFcnParam(S,0) は1番目のパラメータ(P1)
ssSetUserData(S, getInputArrayPtr(buffer));
#define MDL_OUTPUTS
static void mdlOutputs(SimStruct *S, int_T tid)
メイン処理
#define portIndex (int32_T) mxGetPr(ssGetSFcnParam(S,1))[0]
double *inputArray;
inputArray = ssGetUserData(S);
if (ssGetOutputPortDataType(S, 0) == SS_DOUBLE)
*(real_T *) ssGetOutputPortRealSignal(S,0) = inputArray[portIndex];
#define MDL_UPDATE
static void mdlUpdate(SimStruct *S, int_T tid)
処理無し
#define MDL_DERIVATIVES
static void mdlDerivatives(SimStruct *S)
処理無し
static void mdlTerminate(SimStruct *S)
処理無し
(outport の場合)
#define MDL_INITIAL_SIZES
ssSetNumSFcnParams 2
ssSetNumInputPorts 1
ssSetNumOutputPorts 0
ssSetInputPortWidth 0,1
ssSetInputPortDataType 0,DYNAMICALLY_TYPED
ssSetInputPortRequiredContiguous 0,true
ssSetInputPortDirectFeedThrough 0,1
ssSetSFcnParamTunable 0,1
ssSetSFcnParamTunable 1,1
# define MDL_SET_INPUT_PORT_DATA_TYPE
ssSetInputPortDataType 0,id
#define MDL_INITIALIZE_SAMPLE_TIMES
index = 0
sample time and offset values = [CONTINUOUS_SAMPLE_TIME, 0.0]
#define MDL_START
ssSetUserData(S, getOutputArrayPtr(buffer));
#define MDL_OUTPUTS
outputArray = ssGetUserData(S);
if (ssGetInputPortDataType(S, 0) == SS_DOUBLE)
outputArray[portIndex] = *(real_T *) ssGetInputPortRealSignal(S,0);
MATLAB のコマンドウィンドウで, フォルダ
C:\Program Files\MATLAB\R2020b\toolbox\simulink\simdemos\simfeatures
に移動して, ビルド
mex .\src\GBLInport.c
GBLInport.mexw64 が出来る
次に, S-Function を配置して, S-Function 名に GBLInport を入力し, 適用ボタンを押下すると, S-Function パラメーターが空欄のままだと, エラーメッセージが出る
S-Function パラメーターに項目を4つ入力する。適用, OK
マウス右クリック, マスク, マスクの作成
アイコンと端子, はそのまま
パラメーターとダイアログ, で, パラメーター配下にエディットを4個追加
それぞれのプロンプトと名前を編集。適用
初期化とドキュメンテーションはそのまま。適用, OK
S-Function ブロックをダブルクリックすると, パラメーターの入力画面が開くようになる
ModelName に仮に 'ParentModel' を入力
Simulink モデルを, 例えば C:\Program Files\MATLAB\R2020b\toolbox\chbstyle フォルダに, GBLPortLib_Sample.slx と名前を付けて保存
新規で空のライブラリを作成。ブロックをコピー, 貼付け。コマンドウィンドウで
set_param(gcs,'EnableLBRepository','on');
を実行する。ライブラリを GBLPortLib.slx と名前を付けて保存
ファイルの配置
ファイルを同じフォルダにコピーする。ファイルが二重になってしまうが, 手順を分かりやすくするため
slblocks.m は他のものからコピーして, 内容を現在のブロックに合わせて変更する
GBLOutport.c
GBLInport.mexw64
GBLOutport.c
GBLOutport.mexw64
slblocks.m
パスの追加
MATLAB のホーム, 環境, パスの設定, フォルダを追加, で上記フォルダを追加する
Simulink を起動し, ライブラリブラウザーを開く。最初は My Library が表示されていないので, マウス右クリック, ライブラリ ブラウザーを更新, を選択すれば表示される
□ モデル(model_main)と S-Function の両方から参照できる共通モジュールを作る
modcomm.c を作成
model_main.c で modcomm.h をインクルード
S-Function のCコードで modcomm.h をインクルード
NewSimModel_main.c で
#define noInputs 2
#define noOutputs 1
static double localInputArray_NewSimModel[noInputs];
static double localOutputArray_NewSimModel[noOutputs];
を作る (値の格納先)
そのポインタを NewSimModel_main.c の Start で registerModule(名前, 入力数, 入力ptr, 出力数, 出力ptr) を使って共通モジュールに登録する。後で名前("NewSimModel")を使って検索できる
S-Function では mdlStart で ssSetUserData を行う。ここで, getInputArrayPtr を使って名前で検索
mdlOutputs で ssGetUserData で参照 (結果として NewSimModel_main.c の localInputArray_NewSimModel を参照する)
ポートインデックスはパラメータ mxGetPr(ssGetSFcnParam(S,1))[0] で取得
mxGetPr(ssGetSFcnParam(S,1))[0] は2番目のパラメータ(P2)のインデックス0
newsimmodel_data.c にそれがある
S-Function のパラメータ
-- GBLInport.c --
moduleName 自分があるモデル名"NewSimModel"
portIndex モデル内でのポートのインデックス
b_useConstant
constValue
-- GBLOutport.c --
moduleName 自分があるモデル名"NewSimModel"
portIndex モデル内でのポートのインデックス
rt_main で参照する場合は
#include "modcomm.h"
#define Inports_NewSimModel getInputArrayPtr("NewSimModel")
#define Outports_NewSimModel getOutputArrayPtr("NewSimModel")
Inports_NewSimModel[0] = val1;
Inports_NewSimModel[1] = val2;
/* OneStep_NewSimModel(); */
val3 = Outports_NewSimModel[0];
□ ModelName が設定されていること, InportID と OutportID に抜けと重複が無いことを確認
allBlocks = find_system('NewSimModel', 'LookUnderMasks', 'all', 'BlockType', 'S-Function');
inBlocks = find_system(allBlocks, 'LookUnderMasks', 'all', 'FunctionName', 'GBLInport');
outBlocks = find_system(allBlocks, 'LookUnderMasks', 'all', 'FunctionName', 'GBLOutport');
for noInputs = 1:length(inBlocks)
fprintf('%s, %s\n', get_param(inBlocks{noInputs},'ModelName'), get_param(inBlocks{noInputs},'InportID'));
end
for noOutputs = 1:length(outBlocks)
fprintf('%s, %s\n', get_param(outBlocks{noOutputs},'ModelName'), get_param(outBlocks{noOutputs},'OutportID'));
end
あるシステムでは, m ファイルで ModelName の自動書き込み, InportID, OutportID の自動割り振りを行っている