logo资料库

C语言编写S函数方法.doc

第1页 / 共10页
第2页 / 共10页
第3页 / 共10页
第4页 / 共10页
第5页 / 共10页
第6页 / 共10页
第7页 / 共10页
第8页 / 共10页
资料共10页,剩余部分请下载后查看
S 函数(system function)是模块的核心,是完成功能实现的关键。S 函数的 编写可以使用多种程序语言,其中 M 语言是最常用的,同时也是最简单的。在 运用 M 语言进行 s 函数编写的时候,可以调用 MATLAB 提供的函数,简化了开 发过程。但是如果要与其他进程通讯或驱动外部硬件接口,则要调用 API 函数, 这样就需要用 C 语言来开发 S 函数。较 M 语言的开发,C 语言开发 S 函数更具有 灵活性,但是相对复杂一些。 C 语言写 S 函数,顾名思义,运用 C 语言语法,依照 S 函数格式要求,最后 在 MATLAB 中 MEX 命令编译,编译成功既得函数。 S 函数格式可简单看成:初始化、采样时间设定、系统输出、结束四个部分。 对应的函数分别为 mdlInitializeSizes()、mdlInitializeSampleTimes()、mdlOutputs()、 mdlTerminate()。这四个函数是一个 S 函数必不可少的,缺少任何一个在编译的 时候都无法通过,输出信息会提示哪个函数没有写。 一个最基本的 C 语言 S 函数模版如下: #define S_FUNCTION_NAME name #define S_FUNCTION_LEVEL 2 #include“simstruc.h” Static void mdlInitializeSizes(SimStruct *S){} Static void mdlInitializeSampleTimes(SimStruct *S){} Static void mdlOutputs(SimStruct *S,int_T tid){} Static void mdlTerminate(SimStruct *S){} #ifdef MATLAB_MEX_FILE #include“Simulink.c” #else #include“cg_sfun.h” #endif S 函数的运行依托于 Simulink,Simulink 的运行是采用循环方式,计算各采样 时间点的系统状态得到的,由此可理解 S 函数,在初始化之后,S 函数也通过循 环完成输出状态计算。 结合上述格式,首先自定义 S 函数名称,然后定义 S 函数级别,这里写 2,1 级是老版本 Simulink 使用的,现已经不是用,之所以保留 1 级是为了兼容原有的 老程序,现在写的 S 函数都是 2 级的。接下来将需要的头文件包含进来,这里必 须包含 simstruc.h 文件,这里的 SimStruc 是 Simulink 提供的数据结构,S 函数中 的输入输出等信息都包含在这个结构体中,同时,在编写 S 函数的时候也要把使 用到的 C 语言库中的头文件包含进来,所有的 C 语言库文件在这里都可以使用。 接下来即可按照格式顺序编写代码。最后要注意,如果用于仿真则添加 Simulink.c 文件,如果用于 RTW 代码生成,则添加 cg_sfun.h 头文件。这里的 RTW 代码生 成是指非内嵌的 S 函数,如果要做一个内嵌的 S 函数则需要在 S 函数中添加 mdlRTW()函数,并额外编写 TLC 文件。其中,TLC 文件用于优化的 C 代码生成, mdlRTW()函数则把模块参数传递到生成的代码当中。具体 TLC 文件的编写方法这 里不再赘述。 除了上述必需的函数外,系统提供了其他可选用的函数,功能各异,例如 mdlStart()等。
只要理解了 Simulink 运行方式就可以理解文件的开发过程了,其中,系统函数和 特定的变量类型都可以在 SimStruct 数据结构中找到。至此,基本的 S 函数都可 以编写了。 在编写结束后,将 S 函数源文件存储在 MATLAB 路径下,打开 MATLAB 命令 行窗口,选择当前路径为存储路径,运用 MEX 命令编译 C 源文件,如果成功则 在当前路径下生成一个后缀名为 mexw32 的文件(后缀名随系统环境不同而不 同,32 指 32 位系统,如果是 64 位系统则不同),如果使用的是 MATLAB 早期 版本,则生成的文件后缀名为 dll,即动态链接库。两者等价,这里可以用 dll 来 理解 mexw32 文件的作用。 当 S 函数编译写好之后,还不能在 Simulink 中直接调用,因为缺少一个可视 化的模块。这时候打开 Simulink,在用户自定义模块库中找到名称为 S_function 的模块,并将它拖拽到模型文件中。可以把它看成一个 S 函数的通用的容器,下 面介绍如何把编写好的 S 函数放入这个容器,即模块封装。 下面讲解 S 函数的模块封装方法: 右键点击 S 函数模块,选择 MASK 选项,弹出封装编辑框,在这里有四个栏, 分别为图标、参数、初始化、文档。其中参数最为重要。图标即模块上显示的图 形,可以编辑自己需要的文字,也可以用图片包装模块。初始化可以对模块参数 进行默认设置,文档中可以编写模块说明和帮助链接。而最重要的参数栏中,要 把模块对应的 S 函数的参数列出来,每一个参数有三种形式:编辑、下拉框、复 选框。如果是下拉框形式,要编辑对应的选项。如果 S 函数需要响应不同操作, 可以对每一个参数选择编写对应的回调函数。值得一提的是,可以用 set_param() 函数直接对封装模块进行操作,可以实现更加灵活的封装。 封装编辑好后,右键点击 S 函数模块选择 LOOK UNDER MASK 选项,在弹出 的对话框中,首先填写原文件,把编译过的文件(mexw32)放置在当前目录下, 在对话框中正确填写文件名(不写后缀),然后再把封装时定义的参数变量按顺 序写在参数框中,每个参数用逗号隔开,注意变量名必须与封装填写的名称一致, 且数目相同。最有一个框不用填写。点击 OK。则完成了对 S 函数的模块封装。 完成上述两个步骤之后,即完成了自定义的 Simulink 驱动模块,这时要做的 工作是对该模块经行测试。若测试通过,可以将该模块添加进 Simulink 模块库, 和 Simulink 提供的模块并没有任何的区别,方便以后工作中的重复利用。若测试 未通过,则返回 S 函数编写工作中,重新编写 S 函数,重复上述步骤。由于封装 只是一个将 S 函数图形化的过程,当测试出现问题的时候,可以确定是 S 函数的 工作出现了问题,而不是因为封装引发的。 由于水平有限,这里讲解不那么易于理解,可以在学习过程中,参照现有程序和 MATLAB 帮助文档,从自己动手编写简单的 S 函数入手,一旦完成一次,以后就很好理解了。 4.1 C MEX-file S-function 简介 定义了 S-function 模块的 C MEX-file 必须在仿真过程中向 Simulink 提供模型信 息。在仿真中 Simulink、ODE 求解器、MEX-file 协作完成指定任务。这些任务 包括:定义初始条件和模块特性,计算微分、离散状态和输出。 Simulink 与 C MEX-file S-function 模块的交互仍是通过 S-function 的回调方法。 每个回调方法执行一个预定义的,实现仿真所需功能的任务。S-function 可以执 行任何其实现的任务。一系列 C MEX-file S-function 实现的回调方法,都远大于 M-file S-function 中的。与 M-file S-function 不同的是,C MEX-file 可以访问并
修改 Simulink 内部用来存储 S-function 信息的数据结构。更多的回调方法和对 Simulink 内部数据结构的访问能力,使得 C MEX-file S-function 可以实现更丰富 的模块特性,如处理矩阵信号和多种数据类型。 C MEX-file S-function 只需实现 Simulink 定义的回调方法的一个小子集即可。如 果不实现某个回调方法,相应的功能将被省略掉。这有利于快速开发简单的模块。 通常 C MEX-file S-function 的形式如下: #define S_FUNCTION_NAME your_sfunction_name_here #define S_FUNCTION_LEVEL 2 #include "simstruc.h" static void mdlInitializeSizes(SimStruct *S) {} static void mdlTerminate(SimStruct *S) {} #ifdef MATLAB_MEX_FILE #include "simulink.c" /* Is this file being compiled as a MEX-file? */ /* MEX-file interface mechanism */ #else #include "cg_sfun.h" /* Code generation registration function */ #endif mdlInitializeSizes 是 Simulink 与 S-function 交互时调用的第一个方法。随后 Simulink 将调用其他 S-function 方法(都以 mdl 开头)。仿真结束时,Simulink 调用 mdlTerminate。 注意:与 M-file S-function 不同,C MEX-file S-function 回调方法不是每个都具 有 flag 参数。这是因为,Simulink 仿真时直接在适当的时间调用每个回调方法。 4.2 自动建立 S-function 模块 S-Function Builder 是通过规范定义和用户提供的 C 代码建立 S-function 的 Simulink 模块。S-Function Builder 还用作普通的 S-function 在 Simulink 模型中 的包装。 通过 S-Function Builder 建立 S-function。 1. 将 MATLAB 当前目录设置到需要建立 S-function 的目录。 2. 创建新的 Simulink 模型。 3. 从 Simulink User-Defined Functions library 中将 S-Function Builder 拖入新 建的 ulink 模型。
4. 双击模块打开 S-Function Builder 对话框。 5. 输入所需信息和用户代码。(详见下节) 6. 如果还未设置 mex 编译器,用 mex –setup 在 MATLAB 命令行设置。 7. 点 Build 按钮,启动建立过程。Simulink 建立 MEX 文件实现指定的 S-function, 并存放在当前目录 8. 保存包含 S-Function Builder 模块的模型。 部署生成的 S-Function 要在其他模型中使用生成的 S-Function,首先必须检查生成的 S-Function 所在 的目录是否在 MATLAB 路径中。然后把 S-Function Builder 模块从创建它的模 型复制到目标模型并设置其参数。 S-Function Builder 如何建立 S-Function 4.3 S-Function Builder 对话框 4.4 基本的 C MEX-file S-function 实例 本节介绍一个 C MEX-file S-function 实例:timestwo,实现输出信号放大为输入 信号的 2 倍。以下是模型图: 以下是 timestwo.c 文件的代码: #define S_FUNCTION_NAME timestwo #define S_FUNCTION_LEVEL 2 #include "simstruc.h" static void mdlInitializeSizes(SimStruct *S) { ssSetNumSFcnParams(S, 0); if (ssGetNumSFcnParams(S) != ssGetSFcnParamsCount(S)) { return; /* Parameter mismatch will be reported by Simulink */ } if (!ssSetNumInputPorts(S, 1)) return; ssSetInputPortWidth(S, 0, DYNAMICALLY_SIZED); ssSetInputPortDirectFeedThrough(S, 0, 1); if (!ssSetNumOutputPorts(S,1)) return; ssSetOutputPortWidth(S, 0, DYNAMICALLY_SIZED); ssSetNumSampleTimes(S, 1); ssSetOptions(S,
SS_OPTION_WORKS_WITH_CODE_REUSE | SS_OPTION_EXCEPTION_FREE_CODE | SS_OPTION_USE_TLC_WITH_ACCELERATOR); } static void mdlInitializeSampleTimes(SimStruct *S) { ssSetSampleTime(S, 0, INHERITED_SAMPLE_TIME); ssSetOffsetTime(S, 0, 0.0); ssSetModelReferenceSampleTimeDefaultInheritance(S); } static void mdlOutputs(SimStruct *S, int_T tid) { int_T i; InputRealPtrsType uPtrs = ssGetInputPortRealSignalPtrs(S,0); real_T int_T *y = ssGetOutputPortRealSignal(S,0); width = ssGetOutputPortWidth(S,0); for (i=0; i
这 个 实 例 包 括 3 部 分 : 宏 定 义 和 头 文 件 ; 回 调 方 法 的 实 现 ;Simulink ( 或 Real-Time Workshop)接口。 宏定义和头文件 示例程序中包含两个宏定义: #define S_FUNCTION_NAME timestwo #define S_FUNCTION_LEVEL 2 第一个指定 S-function 的名字,第二个指示该 S-function 是 Level-2 格式的。 然后是包含头文件"simstruc.h",在其中定义了 SimStruct 数据结构和 MATLAB 应用程序接口(API)函数。SimStruct 是 Simulink 用于保持 S-function 信息的数 据结构,"simstruc.h"中还有用于 MEX 文件设置或获取 SimStruct 属性值的宏定 义。 回调方法的实现 mdlInitializeSizes: Simulink 调用 mdlInitializeSizes 方法查询 S-function 模块的输入输出端口数, 端口容量,以及 S-function 所需的其他对象(如,状态个数等)。 Timestwo 实现的 mdlInitializeSizes 方法指定了下面信息 ● 零参数: 意味着 S-function 对话框的参数框必须为空。否则,Simulink 将报告参数不匹配。 ● 一个输入和一个输出端口: 输入输出端口的宽度可以动态变化。Simulink 将把所有输入信号乘以 2 作为输出 信号的结果。注意,在这种情况下(一个输入一个输出端口),Simulink 对 S-function 宽度的默认处理是输入和输出宽度相等。 ● 一个采样时间 例子 timestwo 在 mdlInitializeSampleTimes 中指定实际的采样时间。 ● 代码无异常处理 指定无异常处理的代码可以加速 S-function 的执行。作这项指定必须谨慎。通常, 如果用户 S-function 与 MATLAB 没有交互,指定无异常处理的代码是安全的。 mdlInitializeSampleTimes: Simulink 调 用 mdlInitializeSampleTimes 设 置 S-function 的 采 样 时 间 。 每 当 timestwo 模块的前驱模块执行一次,timestwo 模块就执行一次,所以 timestwo 模块采用继承的采样时间。 mdlOutputs Simulink 在每个时间步调用 mdlOutputs 计算模块的输出。Timestwo 模块的 mdlOutputs 方法实现了将输入信号乘以 2,将结果写到输出信号。
Timestwo 模块的 mdlOutputs 方法使用了 SimStruct 中的宏: InputRealPtrsType uPtrs = ssGetInputPortRealSignalPtrs(S,0); 来实现对输入信号的访问。这个宏返回一个指针向量,必须通过*uPtrs[i]来访问。 Timestwo 模块的 mdlOutputs 方法还使用了 real_T *y = ssGetOutputPortRealSignal(S,0); 来访问输出信号。这个宏返回一个包含模块输出的数组。 S-function 使用 int_T width = ssGetOutputPortWidth(S,0); 来得到通过该模块的信号宽度。最后 S-function 循环通过输入得到输出。 mdlTerminate 执行仿真结束最后的任务。这是一个强制的 S-function 过程。不过由于 timestwo 模块不需要任何终止操作,所以其函数为空。 Simulink/Real-Time Workshop 接口 在 S-function 的最后,下面的特定代码将该例子关联到 Simulink 或者 Real-Time Workshop: #ifdef MATLAB_MEX_FILE #include "simulink.c" #else #include "cg_sfun.h" #endif 生成 timestwo 实例 在命令行键入:mex timestwo.c mex 命令将把 timestwo.c 编译、链接为一个可由 Simulink 动态加载执行的模块。 这是一个动态链接库文件,在 Window 中,是个 dll 文件。 4.5 C MEX S-functions 模板 Simulink 提 供 了 C S-functions 模 板 。 /simulink/src/sfuntmpl_basic.c 提供了 C MEX S-functions 的常用 功 能 方 法 。 /simulink/src/sfuntmpl_doc.c 则 描 述 了 C MEX S-functions 的全部实现方法。 S-function 源代码文件的要求 用户 S-function 要访问 SimStruct 结构,则必须在文件头部具备下列宏定义和头 文件: MEX #define S_FUNCTION_NAME your_sfunction_name_here
#define S_FUNCTION_LEVEL 2 #include "simstruc.h" 这里 your_sfunction_name_here 指得是用户 S-function 的模块名。这些声明使 S-function 能访问 SimStruct 结构。 当被编译为 MEX 文件时,matlabroot/simulink/include/simstruc.h 将包括下面头 文件: Header File Description matlabroot/extern/include/tmwtypes.h General data types, e.g., real_T matlabroot/extern/include/mex.h MATLAB MEX-file API routines matlabroot/extern/include/matrix.h MATLAB MEX-file API routines 当被编译为 MEX 文件时,matlabroot/simulink/include/simstruc.h 将包括下面头文 件: Header File Description matlabroot/extern/include/tmwtypes.h General types, e.g., real_T matlabroot/rtw/c/libsrc/rt_matrx.h Macros for MATLAB API routines 用户 C MEX S-function 文件尾部必须包括下面声明: #ifdef MATLAB_MEX_FILE /* Is this being compiled as MEX-file? */ #include "simulink.c" /* MEX-file interface mechanism */ #else #include "cg_sfun.h" /* Code generation registration func */ #endif 这些声明确保针对用户具体应用选择适当的代码: ● 当被编译为 MEX 文件的时候,simulink.c 文件将被包含。 ● 当被编译为关联了实时工具箱(Real-Time Workshop)的独立程序时, cg_sfun.h 文件将被包含。 SimStruct 结构
分享到:
收藏