Level-2 MATLAB S-Function解析

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);
% ... 等等

这里注册了 三大类方法

阶段 注册的方法 作用
编译/检查阶段 CheckParametersSetInputPortDimensionsSetInputPortDataType 验证参数、传播维度/类型
运行阶段 InitializeConditionsOutputsUpdateDerivativesTerminate 执行仿真逻辑
代码生成阶段 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 引擎控制,用户只需填充具体实现
相关推荐
2zcode3 小时前
基于MATLAB图像处理的金属表面缺陷检测与工业量测系统设计与实现
图像处理·数码相机·matlab
2zcode5 小时前
基于MATLAB图像处理的饮料瓶识别与价格显示系统设计与实现
开发语言·图像处理·matlab
简简单单做算法12 小时前
基于圆投影和伪Zernike的图像亚像素匹配算法matlab仿真
matlab·圆投影·伪zernike·亚像素匹配
2zcode1 天前
免费开源项目文档:基于MATLAB图像处理的药片检测与计数系统设计与实现
开发语言·图像处理·matlab
Evand J1 天前
【论文复现】MATLAB例程,存在测距误差的WSN无锚点分布式自定位,《WSN中存在测距误差的无锚点分布式自定位方法》
开发语言·分布式·matlab·定位·导航·wsn
Evand J1 天前
【MATLAB例程】一维非线性状态滤波对比:经典EKF、MCC-EKF、MVC-EKF。在含异常测量的场景下,对比三种滤波方法的估计曲线和误差统计。
matlab·mvc·ekf·滤波·mcc
2zcode1 天前
基于MATLAB图像处理的苹果质量智能分级系统设计与实现
图像处理·人工智能·matlab
曲折前进的小白2 天前
MATLAB2026a添加新的工具箱
matlab
m0_547486662 天前
《模式识别:使用MATLAB分析与实现》全套PPT课件
开发语言·matlab·模式识别