matlabsimulink中带参数的S-Function(S函数)的写法
S函数的相关概念与写法,直接在帮助⽂件中搜:【MATLAB S-Functions Create custom blocks defined】、【S-Function Concepts】等
S函数模块可以从下图中拖出来:
图 1
其中S-Function是正宗的S函数模块,旁边还有⼀个S-Function builder是给新⼿⽤的,只要学会了S函数模块,S builder模块⾃然⼀看就懂。
使⽤S函数模块的步骤:①写S函数的.m⽂件, 并把m⽂件所在的⽂件夹加⼊搜索路径,如下图2所⽰。②在simulink中拖出S函数,并填上m⽂件的名字,如果有参数(下⽂会讲到),也把参数名填上,如下图3所⽰。然后就可以执⾏仿真了
图2
图3
下⾯是最关键的部分,如何写S函数:
写S函数的本质就是写⼀堆回调函数,C/C++程序员对回调函数应该很熟悉了,既然是回调函数,那写之前必须要知道形参和返回值的格式,这个格式从哪查?直接在matlab命令⾏执⾏: edit sfuntmpl,就直接打开了官⽅提供的模板,连格式都不⽤查了,直接仿照官⽅模板把函数体改改盖就⾏了,⽅便。
(1)S函数的总函数
把官⽅模板的代码拷到⼀个新⽂件⾥,并命名为⾃定义名称,我取的名字是oneOrderModule.m,然后把函数名也改成和⽂件名相同,我的是这样的:function [sys,x0,str,ts,simStateCompliance] = oneOrderModule(t,x,u,flag, T)
我与官⽅版不同的是,⾃⼰加了⼀个参数T,如果你还想添加更多参数,直接在形参表⾥添加就⾏了。添加的形参的实参值,来⾃于图3的第⼆个输⼊框,这个输⼊框可填常量,也可以填⼯作区变量名。
形参:①当前的仿真时间t,单位为秒,该参数可以⽤来描述变参数系统,例如你想实现【在t>2S时,把系统增益给改掉】这⼀功能,就可以通过判定t的值来实现;②x为状态列向量;③输⼊列向量u;④flag为当前状态机的第⼏步,例如实参送进来的flag=0代表S函数需要初始化,flag=1代表要更新连续状态
返回值:在不同的状态步下(也即flag不同时),返回值的意义是不同的,在模板⽂件的注释中都讲到了:
例如flag=0时,需要返回:输⼊输出状态变量等的⼤⼩SIZES、状态变量的初值X0等。。。
⼜如flag=3时,返回值sys代表输出向量Y,也即状态空间表达式第2式,Y=CX+DU
不同flag下返回值得写法,将在下⾯的各个函数中依次讲解
(2)系统初始化
当我么在函数中检测到flag=0时,意味着simulnk需要我们返回系统初始化的⼀些信息。
实际上,我们可以直接把flag=0时需要执⾏的代码直接写在switch-case中,但是为了使程序更清晰,我们也仿照官⽅模板,在case中调⽤初始化函数mdlInitializeSizes,我们把代码写在初始化函数中。
function [sys,x0,str,ts,simStateCompliance]=mdlInitializeSizes
sizes = simsizes;
sizes.NumContStates  = 1;%连续状态向量的元素数⽬
sizes.NumDiscStates  = 0;%离散状态向量的元素数⽬
sizes.NumOutputs    = 2;%输出向量的元素数⽬
sizes.NumInputs      = 1;%输⼊向量的元素数⽬
sizes.DirFeedthrough = 1;%输⼊是否直接馈通到输出
sizes.NumSampleTimes = 1;  % 采样时间矩阵的⾏数(必须设为>=1),另外列数固定为2,⽆需设置
sys = simsizes(sizes);%把以上赋值好的结构赋给返回值
x0  = [0];%设置状态向量的初值
s parameterstr = [];%保留参数,不⽤管
ts  = [0 0];%采样时间设置,必须为mx2维度,其中m为上⾯sizes.NumSampleTimes的值
simStateCompliance = 'UnknownSimState';
此函数中,按照回调函数的要求,sys的返回要返回⼀些成员的尺⼨⼤⼩,我们可以⼀个个为sys(1)、sys(2)。。等依次赋值,但我们不会这么做,因为官⽅模板为我们提供了⼀个辅助数据结构的实体simsizes,直接把他复制出来把成员值改好,再赋值给返回值sys即可。simsizes的成员有6个,其中有2个需要单独讲⼀下:
①直接馈通标志DirFeedthrough,这个东西实际上就是看看状态空间表达式第2式Y=CX+DU中的D矩阵是否为0矩阵,如果不是,那我们必须把馈通标志设为1。从回调函数来看,只要我们把DirFeedthrough设成了1,那么当flag=3时,系统会把t、u两个参数传进总函数oneOrderModule中,如果DirFeedthrough设成了0,那么当flag=3时,我们在oneOrderModule函数或者mdlOutputs函数中中将⽆法读到t的值(实际读出来总是0),也⽆法读到u的值(实际读出来总是⼀个只含Nan元素的向量)。
②采样时间矩阵的⾏数NumSampleTimes
这个东西有些复杂,从直观上看,它决定了【采样时间矩阵ts】的⾏数,ts矩阵是NumSampleTimes⾏2列的矩阵。ts的每⼀⾏均包含⼀个数据对:[ 采样时间  偏移量 ],这些数据对不是乱填的,可选就这么⼏种形式:
采样时间可以理解为采样周期,真正的采样时刻=n*周期+偏移量。
对于连续系统,采样时间应设为0,matlab也提供宏CONTINUOUS_SAMPLE_TIME,该宏的值=0。
对于固定步长的离散系统,可以直接设置采样间隔和偏移,形如:[ 0.1  0.02 ]
对于变步长的离散系统,可以设置为:[VARIABLE_SAMPLE_TIME,  0.0],这种参数需要同时把simulink求解器solver设置成变步长的。继承前⼀模块的采样点,可以设置为:[INHERITED_SAMPLE_TIME, FIXED_IN_MINOR_STEP_OFFSET或0]。
更多知识点,可以搜索这⼏个宏名来学习。
(3)连续系统更新、离散系统更新
这两个函数分别为mdlDerivatives和mdlUpdate,如果需要⽀持⾃定义的参数,那么直接修改函数的形参表即可,在我的例⼦中,我附加了⼀个T参数,那么我的连续系统更新函数是这样的:
function sys=mdlDerivatives(t,x,u, T)
A = [-1/T];
B = [1/T];
sys = A*x+B*u;
原理是这样的,典型⼀阶系统的微分⽅程:
如果系统中存在离散状态,那么就在mdlUpdate中写出离散状态空间表达式即可,如果没有离散状态,就直接sys返回空矩阵。
(4)输出函数
function sys=mdlOutputs(t,x,u)
C = [1
1];
D = [0
1];
sys = C * x + D * u;
%sys = [x t];
这个也没啥好说的,描述⼀下输出向量即可。不过提醒⼀下,如果使⽤了 u或t 参数,不要忘记把馈通标志置1,否则在本函数中收不到t和u的实参值。
这个函数描述了两个输出: y(1)=x,y(2)=x+u
下⾯看⼀下仿真结果:
和预想的⼀样,没⽑病。

版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系QQ:729038198,我们将在24小时内删除。