s-function的介绍

news/2024/9/19 8:10:26/

定义:S-函数是 System function 系统函数的简称,是指采用非图形化(即计算机语言,而非Simulink系统模块)的方式描述的功能模块。在 MATLAB 中,用户除了可以使用MATLAB 代码编写 S-函数以外,还可以使用 C、C++、FORTRAN 或 Ada 语言编写 S-函数,只不过用这些语言编写程序时需要用编译器生成动态连接库(DLL)文件,然后在Simulink 中直接调用。

使用s-函数的一般步骤:
一、在系统的 Simulink 仿真框图中添加 S-function 模块,并进行正确的设置;
二、创建 S-函数源文件。创建 S-函数源文件的方法有多种。用户可以按照 S-函数的语法格式自行编写代码,但是这样做很麻烦,且容易出错。Simulink 在 S-function Examples 模型库中为用户提供了针对不同语言的很多 S-函数模板和例子,用户可以根据自己的需要修改相应的模板或例子即可完成 S-函数源文件的编写工作;
三、在系统的 Simulink 仿真框图中按照定义好的功能连接输入输出端口。
这里需要说明的是,S-function 模块中 S-函数名称必须和用户建立的 S-函数源文件的名称完全相同,S-function 模块中的 S-函数参数列表必须按照 S-函数源文件中的参数顺序赋值,且参数之间需要用逗号隔开。另外,用户也可以使用子系统封装技术对 S-函数进行封装,这样做的好处是可以增强系统模型的可读性。

常用的s-function主要有M文件和C MEX文件两种。M 文件 S-函数由于具有易于编写和理解的特点,在仿真计算中得到了广泛的应用。但是它有一些缺点:首先,M 文件 S-函数使得每个仿真步都必须激活 MATLAB 解释器,以致仿真速度变慢;其次,当需要利用 RTW 从 Simulink 框图生成实时代码时,框图中不能含有 M 文件 S-函数。而 C MEX S-函数不仅运算速度快,而且可以用来生成独立的仿真程序。现已的 C 语言编写的程序还可以方便地通过包装程序结合至 C MEX S-函数中。C MEX S-函数结合了 C 语言的优势,可以实现对操作系统和硬件的访问,实现与串口或网络的通信,编写设备驱动程序等。

一:M文件编写的s函数
附上mathworks公司的模板(在matlab的命令行窗口输入edit Sfuntmpl.m)

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);otherwiseDAStudio.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;   % 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 = [];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 = [];

对上述模板进行解析:
function [sys,x0,str,ts,simStateCompliance] = sfuntmpl(t,x,u,flag)
先讲输入与输出变量的含义:t是采样时间,x是状态变量,u是输入(是做成simulink模块的输入),flag是仿真过程中的状态标志(以它来判断当前是初始化还是运行等);sys输出根据flag的不同而不同(下面将结合flag来讲sys的含义),x0是状态变量的初始值(可根据需要对其进行赋值),str是保留参数(一般都是在初始化中将它置空),ts是一个1×2的向量,ts(1)表示采样周期,ts(2)表示偏移量。
ps:如果是人为地自定义一些参量作为输入,则需要将模块改为:
function [sys,x0,str,ts,simStateCompliance] = sfuntmpl(t,x,u,flag,a,b,c) %a,b,c即为定义的输入变量

之后是switch,case模块:
根据flag的值判断执行哪一步。
case 0,
[sys,x0,str,ts,simStateCompliance]=mdlInitializeSizes; %该模块为初始化模块。在代码中,找到相应的执行模块:
function [sys,x0,str,ts,simStateCompliance]=mdlInitializeSizes
sizes = simsizes; %用于设置模块参数的结构体用simsizes来生成
sizes.NumContStates = 0; %模块连续状态变量的个数
sizes.NumDiscStates = 0; %模块离散状态变量的个数
sizes.NumOutputs = 0; %模块输出变量的个数
sizes.NumInputs = 0; %模块输入变量的个数
sizes.DirFeedthrough = 1; ;%模块是否存在直接贯通(直接贯通我的理解是输入能 直接控制输出)
sizes.NumSampleTimes = 1; % 模块的采样时间个数,至少是一个
sys = simsizes(sizes); %设置完后赋给sys输出
x0 = []; %根据需要对状态变量赋初值
str = []; %一般都设置为空
ts = [0 0]; %若系统为连续系统,则第一空为0;若第一空不为0,则该值为采样时间。 若第二空为0,表示整个系统无偏移,即为从初始时刻0开始动作。
simStateCompliance = ‘UnknownSimState’;

case 1,
sys=mdlDerivatives(t,x,u); %该模块为连续状态的微分模块。
在代码中,找到相应的执行模块:
function sys=mdlDerivatives(t,x,u)
sys = [];
此时要计算连续状态的微分。如果设置的连续状态变量个数为0,此处置空就可以了。

case 2,
sys=mdlUpdate(t,x,u); %该模块为离散转态的计算模块
在代码中,找到相应的执行模块:
function sys=mdlUpdate(t,x,u)
sys = [];

case 3,
sys=mdlOutputs(t,x,u); %该模块为计算输出的模块
在代码中,找到相应的执行模块:
function sys=mdlOutputs(t,x,u)
sys = [];

case 4,
sys=mdlGetTimeOfNextVarHit(t,x,u); %表示要计算下一次采样的时间。只有在离散采样系统中才有用
在代码中,找到相应的执行模块:
function sys=mdlGetTimeOfNextVarHit(t,x,u)
sampleTime = 1; % Example, set the next hit to be one second later.
sys = t + sampleTime; %对于连续系统,只需将sys置空就可以

case 9,
sys=mdlTerminate(t,x,u); %该模块为结束模块
在代码中,找到相应的执行模块:
function sys=mdlTerminate(t,x,u)
sys = []; %一般直接置空就可以了

进一步的学习内容可以参考
https://blog.csdn.net/weixin_42736130/article/details/89084225
https://blog.csdn.net/weixin_42736130/article/details/89178868
https://blog.csdn.net/dm12mail/article/details/66974956

二:C语言编写的s函数
C语言编写的s函数,需要先编译成可以在MATLAB内运行的二进制代码,然后才可以使用。
编译方法为:mex .c文件
C语言模板的打开方式:在matlab的命令行窗口中输入edit sfuntmpl_basic.c
同样附上mathworks公司的模板

#define S_FUNCTION_NAME  sfuntmpl_basic
#define S_FUNCTION_LEVEL 2
#include "simstruc.h"static void mdlInitializeSizes(SimStruct *S)
{ssSetNumSFcnParams(S, 0);  /* Number of expected parameters */if (ssGetNumSFcnParams(S) != ssGetSFcnParamsCount(S)) {/* Return if number of expected != number of actual parameters */return;}ssSetNumContStates(S, 0);ssSetNumDiscStates(S, 0);if (!ssSetNumInputPorts(S, 1)) return;ssSetInputPortWidth(S, 0, 1);ssSetInputPortRequiredContiguous(S, 0, true); /*direct input signal access*/ssSetInputPortDirectFeedThrough(S, 0, 1);if (!ssSetNumOutputPorts(S, 1)) return;ssSetOutputPortWidth(S, 0, 1);ssSetNumSampleTimes(S, 1);ssSetNumRWork(S, 0);ssSetNumIWork(S, 0);ssSetNumPWork(S, 0);ssSetNumModes(S, 0);ssSetNumNonsampledZCs(S, 0);ssSetSimStateCompliance(S, USE_DEFAULT_SIM_STATE);ssSetOptions(S, 0);
}static void mdlInitializeSampleTimes(SimStruct *S)
{ssSetSampleTime(S, 0, CONTINUOUS_SAMPLE_TIME);ssSetOffsetTime(S, 0, 0.0);}#define MDL_INITIALIZE_CONDITIONS   /* Change to #undef to remove function */
#if defined(MDL_INITIALIZE_CONDITIONS)static void mdlInitializeConditions(SimStruct *S){}
#endif /* MDL_INITIALIZE_CONDITIONS */#define MDL_START  /* Change to #undef to remove function */
#if defined(MDL_START) static void mdlStart(SimStruct *S){}
#endif /*  MDL_START */static void mdlOutputs(SimStruct *S, int_T tid)
{const real_T *u = (const real_T*) ssGetInputPortSignal(S,0);real_T       *y = ssGetOutputPortSignal(S,0);y[0] = u[0];
}#define MDL_UPDATE  /* Change to #undef to remove function */
#if defined(MDL_UPDATE)static void mdlUpdate(SimStruct *S, int_T tid){}
#endif /* MDL_UPDATE */#define MDL_DERIVATIVES  /* Change to #undef to remove function */
#if defined(MDL_DERIVATIVES)static void mdlDerivatives(SimStruct *S){}
#endif /* MDL_DERIVATIVES */static void mdlTerminate(SimStruct *S)
{
}#ifdef  MATLAB_MEX_FILE    /* Is this file being compiled as a MEX-file? */
#include "simulink.c"      /* MEX-file interface mechanism */
#else
#include "cg_sfun.h"       /* Code generation registration function */
#endif

对上述模板进行分析。为了更好地解释清楚,此处举一个例子:
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
static void mdlInitializeSizes(SimStruct S)
{
ssSetNumSFcnParams(S, 0); /
不含用户参数,设置为零 /
if (ssGetNumSFcnParams(S) != ssGetSFcnParamsCount(S)) {
return; /
若参数不匹配,Simulink 将发出警告 /
}
ssSetNumContStates(S, 2); /
系统有两个连续状态*/
ssSetNumDiscStates(S, 0); /* 系统无离散状态*/
if (!ssSetNumInputPorts(S, 1)) return; /* 如果输入端口数不为 1,则返回*/
/* S-functions 块只有一个输入端口,当需要多个输入时,必须使用 mux 模块把需要输入的信号合
成一个向量*/
ssSetInputPortWidth(S, 0, 2); /* 输入信号宽度为 2 /
ssSetInputPortDirectFeedThrough(S, 0, 1); /
设置馈通标志为 1 /
if (!ssSetNumOutputPorts(S, 1)) return; /
如果输出端口数不为 1,则返回*/
ssSetOutputPortWidth(S, 0, 2); /* 输出信号宽度为 2 /
ssSetNumSampleTimes(S, 1); /
1 个采样时间 /
ssSetNumRWork(S, 0); /
不使用工作向量 */
ssSetNumIWork(S, 0);
ssSetNumPWork(S, 0);
ssSetNumModes(S, 0);
ssSetNumNonsampledZCs(S, 0);
ssSetOptions(S, SS_OPTION_EXCEPTION_FREE_CODE);
}

static void mdlInitializeSampleTimes(SimStruct *S)
{
ssSetSampleTime(S, 0, CONTINUOUS_SAMPLE_TIME);
/*连续系统的采样时间设置为 0,等同于 ssSetSampleTime(S, 0, 0) */
ssSetOffsetTime(S, 0, 0.0);
}

#define MDL_INITIALIZE_CONDITIONS
static void mdlInitializeConditions(SimStruct S)
{
real_T x0 = ssGetContStates(S); / 获得指向连续状态的指针
/
int_T lp;
for (lp=0;lp<2;lp++) {
x0++=0.0; / 各状态初值设置为 0 */
}
}

static void mdlOutputs(SimStruct *S, int_T tid)
{ /*获得指向输出向量、连续状态向量和输入端口的指针 */
real_T *y = ssGetOutputPortRealSignal(S,0);
real_T x = ssGetContStates(S);
InputRealPtrsType uPtrs = ssGetInputPortRealSignalPtrs(S,0);
UNUSED_ARG(tid); /
not used in single tasking mode /
/
y=Cx+Du 输出方程 */
y[0]=C[0][0]*x[0]+C[0][1]*x[1]+D[0][0]*U(0)+D[0][1]*U(1);
y[1]=C[1][0]*x[0]+C[1][1]*x[1]+D[1][0]*U(0)+D[1][1]*U(1);
}

#define MDL_DERIVATIVES
static void mdlDerivatives(SimStruct *S)
{
real_T dx = ssGetdX(S); / 获得指向状态导数向量的指针 */
real_T x = ssGetContStates(S);
InputRealPtrsType uPtrs = ssGetInputPortRealSignalPtrs(S,0);
/
xdot=Ax+Bu 状态方程 */
dx[0]=A[0][0]*x[0]+A[0][1]*x[1]+B[0][0]*U(0)+B[0][1]*U(1);
dx[1]=A[1][0]*x[0]+A[1][1]*x[1]+B[1][0]*U(0)+B[1][1]*U(1);
}
static void mdlTerminate(SimStruct S)
{
UNUSED_ARG(S); /
unused input argument */
}

#ifdef MATLAB_MEX_FILE /* 是否编译成 MEX 文件 ? /
#include “simulink.c” /
包含 MEX 文件的接口机制 /
#else
#include “cg_sfun.h” /
代码生成注册函数 */
#endif

似乎很难吧。However,在这个社会中好像万事万物都有后门可走:s-function builder
用户只需在 S-function Builder 界面中的相应位置写入所需的信息和代码即可。S-function Builder会自动生成 C MEX S-函数源文件。用户只要单击 Build 按钮,S-function Builder 就会自动编译,自动生成用户所需的 MEX 文件。
在这里插入图片描述
第一步:先在名称栏中定义s函数的名称,之后将上图中的离散状态量个数,离散状态初值,连续状态变量个数,连续状态初值等信息按需要填上;
在这里插入图片描述
第二步:设置数据属性选项卡中的设置输入、输出的数据类型、信号维数等信息,设置用户参数的名称、数据类型等。
在这里插入图片描述
第三步:在这调用所需的库文件
第四步:在 Outputs、Continues Derivatives 和 Discrete Update 选项卡中分别填入输出方程、连续状态方程、离散状态方程以及其它用户定制的代码。
第五步:单击build键 is ok.


http://www.ppmy.cn/news/395012.html

相关文章

K8s 介绍

K8s 介绍 Kubernetes&#xff08;k8s&#xff09;是自动化容器操作的开源平台&#xff0c;这些操作包括部署&#xff0c;调度和节点集群间扩展。 使用Kubernetes可以&#xff1a; 1. 自动化容器的部署和复制 2. 随时扩展或收缩容器规模 3. 将容器组织成组&#xff0c;并且…

全志F1C200s芯片处理器参数介绍

F1C200s是全志的一款高度集成、低功耗的移动应用处理器&#xff0c;可用于多种多媒体音视频设备中。 全志F1C200s基于ARM 9架构&#xff0c;集成了DDR。它支持高清视频解码&#xff0c;包括H.264、H.263、MPEG 1/2/4等。它还集成了音频编解码器和I2S/PCM接口&#xff0c;以增强…

极路由1S HC5661A 刷入不死u-boot(breed)加刷潘多拉固件教程

原文来自&#xff1a;新版极路由1S&#xff08;HC5661A&#xff09;刷潘多拉加SS配置教程 不死uboot(breed)如何使用 下文是以原文为基础&#xff0c;更详细也更适合小白的整合版。 注意&#xff1a;本贴是新版的白盒极路由1S&#xff08;HC5661A&#xff09;教程&#xff…

解析 css3 transition:all 1s ease 1s

ease&#xff1a; 1、ease&#xff1a;&#xff08;逐渐变慢&#xff09;默认值 2、linear&#xff1a;&#xff08;匀速&#xff09; 3、ease-in&#xff1a;(加速) 4、ease-out&#xff1a;&#xff08;减速&#xff09; 5、ease-in-out&#xff1a;&#xff08;加速然后减…

java如何实现让程序暂停1s再继续执行?

java如何实现让程序暂停1s再继续执行&#xff1f; www1314520sss | 浏览 16157 次 问题未开放回答 |举报 推荐于2017-09-10 16:16:36 最佳答案 被采纳的那位有个小错误 1 2 3 4 5 6 7 8 9 10 11 12 13 14 public class a{ public static void main(String[] args) { Sy…

定时器中断控制LED闪烁(每隔1s)---普中科技开发仪

定时器中断o,利用中断控制LED闪烁每隔1s闪烁一次&#xff08;精确的1s&#xff09; notes: (1)工作方式寄存器TMOD ,低四位用于To&#xff0c;高四位用于T1&#xff0c;(GATE,C/T- ,M1,M0) 一般让GATE 0,C/T0是定时器&#xff0c;C/T1是计数器&#xff1b; MiM0: 工作方式设置位…

51单片机实验——用定时器0实现流水灯,要求每个led轮流显示1s。

1.实验题目&#xff1a; 用定时器0实现流水灯&#xff0c;要求每个led轮流显示1s。 2.KEIL代码 #include<reg51.h> void main() {TMOD &0X0F;TMOD |0x01;TH0 (65536 - 50000)/256;//高四位初值TL0 (65536 - 50000)%256;//低四位初值&#xff0c;每隔50ms溢出EA…

VBA 等待1S 处理方法

Application.Wait (Now TimeValue("0:00:01")) 表示暂停1s

通过单片机定时器输出周期为1s的方波,驱动LED灯闪烁

方波 方波的占空比固定是50%,即高电平和低电平的时间为1:1; 方波的周期:从一个上升沿(下降沿)到下一个上升沿(下降沿)的时间; 由此可得知周期为1s的方波就是高电平占0.5s,低电平占0.5s的波形; 单片机定时器 MCS-51有两个定时器,定时器0,定时器1; 相关寄存器 TMOD…

定时器0工作方式2,定时1s

定时器0工作方式2&#xff0c;定时1s

过渡属性 transition:all 1s linear 0s;

过渡属性的作用就是体现元素默认样式与最终样式变化的过程。 代码格式&#xff1a;transition&#xff1a;all 1s linear 0s&#xff1b; 注&#xff1a; 第一个参数的作用是设置元素的哪些属性过渡&#xff0c;all表示全部过渡&#xff0c;width代表属性宽度过渡&#xff0c;…

51单片机如何延时1s,让LED灯闪烁

精确地延时1s需要准确地计算&#xff0c;粗略地延迟1s可以自定义一个delay函数&#xff0c;下面我们让第一个LED灯延迟1s闪烁&#xff1a; //本题的delay函数参数为1时延迟的是1ms&#xff0c;1000是1s #include<reg52.h> #define uchar unsigned char #define uint…

Linux网卡命名enp1s0说明

用了很多年Linux的我在升级Ubuntu 16.04之后竟然发现我的以太网卡的名字竟然不是eth0&#xff0c;变成了enp1s0&#xff0c;每次想要修改什么配置&#xff0c; 都要先ifconfig查一下网卡名&#xff0c;真是让我很郁闷&#xff01; 去网上搜索一下才知道&#xff0c;这次的Ubun…

汇编语言软件延时1s

对于不同的计算机&#xff0c;因为其主频不同&#xff0c;延时1s的参数也不相同&#xff0c;计算延时的方法如下: 计算机主频&#xff1a;x &#xff08;Hz&#xff09; 一条LOOP语句执行始终周期数&#xff1a;y 所需要延时的时间&#xff1a;z &#xff08;s&#xff09; 需…

定时器0工作方式1,定时1s

定时器0工作方式1&#xff0c;定时1s。

时间单位的换算(秒,毫秒,微秒,纳秒,皮秒)

时间单位&#xff1a; 秒&#xff08;second&#xff09;&#xff0c;时间单位 &#xff1a; s&#xff0c;   毫秒(millisecond&#xff09;&#xff0c;时间单位&#xff1a;ms   微秒&#xff08;microsecond&#xff09;&#xff0c;时间单位:μs 时间换算: 1s【秒】 …

王道机试指南NO.1排序1s运行时限的时间复杂度分析

题目描述 对输入的n&#xff08;1<n<100&#xff09;个数进行排序并输出 时间限制 1s&#xff1b;内存限制 32MB 样例输入 4 1 4 3 2 样例输出 1 2 3 4 &#xff08;每个数后面都有一个空格&#xff09; 题目分析----使用冒泡 对于1s的运行时限&#xff0c;设计的…

C语言之指针详解(2)

目录 本章重点 1. 字符指针 2. 数组指针 3. 指针数组 4. 数组传参和指针传参 5. 函数指针 6. 函数指针数组 7. 指向函数指针数组的指针 8. 回调函数 9. 指针和数组面试题的解析 数组指针 数组指针的定义 数组指针是指针&#xff1f;还是数组&#xff1f; 答案是&…

python通过SimpleITK库预览.mha格式图片

python代码 import SimpleITK as sitk import matplotlib.pyplot as plt from pathlib import Path def read_and_display_mha(file_path): # 使用SimpleITK库读取MHA文件 image sitk.ReadImage(str(file_path)) # 将SimpleITK图像转换为NumPy数组 image_array sitk.GetArr…

proxmark3

proxmark3是一款开源的RFID工具&#xff0c;详细介绍请见http://code.google.com/p/proxmark3/wiki/HomePage?tm6 这是我的proxmark3&#xff0c;天线很土&#xff0c;信号也不太好&#xff0c;但还是能工作的。感谢原作者Jonathan Westhues 的无私奉献&#xff01; HF天线上…