Level-2 MATLAB S-Function
文章目录
- [Level-2 MATLAB S-Function](#Level-2 MATLAB S-Function)
-
- [一、 打开Matlab模板](#一、 打开Matlab模板)
- [二、 Level-2 MATLAB S-Function结构](#二、 Level-2 MATLAB S-Function结构)
- [2.1 总体架构:三层结构](#2.1 总体架构:三层结构)
- [2.2 第一层:主函数](#2.2 第一层:主函数)
- [2.3 第二层:setup 函数](#2.3 第二层:setup 函数)
-
- [1. 端口设置](#1. 端口设置)
- [2. 参数设置](#2. 参数设置)
- [3. 状态与采样时间](#3. 状态与采样时间)
- [4. 选项配置](#4. 选项配置)
- [5. 方法注册------ 最关键的部分](#5. 方法注册—— 最关键的部分)
- [2.3 局部函数实现](#2.3 局部函数实现)
-
- [A. 参数与配置检查](#A. 参数与配置检查)
- [B. 端口属性传播](#B. 端口属性传播)
- [C. 工作区(DWork)设置](#C. 工作区(DWork)设置)
- [D. 仿真运行核心逻辑](#D. 仿真运行核心逻辑)
- [E. 生命周期钩子](#E. 生命周期钩子)
- [2.4 结构总结:时序与职责](#2.4 结构总结:时序与职责)
- [2.5 设计模式总结](#2.5 设计模式总结)
一、 打开Matlab模板
matlab
edit msfuntmpl
打开模板可以看到以下代码,
matlab
function msfuntmpl(block)
%MSFUNTMPL MATLAB S-Function 模板
% MATLAB S-function 被编写为一个与 S-function 同名的 MATLAB 函数。
% 请将 'msfuntmpl' 替换为您的 S-function 的名称。
% 版权所有 2003-2018 The MathWorks, Inc.
%
% setup 方法用于设置 S-function 的基本属性,
% 例如端口、参数等。请勿在主函数体中添加任何其他调用。
%
setup(block);
%endfunction
% Function: setup ===================================================
% 摘要:
% 设置 S-function 模块的基本特性,例如:
% - 输入端口
% - 输出端口
% - 对话框参数
% - 选项
%
% 必需 : 是
% C MEX 对应函数: mdlInitializeSizes
%
function setup(block)
% 注册端口数量。
block.NumInputPorts = 1;
block.NumOutputPorts = 1;
% 将端口属性设置为继承或动态。
block.SetPreCompInpPortInfoToDynamic;
block.SetPreCompOutPortInfoToDynamic;
% 覆盖输入端口属性。
block.InputPort(1).DatatypeID = 0; % double 类型
block.InputPort(1).Complexity = 'Real'; % 实数
% 覆盖输出端口属性。
block.OutputPort(1).DatatypeID = 0; % double 类型
block.OutputPort(1).Complexity = 'Real'; % 实数
% 注册参数。
block.NumDialogPrms = 3;
block.DialogPrmsTunable = {'Tunable','Nontunable','SimOnlyTunable'};
% 设置连续状态。
block.NumContStates = 1;
% 注册采样时间。
% [0 offset] : 连续采样时间
% [positive_num offset] : 离散采样时间
%
% [-1, 0] : 继承采样时间
% [-2, 0] : 可变采样时间
block.SampleTimes = [0 0];
% -----------------------------------------------------------------
% 选项
% -----------------------------------------------------------------
% 指定加速器模式是使用 TLC 还是回调 MATLAB 文件
block.SetAccelRunOnTLC(false);
% 指定模块的工作点合规性。模块工作点用于包含它的模型的工作点保存/恢复。
% 允许的值为:
% 'Default' : 模块的工作点与内置模块相同
% 'UseEmpty': 模块工作点中没有数据需要保存/恢复
% 'Custom' : 具有自定义的工作点保存/恢复方法
% (请参见下面的 GetOperatingPoint/SetOperatingPoint)
% 'Disallow': 在保存或恢复模块工作点时报错。
block.OperatingPointCompliance = 'Default';
% -----------------------------------------------------------------
% MATLAB S-function 使用内部注册表来管理所有模块方法。
% 您应按如下所示注册所有相关方法(可选和必需)。
% 您可以为这些方法选择任何合适的名称,并在同一文件中将它们实现为局部函数。
% -----------------------------------------------------------------
% -----------------------------------------------------------------
% 注册在更新图表/编译期间调用的方法
% -----------------------------------------------------------------
%
% CheckParameters:
% 功能 : 用于验证模块对话框参数。您有责任在 setup 方法
% 的开头显式调用此方法。
% C MEX 对应函数: mdlCheckParameters
%
block.RegBlockMethod('CheckParameters', @CheckPrms);
%
% SetInputPortSamplingMode:
% 功能 : 检查并设置输入和输出端口属性,并指定端口是以
% 基于采样还是基于帧的模式运行。
% C MEX 对应函数: mdlSetInputPortFrameData.
% (需要 DSP System Toolbox 才能将端口设置为基于帧)
%
block.RegBlockMethod('SetInputPortSamplingMode', @SetInpPortFrameData);
%
% SetInputPortDimensions:
% 功能 : 检查并设置输入端口以及可选地设置输出端口的维度。
% C MEX 对应函数: mdlSetInputPortDimensionInfo
%
block.RegBlockMethod('SetInputPortDimensions', @SetInpPortDims);
%
% SetOutputPortDimensions:
% 功能 : 检查并设置输出端口以及可选地设置输入端口的维度。
% C MEX 对应函数: mdlSetOutputPortDimensionInfo
%
block.RegBlockMethod('SetOutputPortDimensions', @SetOutPortDims);
%
% SetInputPortDatatype:
% 功能 : 检查并设置输入端口以及可选地设置输出端口的数据类型。
% C MEX 对应函数: mdlSetInputPortDataType
%
block.RegBlockMethod('SetInputPortDataType', @SetInpPortDataType);
%
% SetOutputPortDatatype:
% 功能 : 检查并设置输出端口以及可选地设置输入端口的数据类型。
% C MEX 对应函数: mdlSetOutputPortDataType
%
block.RegBlockMethod('SetOutputPortDataType', @SetOutPortDataType);
%
% SetInputPortComplexSignal:
% 功能 : 检查并设置输入端口以及可选地设置输出端口的复数属性。
% C MEX 对应函数: mdlSetInputPortComplexSignal
%
block.RegBlockMethod('SetInputPortComplexSignal', @SetInpPortComplexSig);
%
% SetOutputPortComplexSignal:
% 功能 : 检查并设置输出端口以及可选地设置输入端口的复数属性。
% C MEX 对应函数: mdlSetOutputPortComplexSignal
%
block.RegBlockMethod('SetOutputPortComplexSignal', @SetOutPortComplexSig);
%
% PostPropagationSetup:
% 功能 : 设置工作区(DWork)和状态变量。您也可以在此处注册运行时方法。
% C MEX 对应函数: mdlSetWorkWidths
%
block.RegBlockMethod('PostPropagationSetup', @DoPostPropSetup);
% -----------------------------------------------------------------
% 注册在运行时调用的方法
% -----------------------------------------------------------------
%
% ProcessParameters:
% 功能 : 用于更新运行时参数的调用。
% C MEX 对应函数: mdlProcessParameters
%
block.RegBlockMethod('ProcessParameters', @ProcessPrms);
%
% InitializeConditions:
% 功能 : 用于初始化状态和工作区值的调用。
% C MEX 对应函数: mdlInitializeConditions
%
block.RegBlockMethod('InitializeConditions', @InitializeConditions);
%
% Start:
% 功能 : 用于初始化状态和工作区值的调用。
% C MEX 对应函数: mdlStart
%
block.RegBlockMethod('Start', @Start);
%
% Outputs:
% 功能 : 在仿真步长期间生成模块输出的调用。
% C MEX 对应函数: mdlOutputs
%
block.RegBlockMethod('Outputs', @Outputs);
%
% Update:
% 功能 : 在仿真步长期间更新离散状态的调用。
% C MEX 对应函数: mdlUpdate
%
block.RegBlockMethod('Update', @Update);
%
% Derivatives:
% 功能 : 在仿真步长期间更新连续状态导数的调用。
% C MEX 对应函数: mdlDerivatives
%
block.RegBlockMethod('Derivatives', @Derivatives);
%
% Projection:
% 功能 : 在仿真步长期间更新投影的调用。
% C MEX 对应函数: mdlProjections
%
block.RegBlockMethod('Projection', @Projection);
%
% SimStatusChange:
% 功能 : 当仿真进入暂停模式或离开暂停模式时调用。
% C MEX 对应函数: mdlSimStatusChange
%
block.RegBlockMethod('SimStatusChange', @SimStatusChange);
%
% Terminate:
% 功能 : 在仿真结束时调用,用于清理。
% C MEX 对应函数: mdlTerminate
%
block.RegBlockMethod('Terminate', @Terminate);
%
% GetOperatingPoint:
% 功能 : 返回模块的工作点。
% C MEX 对应函数: mdlGetOperatingPoint
%
block.RegBlockMethod('GetOperatingPoint', @GetOperatingPoint);
%
% SetOperatingPoint:
% 功能 : 使用给定的值设置模块的工作点数据。
% C MEX 对应函数: mdlSetOperatingPoint
%
block.RegBlockMethod('SetOperatingPoint', @SetOperatingPoint);
% -----------------------------------------------------------------
% 注册在代码生成期间调用的方法
% -----------------------------------------------------------------
%
% WriteRTW:
% 功能 : 向 model.rtw 文件写入特定信息。
% C MEX 对应函数: mdlRTW
%
block.RegBlockMethod('WriteRTW', @WriteRTW);
%endfunction
% -------------------------------------------------------------------
% 下面的局部函数用于说明如何实现上述各种模块方法。
% -------------------------------------------------------------------
function CheckPrms(block)
a = block.DialogPrm(1).Data;
if ~isa(a, 'double')
me = MSLException(block.BlockHandle, message('Simulink:blocks:invalidParameter'));
throw(me);
end
%endfunction
function ProcessPrms(block)
block.AutoUpdateRuntimePrms;
%endfunction
function SetInpPortFrameData(block, idx, fd)
block.InputPort(idx).SamplingMode = fd;
block.OutputPort(1).SamplingMode = fd;
%endfunction
function SetInpPortDims(block, idx, di)
block.InputPort(idx).Dimensions = di;
block.OutputPort(1).Dimensions = di;
%endfunction
function SetOutPortDims(block, idx, di)
block.OutputPort(idx).Dimensions = di;
block.InputPort(1).Dimensions = di;
%endfunction
function SetInpPortDataType(block, idx, dt)
block.InputPort(idx).DataTypeID = dt;
block.OutputPort(1).DataTypeID = dt;
%endfunction
function SetOutPortDataType(block, idx, dt)
block.OutputPort(idx).DataTypeID = dt;
block.InputPort(1).DataTypeID = dt;
%endfunction
function SetInpPortComplexSig(block, idx, c)
block.InputPort(idx).Complexity = c;
block.OutputPort(1).Complexity = c;
%endfunction
function SetOutPortComplexSig(block, idx, c)
block.OutputPort(idx).Complexity = c;
block.InputPort(1).Complexity = c;
%endfunction
function DoPostPropSetup(block)
block.NumDworks = 2;
block.Dwork(1).Name = 'x1';
block.Dwork(1).Dimensions = 1;
block.Dwork(1).DatatypeID = 0; % double 类型
block.Dwork(1).Complexity = 'Real'; % 实数
block.Dwork(1).UsedAsDiscState = true; % 用作离散状态
block.Dwork(2).Name = 'numPause';
block.Dwork(2).Dimensions = 1;
block.Dwork(2).DatatypeID = 7; % uint32 类型
block.Dwork(2).Complexity = 'Real'; % 实数
block.Dwork(2).UsedAsDiscState = true; % 用作离散状态
% 将所有可调参数注册为运行时参数。
block.AutoRegRuntimePrms;
%endfunction
function InitializeConditions(block)
block.ContStates.Data = 1;
%endfunction
function Start(block)
block.Dwork(1).Data = 0;
block.Dwork(2).Data = uint32(1);
%endfunction
function WriteRTW(block)
block.WriteRTWParam('matrix', 'M', [1 2; 3 4]);
block.WriteRTWParam('string', 'Mode', 'Auto');
%endfunction
function Outputs(block)
block.OutputPort(1).Data = block.Dwork(1).Data + block.InputPort(1).Data;
%endfunction
function Update(block)
block.Dwork(1).Data = block.InputPort(1).Data;
%endfunction
function Derivatives(block)
block.Derivatives.Data = 2*block.ContStates.Data;
%endfunction
function Projection(block)
states = block.ContStates.Data;
block.ContStates.Data = states+eps;
%endfunction
function SimStatusChange(block, s)
block.Dwork(2).Data = block.Dwork(2).Data+1;
if s == 0
disp('仿真暂停。');
elseif s == 1
disp('恢复仿真。');
end
%endfunction
function Terminate(block)
disp(['正在终止句柄为 ' num2str(block.BlockHandle) ' 的模块。']);
%endfunction
function operPointData = GetOperatingPoint(block)
% 将 DWork 数据打包作为此模块的整个工作点
operPointData = block.Dwork(1).Data;
%endfunction
function SetOperatingPoint(block, operPointData)
% 此模块的工作点就是 DWork 数据(此方法通常执行 GetOperatingPoint 方法的逆操作)
block.Dwork(1).Data = operPointData;
%endfunction
二、 Level-2 MATLAB S-Function结构
2.1 总体架构:三层结构
┌─────────────────────────────────────────┐
│ 第一层:主函数入口 (msfuntmpl) │ ← 对外接口,仅调用 setup
├─────────────────────────────────────────┤
│ 第二层:核心设置 (setup) │ ← 注册所有端口、参数、方法
├─────────────────────────────────────────┤
│ 第三层:功能实现 (所有局部函数) │ ← 具体执行仿真逻辑
│ - CheckPrms, Outputs, Update, ... │
└─────────────────────────────────────────┘
2.2 第一层:主函数
matlab
function msfuntmpl(block)
%MSFUNTMPL A Template for a MATLAB S-Function
% The MATLAB S-function is written as a MATLAB function with the
% same name as the S-function. Replace 'msfuntmpl' with the name
% of your S-function.
% Copyright 2003-2018 The MathWorks, Inc.
%
% The setup method is used to setup the basic attributes of the
% S-function such as ports, parameters, etc. Do not add any other
% calls to the main body of the function.
%
setup(block);
%endfunction
结构要点:
| 要素 | 说明 |
|---|---|
| 函数名 | 必须与 S-Function 模块中填写的名字完全一致 |
| 唯一参数 | block------Simulink 传入的模块句柄 |
| 唯一操作 | 调用 setup(block)。不要在这里添加其他代码 |
%endfunction |
MATLAB 的显式函数结束标记(可选,但模板中常用) |
设计思想: 主函数只做"路由",把所有初始化工作委托给 setup 子函数,保持入口干净。
2.3 第二层:setup 函数
setup 函数是最核心 的部分,负责"注册"该模块的一切特性。它按照属性分组,循序渐进地配置:
1. 端口设置
matlab
block.NumInputPorts = 1;
block.NumOutputPorts = 1;
block.SetPreCompInpPortInfoToDynamic; % 设为动态继承
block.InputPort(1).DatatypeID = 0; % double 类型
定义模块有几个输入/输出,以及它们的数据类型。
2. 参数设置
通俗理解: 就是你在 Simulink 模块双击打开设置对话框 时,里面那些你可以填写的参数框。
matlab
% 注册参数数量:告诉 Simulink 对话框里要有 3 个输入框
block.NumDialogPrms = 3;
% 设置参数的可调性(在仿真过程中能否修改)
block.DialogPrmsTunable = {'Tunable', 'Nontunable', 'SimOnlyTunable'};
定义对话框中有 3 个参数,并指定它们的可调性。
三种可调性含义
| 类型 | 含义 |
|---|---|
| 'Tunable' | 仿真运行过程中可以随时修改(比如在线调参) |
| 'Nontunable' | 仿真开始后不能修改,必须在启动前设好 |
| 'SimOnlyTunable' | 只能在仿真模式下调,代码生成时固定 |
3. 状态与采样时间
matlab
block.NumContStates = 1; % 1 个连续状态
block.SampleTimes = [0 0]; % 连续采样时间
0 0表示连续系统;离散系统会用周期, 偏移。
4. 选项配置
通俗理解: 选项不是给用户在对话框里填的,而是告诉 Simulink 引擎"我这个模块有什么特殊要求或行为模式"。
matlab
block.SetAccelRunOnTLC(false); % 加速器模式是否用 TLC
block.OperatingPointCompliance = 'Default';
控制代码生成和运行时的行为。
5. 方法注册------ 最关键的部分
matlab
block.RegBlockMethod('CheckParameters', @CheckPrms);
block.RegBlockMethod('SetInputPortDimensions', @SetInpPortDims);
block.RegBlockMethod('Outputs', @Outputs);
block.RegBlockMethod('Update', @Update);
% ... 等等
这里注册了 三大类方法:
| 阶段 | 注册的方法 | 作用 |
|---|---|---|
| 编译/检查阶段 | CheckParameters、SetInputPortDimensions、SetInputPortDataType 等 |
验证参数、传播维度/类型 |
| 运行阶段 | InitializeConditions、Outputs、Update、Derivatives、Terminate |
执行仿真逻辑 |
| 代码生成阶段 | WriteRTW |
生成 .rtw 文件供代码生成 |
2.3 局部函数实现
这些函数是真正干活的,每个函数对应一个注册的方法。它们按功能分组:
A. 参数与配置检查
matlab
function CheckPrms(block)
a = block.DialogPrm(1).Data;
if ~isa(a, 'double')
throw(MSLException(...));
end
在编译时验证用户输入的参数是否合法。
B. 端口属性传播
matlab
function SetInpPortDims(block, idx, di)
block.InputPort(idx).Dimensions = di;
block.OutputPort(1).Dimensions = di;
当输入维度改变时,自动将输出维度设为相同(维度继承)。
C. 工作区(DWork)设置
matlab
function DoPostPropSetup(block)
block.NumDworks = 2;
block.Dwork(1).Name = 'x1';
block.Dwork(1).UsedAsDiscState = true;
定义内部工作向量(可作离散状态、缓存等)。
D. 仿真运行核心逻辑
matlab
function Outputs(block)
block.OutputPort(1).Data = block.Dwork(1).Data + block.InputPort(1).Data;
最关键:每个仿真步长调用,计算输出。
matlab
function Update(block)
block.Dwork(1).Data = block.InputPort(1).Data;
离散状态更新(下一个时刻的状态)。
matlab
function Derivatives(block)
block.Derivatives.Data = 2*block.ContStates.Data;
连续状态导数(用于积分器)。
E. 生命周期钩子
matlab
function Start(block) % 仿真开始时初始化
function SimStatusChange(block, s) % 暂停/恢复时触发
function Terminate(block) % 仿真结束时清理
function GetOperatingPoint(block) % 保存操作点
function SetOperatingPoint(block, operPointData) % 恢复操作点
2.4 结构总结:时序与职责
这个模板实际上描述了一个 S-Function 的完整生命周期:
仿真开始
│
▼
[编译阶段]
├── CheckParameters → 验证参数
├── SetInputPortDims → 确定维度
├── SetInputPortDataType→ 确定类型
└── PostPropagationSetup→ 分配 DWork 内存
│
▼
[初始化阶段]
├── Start → 执行启动操作
└── InitializeConditions→ 设置初始状态
│
▼
[运行循环] (每个时间步)
├── Outputs → 计算输出
├── Update → 更新离散状态 (可选)
└── Derivatives → 计算连续状态导数 (可选)
│
▼
[结束阶段]
└── Terminate → 清理资源
2.5 设计模式总结
| 设计原则 | 在该模板中的体现 |
|---|---|
| 注册表模式 | 通过 RegBlockMethod 把函数名映射到 Simulink 引擎 |
| 回调机制 | 引擎在特定时刻(如输出计算)回调你注册的函数 |
| 延迟绑定 | 编译时动态确定端口维度/类型,而非硬编码 |
| 模块化 | 每个功能独立为一个局部函数,职责单一 |
| 模板方法模式 | 主流程由 Simulink 引擎控制,用户只需填充具体实现 |