(纯小白跟我从零基础到入门)S-function的使用-保姆级教程

0导入

如上图所示,微机电系统属于复杂系统,用线性系统很难表示,转而用非线性方程。在微机电系统控制中,其算法与模型高度复杂,在simulink已有模块中很难满足特定算法,怎么办呢?在simulink中提供一个工具,你可以利用该工具编写你想要的复杂函数,从而实现系统控制。接下来开始揭开这个工具的神秘面纱。

1,基本概念

1.1,定义

S-FunctionSimulink中的一种特殊函数,它允许用户通过编写C、C++或MATLAB代码来定义模型中的动态系统行为。可以描述连续时间系统、离散时间系统或混合系统,并与Simulink中的其他模块进行连接和交互。通过S-Function,用户可以控制算法、信号处理算法等,从而满足特定的建模和仿真需求。

话句话说,S-Function(system function)是当MATLAB所提供的模型不能完全满足用户时,额外提供接口给用户编写程序满足特定需求。

1.2,流程

1.2.1,创建S-Function模块

Simulink中,可以通过两种方式创建S-Function模块使用S-Function Builder工具可以方便地生成S-Function的框架代码,用户只需填写相应的函数部分即可另一种直接编写S-Function代码并将其编译为MEX文件或共享库文件,需要了解S-FunctionAPI函数和数据结构。

1.2.2,配置S-Function模块

创建好S-Function模块后,需要对其进行配置。配置过程包括设置模块参数、指定输入和输出端口、定义采样时间等。在S-Function的初始化函数中,用户需要设置模块的参数和初始状态,并在仿真过程中根据输入信号和时间步长计算输出信号和状态变量的更新值。

1.2.3,连接S-Function模块

配置好S-Function模块后,可以将其连接到Simulink模型中的其他模块。通过连接不同的模块,可以构建复杂的控制系统模型,并进行仿真和分析。在仿真过程中,Simulink会根据模块之间的连接关系和采样时间调度算法,自动计算每个模块的输入和输出,并更新状态变量的值。

1.3,S-Function组成

S-function包括主函数和6个功能子函数,包括:

mdlInitializeSizes(初始化)

mdlDerivatives(连续状态微分)

mdlUpdate(离散状态更新)

mdlOutputs模块输出

mdlGetTimeOfNextVarHit(计算下次采样时刻)、

mdlTerminate(仿真结束)

1.4,计算流程

1.5,主函数代码

1.5.1,函数代码
function [sys,x0,str,ts,simStateCompliance] = sfuntmpl(t,x,u,flag)
switch flag,
  % Initialization %
  case 0,
    [sys,x0,str,ts,simStateCompliance]=mdlInitializeSizes;
  % Derivatives %
  case 1,
    sys=mdlDerivatives(t,x,u);
  % Update %
  case 2,
    sys=mdlUpdate(t,x,u);
  % Outputs %
  case 3,
    sys=mdlOutputs(t,x,u);
  % GetTimeOfNextVarHit %
  case 4,
    sys=mdlGetTimeOfNextVarHit(t,x,u);
% Terminate %
  case 5,
    sys=mdlTerminate(t,x,u);
  % Unexpected flags %
  otherwise
    DAStudio.error('Simulink:blocks:unhandledFlag', num2str(flag));
end
1.5.2,代码解释

输入量

t——当前时间

x——状态向量

u——输入向量

flag——标志位(默认为0

输出量

sys——一个通用的返回参数。返回值取决于flag的值。例如:flag=3sys则包含了S-function的输出

x0——状态初始值(如果系统中没有状态,则向两位空)

str——默认为空,无需设置

ts——采样时间,包含采样时间和偏移量

simStateComplicance——附加变量

不同标志位调用不同函数:

case 0:调用mdlInitializeSizes函数,初始化子函数,必须执行

case1:调用mdlDerivatives函数,连续状态的导数

case2:对离散状态进行更新,更新到x(n+1)

case3:调用mdlOutputs函数,系统输出y

case4:调用mdlGetTimeOfNextVarHit函数,下一个采样时间点

case5调用mdlTerminate函数,函数终止

1.6,初始函数

1.6.1,初始函数代码
function [sys,x0,str,ts,simStateCompliance]=mdlInitializeSizes

sizes = simsizes;

sizes.NumContStates   = 0;
sizes.NumDiscStates   = 0;
sizes.NumOutputs       = 0;
sizes.NumInputs          = 0;
sizes.DirFeedthrough  = 1;
sizes.NumSampleTimes = 1;   % at least one sample time is needed

sys = simsizes(sizes);

% initialize the initial conditions
x0  = [];

% str is always an empty matrix
str = [];

% initialize the array of sample times
ts  = [0 0];
simStateCompliance = 'UnknownSimState';
1.6.2,代码解释

解释:

其中size属性如下

sizes.NumContStates = 0;       %连续状态的数量

sizes.NumDiscStates = 0;       %离散状态的数量

sizes.NumOutputs = 0;           %输出的数量

sizes.NumInputs = 0;             %输入的数量

sizes.DirFeedthrough = 1;      %输出y和输入u是否是直通(直接调用)

sizes.NumSampleTimes = 1;  %采样时间

x0表示初始状态

ts表示采样时刻

【注意】:

ts的第一个数字表示采样时间,第二个数字表示偏移量

[0 0]——表示默认采样时间(默认为0.2秒采样一次)

[-1 0] ——表示根据连接模块的采样频率进行采样

[a b]表示从第b秒起,每间隔a秒采集一次

1.7,其余函数

以上就是S-function函数代码,接下来我们看看实例是怎么操作的。

2,实例跟我操作

2.0,项目要求:

对系统的赋值进行二倍增幅,Y=2U ,Y为输出矩阵,U为输入矩阵。

以MATLABR2023a演示:

第一步,创建S-function函数,通过命令打开MATLAB自带的S-function模板,将模板另存为自己项目需要的m文件,如jioacheng.m,然后在jioacheng.m里面修改代码,修改完成后点击保存。

第二步,在simulink中搭建模型,添加S-function函数模块,对所有模块按一定逻辑进行连接,配置参数。

最后一步,运行模型。

2.1.1,创建S-function代码

通过命令打开MATLAB自带的模板:open sfuntmpl.m

非正常情况的步骤(如能打开模板,请跳过):

 如果打不开自带S-function模板或者S-function模板文件丢失。解决办法如下(也许不是最佳办法,发现其他大神有更好的办法,欢迎留言交流),在MATLAB主页-新建脚本-复制一下模板代码-粘贴-另存为-文件命名-sfuntmpl.m ,之后得到S-function模板函数啦。

第二种方法也可以,不局限,自己方便就好:

之后保存:特别提示:文件命名为:sfuntmpl.m 

打开之后得到MATLAB自带的S-function模板,如图:

其代码示例:

function [sys,x0,str,ts,simStateCompliance] = sfuntmpl(t,x,u,flag)
%主函数
%主函数包含四个输出:
%                 sys数组包含某个子函数返回的值
%                 x0为所有状态的初始化向量
%                 str是保留参数,总是一个空矩阵
%                 Ts返回系统采样时间
%函数的四个输入分别为采样时间t、状态x、输入u和仿真流程控制标志变量flag
%输入参数后面还可以接续一系列的附带参数simStateCompliance
%注意:编写自己的S-function时,应该把函数名sfuntmpl改为S-function中对应的名字
switch flag,
  case 0,
      [sys,x0,str,ts,simStateCompliance]=mdlInitializeSizes;
  case 1,
    sys=mdlDerivatives(t,x,u);
  case 2,
    sys=mdlUpdate(t,x,u);
  case 3,
    sys=mdlOutputs(t,x,u);
  case 4,
    sys=mdlGetTimeOfNextVarHit(t,x,u);
  case 9,
    sys=mdlTerminate(t,x,u);
  otherwise
    DAStudio.error('Simulink:blocks:unhandledFlag', num2str(flag));
end
%主函数结束
%% %下面是各个子函数,即各个回调过程
function [sys,x0,str,ts,simStateCompliance]=mdlInitializeSizes
%初始化回调子函数
%提供状态、输入、输出、采样时间数目和初始状态的值
%初始化阶段,标志变量flag首先被置为0,S-function首次被调用时
%该子函数首先被调用,且为S-function模块提供下面信息
%该子函数必须存在
sizes = simsizes;             %生成sizes数据结构,信息被包含在其中
sizes.NumContStates  = 0;     %连续状态数,缺省为0
sizes.NumDiscStates  = 0;     %离散状态数,缺省为0
sizes.NumOutputs     = 0;     %输出个数,缺省为0
sizes.NumInputs      = 0;     %输入个数,缺省为0
sizes.DirFeedthrough = 1;     %是否存在直馈通道,1表示存在,0表示不存在
sizes.NumSampleTimes = 1;     %采样时间个数,至少是一个
sys = simsizes(sizes);        %返回size数据结构所包含的信息
x0  = [];                     %设置初始状态
str = [];                     %保留变量置空
ts  = [0 0];                  %设置采样时间
simStateCompliance = 'UnknownSimState';
function sys=mdlDerivatives(t,x,u)
%计算导数回调子函数
%给定t,x,u计算连续状态的导数,可以在此给出系统的连续状态方程
%该子函数可以不存在
sys = [];                     %sys表示状态导数,即dx
%% 
function sys=mdlUpdate(t,x,u)
%状态更新回调子函数
%给定t、x、u计算离散状态的更新
%每个仿真步内必然调用该子函数,不论是否有意义
%除了在此描述系统的离散状态方程外,还可以在此添加其他每个仿真步内都必须执%行的代码
sys = [];                     %sys表示下一个离散状态,即x(k+1)
%% 
function sys=mdlOutputs(t,x,u)
%计算输出回调函数
%给定t,x,u计算输出,可以在此描述系统的输出方程
%该子函数必须存在
sys = [];                     %sys表示输出,即y
%% 
function sys=mdlGetTimeOfNextVarHit(t,x,u)
%计算下一个采样时间
%仅在系统是变采样时间系统时调用
sampleTime = 1;               %设置下一次采样时间是在1s以后
sys = t + sampleTime;         %sys表示下一个采样时间点
%% 
function sys=mdlTerminate(t,x,u)
%仿真结束时要调用的回调函数
%在仿真结束时,可以在此完成仿真结束所需的必要工作
sys = [];

将MATLAB自带的S-function模板另存为项目名称,如jioacheng.m,其中“jioacheng”可以随意命名,特别提示,函数名、文件名一致,因为后续在simulink中搭建模型时需要通过函数名来调用函数。

接下来就要修改模板中的参数了:一般主函数除了修改函数名之外,其他默认,不用修改。

按顺序来先根据实际需要修改初始函数

function [sys,x0,str,ts,simStateCompliance]=mdlInitializeSizes
%初始化回调子函数
%提供状态、输入、输出、采样时间数目和初始状态的值
%初始化阶段,标志变量flag首先被置为0,S-function首次被调用时
%该子函数首先被调用,且为S-function模块提供下面信息
%该子函数必须存在
sizes = simsizes;             %生成sizes数据结构,信息被包含在其中
sizes.NumContStates  = 0;     %连续状态数,缺省为0
sizes.NumDiscStates  = 0;     %离散状态数,缺省为0
sizes.NumOutputs     = 1;     %输出个数,1个输出则为1,没有输出则缺省为0
sizes.NumInputs      = 1;     %输入个数,1个输如则为1,没有输如则缺省为0
sizes.DirFeedthrough = 1;     %是否存在直馈通道,1表示存在,0表示不存在
sizes.NumSampleTimes = 1;     %采样时间个数,至少是一个
sys = simsizes(sizes);        %返回size数据结构所包含的信息
x0  = [];                     %设置初始状态
str = [];                     %保留变量矩阵,一般置空
ts  = [0 0];                  %设置采样时间,[a b]表示从第b秒起,每间隔a秒采集一次
simStateCompliance = 'UnknownSimState';

因任务要求是对线性方程幅值放大,连续函数,所以导数函数不修改,离散函数也不修改。默认为空:

function sys=mdlDerivatives(t,x,u)
%计算导数回调子函数
%给定t,x,u计算连续状态的导数,可以在此给出系统的连续状态方程
%该子函数可以不存在
sys = [];                     %sys表示状态导数,即dx
%% 
function sys=mdlUpdate(t,x,u)
%状态更新回调子函数
%给定t、x、u计算离散状态的更新
%每个仿真步内必然调用该子函数,不论是否有意义
%除了在此描述系统的离散状态方程外,还可以在此添加其他每个仿真步内都必须执%行的代码
sys = [];                     %sys表示下一个离散状态,即x(k+1)

函数Y=2*u

function sys=mdlOutputs(t,x,u)
%计算输出回调函数
%给定t,x,u计算输出,可以在此描述系统的输出方程
%该子函数必须存在
sys =2*u;                     %sys表示输出,即y

后面两个函数根据项目要求,可不作修改;

到这里,S-function函数就完成了,记得保存。接下来就开始在simnliuk中搭建系统模型:

2.1.2,simnliuk环境中搭建系统模型

启动simulink

剩下的工作就是按一定逻辑进行连接了:

2.1.3,运行模型,成功!!

入门是不是超级简单,如果你也觉得是的话给一定赞哦,谢谢。要实现更加复杂功能,原理都是一样的,感兴趣的自己去探索吧!

  • 19
    点赞
  • 9
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值