S-Function的使用
前言
为了兼顾代码和模型的优势,在Simulink的模型中嵌入m文件来对一个系统进行仿真,主要的数学模型放在m文件中,可以将数学语言直接转换成代码,不需要为一堆模块进行“连连看”,更适合状态空间的复现。
先导知识
实现流程
获取模板(Level1形式)
-
2022版,之前的版本
edit sfuntmpl
-
2022版,之后的版本
edit sfundsc2
-
或者直接网上找一个现成的模板再改
修改模板
-
修改模板函数名(例如改成sfun1),将文件另存到当前工作空间,同时修改文件名(直接重命名就行),使文件名和函数名一致
function [sys,x0,str,ts,simStateCompliance] = sfun1(t,x,u,flag)
-
修改初始化函数,以下是常用的一些含义
function [sys,x0,str,ts,simStateCompliance]=mdlInitializeSizes %初始化回调子函数 %提供状态、输入、输出、采样时间数目和初始状态的值 %初始化阶段,标志变量flag首先被置为0,S-function首次被调用时 %该子函数首先被调用,且为S-function模块提供下面信息 %该子函数必须存在 sizes = simsizes; %生成sizes数据结构,信息被包含在其中 sizes.NumContStates = 3; %连续状态数,所有状态字母的种类,例如x,y,z共3种 sizes.NumDiscStates = 0; %离散状态数,默认为0,注意判断有没有 sizes.NumOutputs = 3; %输出个数,3个输出则为3,没有输出则默认为0 sizes.NumInputs = 0; %输入个数,1个输如则为1,没有输如则默认为0 %当out=f(u)时,存在直馈通道;而当out=f(u,u',...)时,不存在直馈通道 sizes.DirFeedthrough = 0; %是否存在直馈通道,1表示存在,0表示不存在 sizes.NumSampleTimes = 1; %采样时间个数,至少是一个 sys = simsizes(sizes); %返回size数据结构所包含的信息 x0 = [10.01;20;30]; %初始化内部变量状态,|*|注意:长度必须与NumContStates中一致|*| str = []; %保留变量矩阵,一般置空 ts = [0 0]; %设置采样时间,[a b]表示从第b秒起,每间隔a秒采集一次 simStateCompliance = 'UnknownSimState';
-
添加求导环节(如果需要的话)
3.1. 先在switch flag中添加求导环节
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
3.2. 添加求导函数
function sys=mdlDerivatives(t,x,u) %计算导数回调子函数 %给定t,x,u计算连续状态的导数,可以在此给出系统的连续状态方程 %该子函数可以不存在 %sys表示状态导数,即dx; % sys = u; %sys中所有变量的导数等于输入u % sys = []; %不进行导数运算 % 以洛伦兹系统为例 rho = 28; beta = 8/3; sys(1) = sigma*(x(2) - x(1)); %dx=σ(y-x) sys(2) = rho*x(1) - x(2) - x(1)*x(3); %dy=ρx-y-xz sys(3) = x(1)*x(2) - beta*x(3); %dz=xy-βz
-
修改输出环节
function sys=mdlOutputs(t,x,u) %计算输出回调函数(时间,中间变量,输入) %给定t,x,u计算输出,可以在此描述系统的输出方程 %该子函数必须存在,支持单独修改/整合修改 % sys(1) = x(1); % sys(2) = x(2); % sys(3) = x(3); sys = x; %sys表示输出,即y;x为系统变量
连接Simulink
-
打开库浏览器,添加S-Function模块
-
连接m函数,将函数名字改成上文已经修改的函数名
- 点击运行
进阶使用
导出数据
可以将Simulink仿真生成的数据导出到工作区,以便与其他指令交互
-
找到To Workspace这个模块
-
连接到需要输出的端口
-
双击选择To Workspace的导出形式
-
重新运行,导出数据到工作区
-
双击打开可以看到导出数据
- “sc2out”为导出的具体数据
- “tout”则为时间序列
-
此时就可以在命令行中使用导出的数据进行操作;例如,调取第一列数据为
out.sc2out(:,1)
在对话框中设置参数
可以实现在不修改代码的情况下,直接调整参数,类似于自带的模块
-
修改m文件,加入待选参数(例如gain这个参数)
-
函数名称处
-
switch调用处
-
函数原型处
-
-
在Simulink处写入具体参数(例如gain这个参数)
-
点击运行
注意:参数是为泛指,即可以是一个参数,也可以是一组参数;若sizes.NumOutputs有多个,可以使用Demux模块拆分信号(直接输出是叠加的)