S-Function是系统函数(System Function)的简称,可以十分方便地用来描述各种动态系统,尤其是复杂的动态系统,属于Simulink动态系统的核心。我们常用的Simulink工具箱都是通过S-Function实现的,如果想开发一个新的模块或工具箱,S-Function可能是最好的选择。
今天,将分两部分内容来介绍S-Function。
1)S-Function简介:简要介绍S-Function的关键信息,理解S-Function的工作过程。
2)电机模型的S-Function实现:以直流电机这一物理对象作为代表,通过S-Function实现电机的动态过程设计。
之前写过一篇文章《Simulink中4种电机建模方式》,有朋友留言比较完美但缺少S-Function,今天借着这个机会一并补上。
1、S-Function简介
学习S-Function的最佳方式是先熟悉Matlab自带的模板sfuntmpl.m,一般在以下路径:C:Program FilesMATLABoolboxsimulinkblocks。
一共40多行代码,主要包括1个主函数和6个子函数,模板代码如下:
function [sys,x0,str,ts,simStateCompliance] = sfuntmpl(t,x,u,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));endfunction [sys,x0,str,ts,simStateCompliance]=mdlInitializeSizessizes = simsizes;sizes.NumContStates = 0;sizes.NumDiscStates = 0;sizes.NumOutputs = 0;sizes.NumInputs = 0;sizes.DirFeedthrough = 1;sizes.NumSampleTimes = 1; sys = simsizes(sizes);x0 = [];str = [];ts = [0 0];simStateCompliance = 'UnknownSimState';function sys=mdlDerivatives(t,x,u)sys = [];function sys= mdlUpdate (t,x,u)sys = [];function sys=mdlOutputs(t,x,u)sys = [];function sys=mdlGetTimeOfNextVarHit(t,x,u)sampleTime = 1; sys = t + sampleTime;function sys=mdlTerminate(t,x,u)sys = [];
主函数:通过flag来选择执行对应的子函数。
mdlInitializeSizes:定义系统的初始条件、采样时间等。
mdlDerivatives:计算连续状态的微分,即dx/dt。
mdlUpdate:计算离散状态x(K+1)。
mdlOutputs:计算输出y。
mdlGetTimeOfNextVarHit:计算离散状态的下一次采样时间。
mdlTerminate:结束函数。
需要注意的是,对于特定的系统可能仅需要调度部分子函数即可完成系统的设计。例如,对于仅存在连续状态的系统,只需要调度mdlInitializeSizes、mdlDerivatives、mdlOutputs、mdlTerminate等4个子函数。这些都是S-Function通过flag去自动实现的。
2、电机模型的S-Function实现
在介绍以前,先回顾一下前面介绍的状态空间搭建电机模型的方法。
选取电流I、转速w作为状态变量,转速w作为输出,直流电机的状态方程和输出方程可表达为:
式中红色部分分别对应系统矩阵A、b、C。使用State-Space模块,完成以上的状态方程搭建,模型如下图。
使用S-Function搭建电机模型时,会借用到上面的参数A、b、C。具体搭建步骤如下:
1)把模板sfuntmpl.m改为motor.m,并新建一个空的mdl文件,也可以命名为motor.mdl。
两个文件放在一起并置于当前目录下,不然m文件后面无法被mdl文件引用。
2)在工具箱中找到S-Function模块,并拖入模型中。
双击打开,将S-Function name设置为motor,S-Function parameter设置为A、b、C。
3)点击Edit,即可打开motor.m文件,进行电机模型设计,修改部分代码,如下面注释。
function [sys,x0,str,ts,simStateCompliance] = sfuntmpl(t,x,u,flag,A,b,C) %%增加参变量switch flag, case 0, [sys,x0,str,ts,simStateCompliance]=mdlInitializeSizes; case 1, sys=mdlDerivatives(t,x,u,A,b); %%增加参变量 case 2, sys=mdlUpdate(t,x,u); case 3, sys=mdlOutputs(t,x,u,C); %%增加参变量 case 4, sys=mdlGetTimeOfNextVarHit(t,x,u); case 9, sys=mdlTerminate(t,x,u); otherwise DAStudio.error('Simulink:blocks:unhandledFlag', num2str(flag));endfunction [sys,x0,str,ts,simStateCompliance]=mdlInitializeSizessizes = simsizes;sizes.NumContStates = 2; %%2个状态变量sizes.NumDiscStates = 0;sizes.NumOutputs = 1; %%单输入sizes.NumInputs = 1; %%单输出sizes.DirFeedthrough = 1;sizes.NumSampleTimes = 1; sys = simsizes(sizes);x0 = [0 0]; %%初始状态为0str = [];ts = [0 0];simStateCompliance = 'UnknownSimState';function sys=mdlDerivatives(t,x,u,A,b) %%增加参变量sys = A*x + b*u; %%计算状态变量的导数function sys=mdlUpdate(t,x,u)sys = [];function sys=mdlOutputs(t,x,u,C) %%增加参变量sys = C*x; %%计算输出function sys=mdlGetTimeOfNextVarHit(t,x,u)sampleTime = 1; sys = t + sampleTime;function sys=mdlTerminate(t,x,u)sys = [];
4)在mdl模型中添加对应的输入,并与状态空间的建模方式对比,如下图。
仿真结果如下图所示,可以看出,两种方法的电机转速曲线完全一致,S-Function的电机建模正确。
以上,以电机模型为例,介绍了利用S-Function的方式来描述系统动态过程的方法。