Matlab使用S函数

什么是S函数?

S-函数是系统函数(System Function)的简称,在 Simulink 中用非图形化的方式来描述一个模块。一个完整的S-函数结构体系包含了描述一个动态系统所需要的全部能力。使用S-函数用户可以向 Simulink 模型中添加自己的模块,可以自由选择使用 MATLAB、C、C++ 等语言来创建自己的模块。Matlab 语言编写的S-函数可以充分利用 MATLAB 所提供的丰富资源,方便地调用各种工具箱函数和图形函数;使用 C 语言编写的S-函数可以实现对操作系统的访问,如实现与其他进程的通信和同步等。

Simulink 已经提供了大量的内置的系统模块,并且允许用户自定义模块,那么为何还要使用S-函数呢?诚然,对于大多数动态系统仿真分析语言,使用 Simulink 提供的模块即可实现,而无需使用S-函数。

但是,当需要开发一个新的通用的模块作为一个独立的功能单元时,使用S-函数实现则是一种相当简便的方法。另外,由于S-函数可以使用多种语言编写,因此可以将已有的代码结合进来,而不需要在 Simulink 中重新实现算法,从而在某种程度上实现了代码移植。此外,在S-函数中使用文本方式输入公式、方程,非常适合复杂动态系统的数学描述,并且在仿真过程中可以对仿真进行更精确的控制。如果恰当地使用S函数,理论上,可以在 Simulink 下对任意复杂的系统进行仿真。

基础知识

Simulink仿真过程

Simulnk 仿真分为两步:初始化、仿真循环。仿真是由求解器控制的,求解器主要作用是:计算模块输出、更新模块离散状态、计算连续状态。求解器传递给系统的信息包括:时间、输入和当前状态。系统的作用:计算模块的输出、更新状态、计算状态导数,然后将这些信息传递给求解器。求解器和系统之间的信息传递是通过不同标志来控制的。

Simulink 仿真过程

Simulink 仿真过程

S函数工作原理

Matlab 为了用户使用方便,有一个S函数的模板 sfuntmpl.m,一般来说,我们仅需要在 sfuntmpl.m 的基础上进行修改即可。在主窗口输入 edit sfuntmpl 即可出现模板函数的内容,可以详细地观察其帮助说明以便更好地了解S函数的工作原理。

S函数的定义形式为 function[sys,x0,str,ts]=sfunc(t,x,u,flag,p1,…Pn),其中的 sfunc 为自己定义的函数名称,以上参数中,t、x、u 分别对应时间、状态、输入信号,flag 为标志位,其取值不同,S函数执行的任务和返回的数据也是不同的,Pn 为额外的参数,sys 为一个通用的返回参数值,其数值根据 flag 的不同而不同,x0 为状态初始数值,str 在目前为止的 matlab 版本中并没有什么作用,一般 str=[] 即可,ts 为一个两列的矩阵,包含采样时间(整个模型的基础采样时间,各个子系统或模块的采样时间,必须以这个步长为整数倍)和偏移量两个参数,如果设置为 [0 0],那么每个连续的采样时间步都运行,[-1 0] 则表示按照所连接的模块的采样速率进行,[0.25 0.1] 表示仿真开始的 0.1s 后每 0.25s 运行一次,采样时间点为 TimeHit = n*period + offset。

S函数的使用过程中有1个概念值得注意

Direct Feedthrough,系统的输出是否直接和输入相关联,即输入是否出现在输出端的标志,若是为 1,否则为 0,一般可以根据在 flag=3 的时候,mdlOutputs 函数是否调用输入 u 来判断是否直接馈通。

S函数中目前支持的 flag 选择有 0、1、2、3、4、9 几个数值,下面说一下在不同的 flag 情况下S函数的执行情况。

  1. flag=0。进行系统的初始化过程,调用 mdlInitializeSizes 函数,对参数进行初始化设置,比如离散状态个数、连续状态个数、模块输入和输出的路数、模块的采样周期个数、状态变量初始数值等。
  2. flag=1。进行连续状态变量的更新,调用 mdlDerivatives 函数。
  3. flag=2。进行离散状态变量的更新,调用 mdlUpdate 函数。
  4. flag=3。求取系统的输出信号,调用 mdlOutputs 函数。
  5. flag=4。调用 mdlGetTimeOfNextVarHit 函数,计算下一仿真时刻,由 sys 返回。
  6. flag=9。终止仿真过程,调用 mdlTerminate 函数。

在实际仿真过程中,Simulink 会自动将 flag 设置为 0,进行初始化过程,然后将 flag 的数值设置为 3,计算模块的输出,一个仿真周期后,Simulink 将 flag 的数值先后设置为 1 和 2,更新系统的连续和离散状态,再将其设置为 3,计算模块的输出,如此循环直至仿真结束条件满足。

S函数执行顺序

S函数执行顺序
在S函数的编写过程中,首先需要搞清楚模块中有多少个连续和离散状态,离散模块的采样周期是如何的,同时需要了解模块的连续和离散的状态方程分别是什么,输出如何表示。下面以实例说明S函数的具体应用。

sfuntmpl.m模板代码内容详细解析

function [sys,x0,str,ts,simStateCompliance] = sfuntmpl(t,x,u,flag)
% 主函数
% 主函数包含四个输出:
%                 sys数组包含某个子函数返回的值
%                 x0为所有状态的初始化向量
%                 str是保留参数,总是一个空矩阵
%                 Ts返回系统采样时间
% 函数的四个输入分别为采样时间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
% 初始化回调子函数
% 提供状态、输入、输出、采样时间数目和初始状态的值
% 初始化阶段,标志变量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 = [];

S函数实例

使用 M 文件编写S函数形式有两种,Level 1 和 Level 2,二者的包装模块是不同的。

类型优点缺点
Level 1运行速度快,能处理矩阵数据只能处理点数据,不能处理复数以及基于帧的数据
Level 2能够处理的数据类型多,包括矩阵、复数以及基于帧的数据运行速度慢

Level 1 M 文件S函数----这种方式提供了一个简单的 M 文件接口,可以与少部分的S函数 API 交互。Matlab 对于这种方式的支持更多的是为了保持与以前版本的兼容,现在推荐采用的是 Level 2 M 文件S函数。

下面是几个 Level-1 M-file S-function 的例子

连续有限输出的积分器

% 实现一个连续有限积分器,其中输出受下限和上限限制,并包括初始条件。
function [sys,x0,str,ts,simStateCompliance]=limintm(t,x,u,flag,lb,ub,xi)
switch flag
  case 0         
    [sys,x0,str,ts,simStateCompliance] = mdlInitializeSizes(lb,ub,xi);
  case 1
    sys = mdlDerivatives(t,x,u,lb,ub);
  case {2,9}
    sys = []; % do nothing
  case 3
    sys = mdlOutputs(t,x,u); 
  otherwise
    DAStudio.error('Simulink:blocks:unhandledFlag', num2str(flag));
end

function [sys,x0,str,ts,simStateCompliance] = mdlInitializeSizes(lb,ub,xi)

sizes = simsizes;
sizes.NumContStates  = 1;
sizes.NumDiscStates  = 0;
sizes.NumOutputs     = 1;
sizes.NumInputs      = 1;
sizes.DirFeedthrough = 0;
sizes.NumSampleTimes = 1;

sys = simsizes(sizes);
str = [];
x0  = xi;
ts  = [0 0];   

simStateCompliance = 'DefaultSimState';

function sys = mdlDerivatives(t,x,u,lb,ub)

if (x <= lb & u < 0)  | (x>= ub & u>0 )
  sys = 0;
else
  sys = u;
end

function sys = mdlOutputs(t,x,u)
sys = x;

一连续系统

蹦极跳是一种挑战身体极限的运动,蹦极者系着一根弹力绳从高处的桥梁或山崖向下跳。如果蹦极者系在一个弹性系数为 k k k 的弹力绳索上。定义绳索下端的初始位置为 0,则蹦极者受到的弹性力是

弹性力
整个蹦极跳系统的数学模型为:

数学模型
其中 m m m 为物体的质量, g g g 为重力加速度取 10, x x x 为物体的位置,第二项为物体受到的弹性力,第三项和第四项表示空气的阻力。桥梁距离地面的高度为 50m,绳子的原长为 30m,弹性系数 k k k 为 50, a 1 = a 2 = 1 a_1 = a_2 = 1 a1=a2=1。试判断质量为 70kg 的人是否能够安全地享受此游戏带来的乐趣。下图为整个系统的示意图。

系统示意图
解:为了便于后面的仿真计算,可以将物理模型写成如下状态方程形式:

状态空间方程

function [sys,x0,str,ts,simStateCompliance] = jumping(t,x,u,flag,len,m,height,k)
switch flag,
  case 0,
    [sys,x0,str,ts,simStateCompliance]=mdlInitializeSizes(len,m,height,k);
  case 1,
    sys=mdlDerivatives(t,x,u,len,m,height,k);
  case 2,
    sys=mdlUpdate(t,x,u);
  case 3,
    sys=mdlOutputs(t,x,u,len,m,height,k);
  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(len,m,height,k)
sizes = simsizes;
sizes.NumContStates  = 2;
sizes.NumDiscStates  = 0;
sizes.NumOutputs     = 1;
sizes.NumInputs      = 0;
sizes.DirFeedthrough = 1;
sizes.NumSampleTimes = 1;  
sys = simsizes(sizes);
x0  = [-len;0];
str = [];
ts  = [0 0];
simStateCompliance = 'UnknownSimState';

function sys=mdlDerivatives(t,x,u,len,m,height,k)
if x(1)>0
    b=-k*x(1);
else 
    b=0;
end
sys = [x(2);10+b/m-1/m*x(2)-1/m*abs(x(2))*x(2)];

function sys=mdlUpdate(t,x,u)
sys = [];

function sys=mdlOutputs(t,x,u,len,m,height,k)
sys = [height-len-x(1)];

function sys=mdlGetTimeOfNextVarHit(t,x,u)

sampleTime = 1;    
sys = t + sampleTime;

function sys=mdlTerminate(t,x,u)
sys = [];

s-function 参数的配置:

S函数参数配置
搭建 simulink 框图观察上述系统输出

蹦极输出
综上所述,此蹦极系统并不能让 70kg 的人嗨。

一离散系统

用 S-function 实现下面的离散系统:

离散方程

function [sys,x0,str,ts] = dsfunc(t,x,u,flag)
A=[-1.3839   0.5097
    1.0000         0];

B=[-2.5559         0
         0    4.2382];

C=[      0    2.0761
         0    7.7891];

D=[   -0.8141   -2.9334
       1.2426         0];
switch flag,
  case 0,
    [sys,x0,str,ts] = mdlInitializeSizes(A,B,C,D);
  case 2,                                                
    sys = mdlUpdate(t,x,u,A,B,C,D); 
  case 3,                                                
    sys = mdlOutputs(t,x,u,A,C,D);
  case 9,                                                
    sys = []; % do nothing
  otherwise
    DAStudio.error('Simulink:blocks:unhandledFlag', num2str(flag));
end

function [sys,x0,str,ts] = mdlInitializeSizes(A,B,C,D)
sizes = simsizes;
sizes.NumContStates  = 0;
sizes.NumDiscStates  = size(A,1);
sizes.NumOutputs     = size(D,1);
sizes.NumInputs      = size(D,2);
sizes.DirFeedthrough = 1;
sizes.NumSampleTimes = 1;
sys = simsizes(sizes);
x0  = ones(sizes.NumDiscStates,1);
str = [];
ts  = [1 0]; 

function sys = mdlUpdate(t,x,u,A,B,C,D)
sys = A*x+B*u;

function sys = mdlOutputs(t,x,u,A,C,D)

sys = C*x+D*u;

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/36272.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

rust 自动化测试、迭代器与闭包、智能指针、无畏并发

编写测试可以让我们的代码在后续迭代过程中不出现功能性缺陷问题&#xff1b;理解迭代器、闭包的函数式编程特性&#xff1b;Box<T>智能指针在堆上存储数据&#xff0c;Rc<T>智能指针开启多所有权模式等&#xff1b;理解并发&#xff0c;如何安全的使用线程&#x…

Mac矢量绘图工具 Sketch

Sketch是一款适用于 UI/UX 设计、网页设计、图标制作等领域的矢量绘图软件&#xff0c; 其主要特点如下&#xff1a; 1. 简单易用的界面设计&#xff1a;Sketch 的用户界面简洁明了&#xff0c;使得用户可以轻松上手操作&#xff0c;不需要复杂的学习过程。 2. 强大的矢量绘图功…

静态路由介绍

目录 静态路由配置方法&#xff08;基本配置&#xff09;&#xff1a; 静态路由的拓展配置 负载均衡 1.环回接口——测试 2.手工汇总——子网汇总 3.路由黑洞&#xff08;黑洞路由) 4.缺省路由 5.空接口——NULL 0 6.浮动静态路由 静态路由配置方法&#xff08;基本配置&#x…

基于matlab使用部分或较低分辨率图像快速处理阻塞图像(附源码)

一、前言 此示例展示了如何使用两种策略快速处理阻塞图像&#xff0c;这两种策略可以对高分辨率图像的较小代表性样本进行计算。 处理被阻止的图像可能非常耗时&#xff0c;这使得算法的迭代开发成本过高。有两种常见的方法可以缩短反馈周期&#xff1a;迭代较低分辨率的图像…

分布式服务高可用实现:复制

大家好&#xff0c;我是 方圆。本文的内容大多数来自于《数据密集型应用系统设计》&#xff0c;也夹杂着一些我个人对复制的理解&#xff0c;原文收录在我的 Github: enthusiasm 中&#xff0c;欢迎Star和获取原文。 1. 为什么需要复制 我们可以考虑如下问题&#xff1a; 当数…

安装Nodejs、NPM、Vue脚手架详细教程

一、安装Nodejs 查看自己电脑是否安装nodejs node --version我这里已经下载过了&#xff0c;没有下载过的会提示该命令不存在 可以到官网下载一下 https://nodejs.org/en/download/ 不要安装在中文路径下 二、安装NPM 如果你安装了nodejs–默认会安装NPM. npm --version…

运营规模突破5万台,绿色慧联启动「望岳计划」!

狙击冲锋问鼎&#xff01;7月7日&#xff0c;绿色慧联“望岳计划”在杭州正式启动。远程新能源商用车集团副总裁兼绿色慧联总经理杨东及运营平台各职能部门、区域运营中心负责人共同参加了会议。 今年绿色慧联正面临更加多变的内外部市场环境&#xff0c;电池原材料价格下滑和整…

2023年07月在线IDE流行度最新排名

点击查看最新在线IDE流行度最新排名&#xff08;每月更新&#xff09; 2023年07月在线IDE流行度最新排名 TOP 在线IDE排名是通过分析在线ide名称在谷歌上被搜索的频率而创建的 在线IDE被搜索的次数越多&#xff0c;人们就会认为它越受欢迎。原始数据来自谷歌Trends 如果您相…

IP数据云揭示高风险IP的来源地

在全球网络安全日临近之际&#xff0c;IP数据云揭示高风险IP的来源地。这些高风险IP以其潜在威胁和犯罪活动而闻名&#xff0c;已引起了全球范围内的关注。 根据IP数据云介绍&#xff0c;高风险IP的主要来源地是位于亚洲和东欧的国家其中包括俄罗斯、朝鲜和乌克兰等地。这些地区…

Mybatis-Plus

1.Mybatis-Plus 1.1 简介 MyBatis-Plus 是一个 Mybatis 增强版工具&#xff0c;在 MyBatis 上扩充了其他功能没有改变其基本功能&#xff0c;为了简化开发提交效率而存在。 官网文档地址&#xff1a;   https://mp.baomidou.com/guide/ MyBatis-Plus 特性&#xff1a;  …

ChatGPT 和爬虫有什么区别

目录 ChatGPT的概念和功能 爬虫的概念和功能 ChatGPT和爬虫的区别 ChatGPT的概念和功能 ChatGPT是一个基于自然语言处理和机器学习的智能对话模型&#xff0c;具有以下功能&#xff1a; 1. 问题回答&#xff1a;ChatGPT可以回答用户提出的各种问题。不论是有关常识、历史、科…

springboot 集成log4j日志,需要自定义json格式内容输出方便ES采集

背景 公司需要将服务迁移到K8S环境上&#xff0c;由于目前服务输出的格式不符合ES进行采集的日志格式&#xff0c;所有需要将日志输出的格式进行调整为JSON格式&#xff0c;方便ES采集 遇到的坑 之前是直接配置的输出格式的message为"message": %msg"&#x…

Hadoop下载安装(物理机)

1、下载Hadoop安装包## http://archive.apache.org/dist/hadoop/common 2、解压安装Hadoop 将hadoop-2-7.4.tar.gz包上传到/root/export/software目录 cd /root/export/software mkdir /root/exprot/servers tar -zxvf hadoop-2.7.4.tar.gz -C /root/export/servers/3、配置…

保护用户数据隐私:Web3 技术在电商行业中的应用

电商行业一直是全球经济发展的重要推动力。然而&#xff0c;随着电商行业的不断发展&#xff0c;中心化的支付、物流和数据存储方式逐渐暴露出安全隐患和隐私问题。这时&#xff0c;Web3 技术以其去中心化、安全性和透明性等特点&#xff0c;为电商行业带来了新的解决方案和可能…

SQL-每日一题【584.寻找用户推荐人】

题目 给定表 customer &#xff0c;里面保存了所有客户信息和他们的推荐人。 写一个查询语句&#xff0c;返回一个客户列表&#xff0c;列表中客户的推荐人的编号都 不是 2。 对于上面的示例数据&#xff0c;结果为&#xff1a; 解题思路 1.题目要求查询列表中客户的推荐人的…

【Ubuntu学习MySQL——报错 ERROR 2002 (HY000)】

问题&#xff1a; 报错含义&#xff1a; 根据上面的报错&#xff0c;意思是说mysql想使用/var/run/mysqld/mysqld.scok文件&#xff0c;但是无法连接&#xff0c;接下来我们来看看这个文件是否存在 1.查看所有的sock文件 sudo find / -type s 根据上述命令所得出的结果可以知…

线程 线程池

线程和进程的区别? 进程是正在运行程序的实例&#xff0c;进程中包含了线程&#xff0c;每个线程执行不同的任务 不同的进程使用不同的内存空间&#xff0c;在当前进程下的所有线程可以共享内存空间 线程更轻量&#xff0c;线程上下文切换成本一般上要比进程上下文切换低 创…

MySQL - 第11节 - MySQL事务管理

目录 1.事务的概念 2.事务的版本支持 3.事务的提交方式 3.1.查看事务的提交方式 3.2.设置事务的提交方式 4.事务的相关演示 4.1.演示一&#xff1a;证明事务的开始与回滚 4.2.演示二&#xff1a;原子性 4.3.演示三&#xff1a;持久性 4.4.演示四&#xff1a;begin会自…

gitlab【安装部署、备份与恢复】

【1】安装依赖 [rootgit ~]# yum -y install install curl opessh-server postfix wget【2】安装软件包 [rootgit ~]# yum -y localinstall gitlab-ce-11.2.3-ce.0.el7.x86_64.rpm 【3】修改配置 [rootgit ~]# grep "^[a-Z]" /etc/gitlab/gitlab.rb external_ur…

❤️创意网页:生日快乐!穿越奇妙时光的温暖庆祝(HTML+CSS+JS)简单好用

✨博主&#xff1a;命运之光 &#x1f338;专栏&#xff1a;Python星辰秘典 &#x1f433;专栏&#xff1a;web开发&#xff08;简单好用又好看&#xff09; ❤️专栏&#xff1a;Java经典程序设计 ☀️博主的其他文章&#xff1a;点击进入博主的主页 前言&#xff1a;欢迎踏入…