S函数是simulink动态系统的核心,可以采用m代码,C,C++等语言编写S函数,由一种特定的语法构成,用来描述并实现连续系统,离散系统以及复合系统等动态系统。S函数可以接收来自simulink求解器的相关信息,并对求解器发出的命令做出适当的响应
基础知识
simulink
simulink是MATLAB中的可视化仿真工具,基于MATLAB采用框图方式实现动态系统建模、仿真和分析的过程。每个simulink模块都有三个基本元素:输入向量,状态向量和输出向量。分别用u,x,y表示。
其中状态向量最为重要,可以分为连续状态,离散状态或两者混合状态,实际运用中多用离散状态。
simulink的仿真过程包含两个主要阶段:初始化和运行阶段,初始化主要是设置一些基本参数,如系统输入输出个数,状态初值,采样时间等;运行阶段主要是计算输出,更新离散状态,计算连续状态等;
对系统仿真控制是通过系统模型与求解器之间建立对话的方式进行,simulink将系统模型、模块参数和系统方程传递给simulink求解器,求解器将计算出的系统状态与仿真时间通过simulink传递给系统模型本身,通过这样的交互作用方式完成动态系统仿真。
S函数
过零
动态系统仿真过程中,过零是指系统模型中的信号或系统模型特征的某种改变,包括:1)信号在上一个仿真时间步长之内改变了符号。2)系统模块在上个仿真时间步长改变了模式。对于离散模块及其产生的离散信号不需要进行过零检测
直接馈通(direct feedthrough)
直接馈通:表示系统的输出或可变采样时间是否受输入控制
在编写S-函数时,初始化函数中需要对sizes.DirFeedthrough 进行设置,如果输出函数mdlOutputs或者对于变采样时间的(mdlGetTimeOfNextVarHit)是输入u的函数,则模块具有直接馈通的特性sizes.DirFeedthrough=1;否则为0。
S-Function建立
1.通过在simulink中双击空白处输入s function,回车确认,添加s函数,打开空白文件
2.通过library Browser打开,找到s-function examples,打开模板文件,更改函数名字与文件名字一致,另存为xiuMS
S函数模板文件详解
function [sys,x0,str,ts,simStateCompliance] = sfuntmpl(t,x,u,flag)
%主函数
%主函数包含四个输出:
% sys数组包含某个子函数返回的值(根据flag不同而不同)
% x0为所有状态的初始化向量
% str是保留参数,总是一个空矩阵(一般置空即可)
% Ts返回系统采样时间(是一个1x2的向量,ts(1)是采样周期,ts(2)是偏移量
%函数的四个输入分别为采样时间t、状态x、输入u和仿真流程控制标志变量flag(判断当前状态)
%输入参数后面还可以接续一系列的附带参数simStateCompliance
%%
switch flag,
case 0,
[sys,x0,str,ts,simStateCompliance]=mdlInitializeSizes;
% flag=0,表示当前处于初始化状态,此时调用函数mdlInitializeSizes进行初始化,具体见下面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];%设置采样时间,若采样周期设为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 = [];
s函数控制流程图
实例
以S函数完成对输入信号运算: y = 2 u \ y=2 u y=2u
在模板文件中只需将输入输出改为1,在回调函数mdlOutputs中输入状态方程 s y s = 2 ∗ u \ sys=2*u sys=2∗u即可
function [sys,x0,str,ts,simStateCompliance] = xiuMS(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));
end
function [sys,x0,str,ts,simStateCompliance]=mdlInitializeSizes
sizes = simsizes;
sizes.NumContStates = 0;
sizes.NumDiscStates = 0;
sizes.NumOutputs = 1;
sizes.NumInputs = 1;
sizes.DirFeedthrough = 1;
sizes.NumSampleTimes = 1; % at least one sample time is needed
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 = 2*u;
function sys=mdlGetTimeOfNextVarHit(t,x,u)
sampleTime = 1; % Example, set the next hit to be one second later.
sys = t + sampleTime;
function sys=mdlTerminate(t,x,u)
sys = [];
建立如图所示simulink框图,得到仿真结果