1、S-函数概述1、什么是 S 函数S 函数(系统函数)提供一个有力的途径用于扩展 Simulink 仿真环境的能力。S 函数是用 MATLAB、C、C+、Fortran 编写的,用来描述 Simulink 模块。C、C+ 、Fortran 编写的用 mex 公用程式编译为 MEX 文件(具体参考 building MEX-File).与其他的 MEX 文件一样,S 函数是一个 MATLAB 翻译器可以自动加载执行的动态链接子程序。S 函数使用一种特殊的调用语法条用 S 函数应用程序,使你们可以与仿真引擎交互。这种交互同发生在引擎与仿真环境中的模块的交互相似。S 函数遵循一种通用的格式,可以兼容连
2、续、离散和混合系统。遵守一系列简单的规则,你们可以在 S 函数中实现算法并且将 S 函数模块添加到仿真模块中。当你编写自己的S 函数后,将其名字添加到 S 函数块(在用户定义函数模块库中可以找到) ,你可以使用masking(在 Creating Custom Blocks 中可以查看) 来定做用户界面。你可以用实时 Workshop 产品使用 S 函数,你也可以通过编写目标语言编译器文件(TLC )来定制生成 S 函数的代码,可以查看( Integrating External Code With Generated C and C+) 。2、在建模中使用 S 函数A、兼容 C MEX S
3、函数或者旧版(MATLAB level-1)的 S 函数,从用户定义函数库拖动S 函数到模型中,然后指定 S 函数的名字(名字中包含了函数的信息) ,level-2 的版本操作也一样(当路径中有同名的 C MEX 文件和 MATLAB 文件时,优选执行 C MEX 文件) 。B、向 S 函数传递参数:S 函数块的“Parameters”文件允许指定参数值传递到相应的S 函数。为了使用这些文件,必须知道 S 函数需要的参数、参数的顺序,如果不知道,可以咨询 S 函数的作者、文档或者源代码。输入参数用逗号分开,按照 S 函数要求的顺序输入,参数的值可以是常数、变量名(定义在 MATALB、建模工作
4、空间或者 MATALB 表达式中) 。当调用 level-1S 函数时,仿真引擎通常传递标准参数快(t,x,u,flag)到 S 函数作为函数参数。引擎可以传递附加的由用户指定的块参数到 S 函数。用户在 S 函数的“S-function parameter”文件中指定参数(参见 Passing Parameters to S-Functions) 。如果块对话框指定额外的参数,引擎传递参数到 S 函数作为额外的函数参数。额外的参数遵循在 S 函数中的参数列表顺序标准。C、何时使用 S 函数:1、建立一个人新的通用模块;2、添加硬件驱动模块;3、兼容现在的 C 代码到仿真中(参见 Integr
5、ating Existing C Functions into Simulink Modules with the legacy Code Tool) ;4、描述一个具有复杂数学方程的系统;5、使用图形激励。其中最常使用 S 函数的是建立用户仿真块(参见 Creating Custom Block) 。当使用 S 函数来建立通用模块时,可以在一个模型中多次使用,根据实际情况指定具体模块的参数。3、在项目中使用 S 函数A、Mathematics of Simulink Blocks:一个仿真模块包含了一系列的输入、输出和状态,输出是时间、输入、状态的函数。输出=0(,)状态方程=(,)更新状态
6、 +1=(,) =;B、仿真阶段:执行一个仿真模型分阶段进行。首先是初始化阶段,仿真引擎加载库模块到模型中,传递信号宽度、数据类型、采样时间、模块参数赋值、确定模块执行顺序、定位内存;随后引擎进入 Simuliation Loop,在这个过程中,每一个循环视为一个仿真步;在每一步中,仿真引擎按初始化确定的顺序执行模型中的每个模块的计算;对于模块,引擎调用函数计算模块采样时刻的状态、导数(微分) 、输出。C、S 函数的回调原理:一个 S 函数包含一系列的 S 函数回调方法来执行每一个仿真阶段的任务。在模型仿真中,在每一个仿真进行阶段,仿真引擎为每一个 S 函数模块调用相应的方法。由 S 函数回调
7、方法实现的任务有:1、初始化:优先于第一个仿真循环,引擎初始化 S 函数,包括:初始化SimStruct(一种包含关于 S 函数信息的仿真结构);设置输入输出的数值和维数;设置模块采样时间;定义存储区域2、计算下一个采样点:如果使用了变采样时间,这个阶段计算下一个采样点的时间,也就是计算下一个步长(采样间隔) ;3、计算主时间步的输出:在这个调用结束之后,所有模块输出都确定。4、在主时间步长更新离散状态:这个调用是说模块执行每一步一次的动作,如更新离散状态;左边的图演示了仿真阶段。Inner integration loop 只有在连续状态仿真时发生。模块仿真引擎执行循环直到求解器达到状态计算
8、的指定精度。整个仿真循环不断执行,直到停止。可以参考(Simulation Dynamic System)了解仿真执行的具体信息;可以参考 How the Simulink Engine Interacts with C S-Function,描述了引擎在初始化和仿真过程中如何调用 S-Function API。5、集成:它应用于具有连续信号或者非过零点采样。如果 S 函数具有连续的状态,引擎调用 S 函数在 Minor time steps 的输出和微分,所以求解器可以计算 S 函数的状态。如果 S 函数具有非采样过零点,引擎也调用 S 函数在 Minor time step 输出和过零点以
9、便于它定位过零点。4、实现 S 函数A、MATLAB 的 S 函数:LEVEL2-MATLAB S-Function 允许在仿真环境中创建具有多种特征和功能的模块,这其中有: 多输入输出口 接收矢量和矩阵信号 支持各种信号属性:数据类型、混合、信号模型 处理多种采样频率LEVEL2-MATLAB S-Function 由一个设置程序来配置基本属性,一系列的在仿真中的相应时间调用的回调方法组成。一个基本注释的模板在“msfuntmpl_basic.m” 。其中模板由一个高级设置函数和一系列骨架子函数(每一个都与相应的回调方法相对应)组成。每一个回调方法实现一个具体的 S 函数在仿真中相应节点的任
10、务。引擎调通过定义在设置程序中的函数句柄调用函数。关于支持 LEVEL2-MATLAB S-Function 的回调方法可参见“Level-2 MATLAB S-Function Callback Methods”;更加详细的 LEVEL2-MATLAB S-Function 模板信息在“msfuntmpl.m”中。作者建议在建立 LEVEL2-MATLAB S-Function 时按照模板格式来规划结构和命名,这对于他人对 S 函数进行理解和维护很方便,如何创建 LEVEL2-MATLAB S-Function 参见“Writing S-Functions in MATLAB” 。MEX S
11、-Functions 就像 LEVEL2-MATLAB S-Function 一样,由一系列在仿真中引擎调用来实现各种模块相关任务的回调方法组成。S-Function 可以有 C、C+、Fortran 实现,引擎直接调用 MEX S-Function 程序而不是通过函数句柄,由于引擎 直接调用函数 MEX S-Function 必须根据 S-Fuction API 指定的命名规则。具有注释的模板在“sfuntmpl_doc.c”。模板包含了实现各种要求和可选的回调方法的骨架,C MEX S-Function 可以实现的。更多的模板的基本版本可在“sfuntmpl_basic.c”中查到。MEX
12、 Verse MATLAB S-Function:LEVEL2-MATLAB S-Function 和 MEX S-functions各有优点,前者的优点在于开发的方便简单,可以节约 compile-link-execute 循环所花费的时间,它也可以更方便使用工具箱函数并利用 Editor 和 Dubugger;后者的优势在于执行的速度上,也可以集成已有的代码到仿真模块中,对于更加复杂的系统,由于前者每次回调都需要翻译执行,会花费更多的时间。权衡选择可参考“Selecting an S-Function Implementation”。5、S-Function 的概念Direct Feedt
13、hrough:意味着输出(或者可变采样系统的采样时间)由输入端口信号值直接控制。 (即输入量直接作用于输出量,如比例关系,如果输出不是输入 U 的有理函数,则不属于 Direct Feedthrough)输入端口 Direct Feedthrough 典型的情况有: 输出函数(mdloutputs)是输入 U 的函数,也就是说输入 U 可以被 mdloutputs 所获取即存在 Direct Feedthrough。输出也可以包含图像输出,比如 XY 图像的示波器。 变采样时间 S 函数的下一个采样点函数(mdlGetTime0fNextVarHit)可以访问输入量 U。正确设置 Direct
14、 Feedthrough flag 是非常重要的,它影响模型中模块的执行顺序并且用于检测 algebraic loop(代数循环),具体信息参见“Algebraic Loop”。如果模型中 S函数的仿真结果没有收敛或者仿真失败,有可能是 Direct Feedthrough flag 设置错误。尝试开启 Direct Feedthrough flag 并设置 algebraic loop 求解器的诊断方法来给出提示,具体参见“ Diagnostics Pane: Solver”,接着运行仿真将显示模型中的所有代数循环并且如果引擎将 S 函数加入代数循环时也将显示出来。Dynamically S
15、ized Arrays:S 函数的输入的维数是可以任意指定的,所以,仿真引擎在仿真开始的时候检测驱动 S 函数的输入矢量的维数来确定实际的输入信号的维数,S函数也可以利用输入维数来确定连续状态的数目、离散状态的数目、和输出的数目。 (在具体模型或者不同的仿真中,输入的维数的尺寸对于每一个具体的使用情况可以有所不同,但是在一个特定的仿真过程中,每一个 S 函数输入的维数是固定不变化的) 。C MEX 函数和 Level-2MATLAB 函数可以含有多个输入和输出端口,每一个端口可以具有不同的维数,端口的个数和个端口的具体维数可以动态的确定。Setting Sample Times and Off
16、sets:Level-2 MATLAB C MEX S-functions 函数如下的采样时间选择,提供高度灵活的选择来执行 S 函数。 连续采样时间对 S 函数来说就是连续状态和非过零检测,可以在“How Simulink Works in Using Simulink for an explanation of zero crossings”查看具体信息。这种情况下,S 函数的输出以 minor 时间步长进行更新。 连续状态但是在 minor time 阶段保持不变这种情况的 S 函数需要在 major time 期间执行,但是在 minor time 期间不改变输出。 离散采样时间如果
17、S 函数的特性是具有离散的时间间隔,可以定义采样时间来实现控制,此时,也可以定义一个补偿来为每个采样点进行延时操作,但补偿不能增加相应的采样周期TimeHit = (n * period) + offset其中的整数 n 是目前的仿真步数,起始值通常为零。如果定义的是离散采样周期,在采样点的时候(方程所定义计算)引擎调用 S 函数 mdloutput 和 mdlUpdate 程序 变采样时间离散采样周期的时间间隔可以改变,在每一个仿真步长的开始,具有变采样周期的 S 函数下一个采样点是不确定的。 Inherited sample time(遗传采样周期)有时 S 函数没有一个固定的采样周期属性
18、(也就说要么是连续,要么离散,取决于系统中其他模块的采样周期) 。这种情况下,可以指定采样周期为 Inherited。举一个例子,比如Gain(比例增益)模块从驱动它的模块出获得采样周期。一般来说,继承采样周期的的来源有: 驱动模块如图所示的例子,S 函数第一个由三元素的矢量驱动,第二个由一维的标量驱动,通过指定 S 函数具有动态的输入维数,同样的 S 函数可以兼容以上的两种情况。仿真引擎自动调用模块并赋予模块合适的输入矢量的尺寸。同样的,其他的模块属性如输出个数、离散或者连续状态的数目,都是动态确定的,引擎自动将这些矢量的尺寸设置与输入向量一致。 目标模块 系统的最短采样周期为了指定采样周期
19、类型为 Inherited,使用-1 Level-2 MATLAB S-functions and INHERITED_SAMPLE_TIME in C MEX S-functions as the sample time。更加详细的信息可以在“How Propagation Affects Inherited Sample Times”中查看。采样周期指定的形式为: sample_time, offset_timeValid C MEX S-Function Sample Times: 在 C MEX 中指定 S 函数采样周期:CONTINUOUS_SAMPLE_TIME, 0.0CONTI
20、NUOUS_SAMPLE_TIME, FIXED_IN_MINOR_STEP_OFFSETdiscrete_sample_time_period, offsetVARIABLE_SAMPLE_TIME, 0.0其中:CONTINUOUS_SAMPLE_TIME = 0.0FIXED_IN_MINOR_STEP_OFFSET = 1.0VARIABLE_SAMPLE_TIME = -2.0 当指定为继承采样周期时, 这里就只需要一个参数:INHERITED_SAMPLE_TIME, 0.0或者:INHERITED_SAMPLE_TIME, FIXED_IN_MINOR_STEP_OFFSET其中
21、 INHERITED_SAMPLE_TIME = -1.0 在 Level-2 MATLAB S-Function 中确定采样周期0 offset % Continuous sample timediscrete_sample_time_period, offset % Discrete sample time-1, 0 % Inherited sample time-2, 0 % Variable sample time 选择采样周期的指导方针使用如下的导引来确定采样周期: 连续 S 函数,并且在 minor 步长期间更新用:CONTINUOUS_SAMPLE_TIME, 0.0 连续 S
22、函数,并且不在 minor 步长期间更新应该注册: CONTINUOUS_SAMPLE_TIME, FIXED_IN_MINOR_STEP_OFFSET 一个离散 S 函数,以固定的频率更新:discrete_sample_time_period, offset其中 discrete_sample_period 0.0;0.0 offset discrete_sample_period 一个离散 S 函数,具有变频率的应注册:VARIABLE_SAMPLE_TIME, 0.0;在 C MEX 中,mdlGetTimeOfNextVariHit 程序来获取下一个采样点的位置;在 Level-2
23、MATLAB S 函数中,NextTimeHit 的属性由Outputs method 来设置。如果 S 函数没有固有的采样周期,就必须默认采样周期时 Inherited 的,有两种情况: S 函数随它输入的改变而改变,即使是在 minor integration steps,此时应该注册INHERITED_SAMPLE_TIME, 0.0Offect=1在 minor 周期不变Offect=0在 minor 周期更新 如果 S 函数随输入的改变而改变,但是在 minor integration steps 期间保持不变,应注册INHERITED_SAMPLE_TIME, FIXED_IN_M
24、INOR_STEP_OFFSET示波器模块是一个很好的例子,这个模块的采样频率随驱动模块而变化,要么连续、要么离散、但是不会以 minor step 为输出周期,因为这样的话,则输出的点的信息会是求解器运算的中间值而不是每个时间节点的最终结果。更多详细的信息参见“Sample-Times” 。5、S 函数举例1. 例子的概述:在 Command Window 中输入”sfundemo”,打开 S 函数“demo”库。具有四中语言格式的演示程序。每一个图标都代表一种 S 函数的分类。代码的存储位置是:MATLAB:toolbox/simulink/simdemos/simfeaturesC、 C+、Fotrantoolbox/simulink/simdemos/simfeatures/src