主要内容

内联C墨西哥人S-Functions

内联函数概述

当一个模型万博1manbetx®模型包含一个功能和相应的TLC块目标文件存在s函数,代码生成器内联函数。内联函数可以生成更高效的代码通过消除s函数生成的代码的API层。

S-functions,可以执行各种任务,内联他们给了你机会来生成代码只对当前的操作模式设置为每个块的实例。作为一个例子,如果一个函数接受任意信号宽度和遍历每个元素的信号,你想生成内联代码循环信号有两个或两个以上的元素,但生成一个简单nonlooped计算当信号只有一个元素。

级别1 C墨西哥人S-functions(写一个旧形式的s函数API)不内联导致生成的代码会调用这些函数,即使常规为特定功能是空的。

函数 目的

mdlInitializeSizes

初始化数组大小

mdlInitializeSampleTimes

数组初始化样本倍

mdlInitializeConditions

初始化状态

mdlOutputs

计算输出

mdlUpdate

更新离散状态

mdlDerivatives

计算连续状态的衍生品

mdlTerminate

清理在仿真终止时

级别2 C墨西哥人S-functions(即。,those written to the current S-function API) that are not inlined make calls to the above functions, with the following exceptions:

  • mdlInitializeConditions就是只有MDL_INITIALIZE_CONDITIONS宣布与#定义

  • mdlStart就是只有MDL_START宣布与#定义

  • mdlUpdate就是只有MDL_UPDATE宣布与#定义

  • mdlDerivatives就是只有MDL_DERIVATIVES宣布与#定义

通过内联函数,可以消除这些可能空函数的调用仿真循环。这可以极大地提高生成的代码的效率。

内联函数的调用sfunc_name,你创建一个自定义功能块目标文件sfunc_name.tlc在相同的文件夹中,并将其功能MEX-file。然后,在构建时,目标文件执行,而不是设置函数调用功能。c文件。“内联”功能的功能目标文件指导目标语言编译器插入的语句在目标文件中定义的。

一般来说,内联函数时尤其有用

  • 所需的时间来执行功能的内容相比,所需的开销小,调用函数。

  • 某些功能的例程是空的(例如,mdlUpdate)。

  • 的行为功能改变之间的模拟和代码生成。例如,设备驱动程序I / O S-functions可能从MATLAB读取®在模拟工作空间,但从一个实际的硬件地址在生成的代码中。

功能参数

一个函数可以写为两种不同类型的参数模型.rtw申请目标语言编译器文件访问:

  • 参数设置:这些对应nontunable参数(通常是蒙面设置复选框和菜单功能),通过编写的mdlRTW函数的使用方法ssWriteRTWParamSettings。s函数的TLC实现文件可以直接访问这些参数设置的值的SFcnParamSettings记录。

  • 参数可调参数:这个类可以访问时登记为在函数运行时参数。请注意,这些可调参数自动写入模型.rtw文件。在TLC文件功能,您可以访问运行时使用的参数和它们的属性LibBlockParameter库函数和它的变体。

有关如何创建和使用的更多信息运行时参数,看看创建和更新功能运行时参数。也看到的例子sfcndemo_runtime如何创建和使用函数例子的两类参数。源文件的例子中,您可以检查和调整

  • 工具箱/模型/ 万博1manbetxsimdemos / simfeatures / src /sfun_runtime1.c

  • 工具箱/模型/ 万博1manbetxsimdemos / simfeatures / tlc_c /sfun_runtime1.tlc

  • 工具箱/模型/ 万博1manbetxsimdemos / simfeatures / src /sfun_runtime2.c

  • 工具箱/模型/ 万博1manbetxsimdemos / simfeatures / tlc_c /sfun_runtime2.tlc

  • 工具箱/模型/ 万博1manbetxsimdemos / simfeatures / src /sfun_runtime3.c

  • 工具箱/模型/ 万博1manbetxsimdemos / simfeatures / tlc_c /sfun_runtime3.tlc

功能的示例代码

假设你有一个简单的函数,模拟获得的块,用一个输入,一个输出,一个标量。也就是说,y = u * p。如果模型块的名万博1manbetx字喷火级别2 s函数的名称foogain墨西哥人,C s函数必须包含这个代码:

#定义S_FUNCTION_NAME foogain # define S_FUNCTION_LEVEL 2 #包括“simstruc。h”#定义获得mxGetPr (ssGetSFcnParam(年代,0))[0]静态空mdlInitializeSizes (SimStruct * S) {ssSetNumContStates (S, 0);ssSetNumDiscStates (S, 0);如果(!ssSetNumInputPorts(年代,1))返回;ssSetInputPortWidth (0, 1);ssSetInputPortDirectFeedThrough (0, 1);如果(!ssSetNumOutputPorts(年代,1))返回;ssSetOutputPortWidth (0, 1); ssSetNumSFcnParams (S, 1); ssSetNumSampleTimes (S, 0); ssSetNumIWork (S, 0); ssSetNumRWork (S, 0); ssSetNumPWork (S, 0); } static void mdlOutputs(SimStruct *S, int_T tid) { real_T *y = ssGetOutputPortRealSignal(S, 0); const InputRealPtrsType u = ssGetInputPortRealSignalPtrs(S, 0); y[0] = (*u)[0] * GAIN; } static void mdlInitializeSampleTimes(SimStruct *S){} static void mdlTerminate(SimStruct *S) {} #define MDL_RTW /* Change to #undef to remove function */ #if defined(MDL_RTW)&&(defined(MATLAB_MEX_FILE)||defined(NRT)) static void mdlRTW (SimStruct *S) { if (!ssWriteRTWParameters(S, 1,SSWRITE_VALUE_VECT,"Gain","", mxGetPr(ssGetSFcnParam(S,0)),1)) { return; } } #endif #ifdef MATLAB_MEX_FILE #include "simulink.c" #else #include "cg_sfun.h" #endif

以下两个部分显示在生成的代码的区别模型。c包含noninlined和内联版本的功能foogain。模型不包含其他仿真软件模块。万博1manbetx

有关这些功能相关的C库函数的更多信息,参见配置C / c++函数特性。如何生成代码的信息,请参阅配置模型和生成代码方法从模型生成的代码构建模型万博1manbetx

比较model.c Noninlined和内联的版本

没有TLC文件定义功能细节,代码生成器必须调用MEX-file s函数通过函数API。下面的代码是模型。c文件noninlined s函数(即。不存在对应的TLC文件)。

Noninlined s函数

/ * *模型. c。* / real_T untitled_RGND = 0.0;/ * real_T地面* / / * * /启动模型空白MdlStart (void){/ *(不需要启动代码)* /}* / / *计算块输出无效MdlOutputs (int_T tid){/ *二级功能块:< Root > / s函数(foogain) * / {SimStruct * rts = ssGetSFunction (rts, 0);sfcnOutputs (rts, tid);}}/ *执行模型更新* /空白MdlUpdate (int_T tid){/ *(不需要更新代码)* /}/ * * /终止函数void MdlTerminate (void){/ *二级功能块:< Root > / s函数(foogain) * / {SimStruct * rts = ssGetSFunction (rts, 0);sfcnTerminate (rts);}}#包括“模型_reg.h" /* [EOF]模型c * /

内联函数。这段代码是模型。cfoogain功能完全内联:

/ * *模型. c。* / / *启动模式* /空白MdlStart (void){/ *(不需要启动代码)* /}* / / *计算块输出无效MdlOutputs (int_T tid) / *功能块:< Root > / s函数* / / *注意:没有调用函数内联版本的API模型. c。* / rtB。S_Function = 0.0 * rtP.S_Function_Gain;}/ *执行模型更新* /空白MdlUpdate (int_T tid){/ *(不需要更新代码)* /}* / / *终止函数void MdlTerminate (void){/ *(不需要终止代码)* /}#包括“模型_reg.h" /* [EOF]模型c * /

如果你为这个功能块包括这个目标文件,由此产生的模型。c代码是

rtB。S_Function = 0.0 * rtP.S_Function_Gain;

包括薄层色谱文件大大减少代码的大小和生成的代码的执行效率增加。这些笔记介绍一些信息TLC代码和生成的输出:

  • TLC指令%实现是块所需的目标文件,必须目标文件中的第一个可执行语句块。这个指令可以防止目标语言编译器执行功能的不恰当的目标文件foogain

  • 的输入喷火rtGROUND(一个万博1manbetx仿真软件编码器™因为全球= 0.0)喷火是唯一一块模型,其输入是无关的。

  • 包括薄层色谱文件foogain不需要登记功能段foogain。这会显著减少代码的大小。

  • TLC代码内联获得构建过程时参数配置为内联参数值。例如,如果s函数参数被指定为2.5 s函数对话框中,薄层色谱输出函数生成

    rtB。喷火= input * 2.5;
  • 使用% generatefile指示如果你的操作系统有文件大小限制和s函数的名称foosfunction(超过极限)。在这种情况下,您将包括以下语句系统中的目标文件(参考之前到这个功能块目标文件)。

    % generatefile foosfunction“foosfunc.tlc”

    这句话告诉目标语言编译器打开foosfunc.tlc而不是foosfunction.tlc

比较model_reg.h Noninlined和内联的版本

内联一个二级功能显著减少的大小模型_reg.h代码。模型注册功能是漫长的;这个例子中的代码已被消灭的。下面的代码强调noninlined和内联的版本之间的区别模型_reg.h;内联消除这段代码:

/ * *模型_reg.h* */ /* Normal model initialization code independent of S-functions */ /* child S-Function registration */ ssSetNumSFunctions(rtS, 1); /* register each child */ { static SimStruct childSFunctions[1]; static SimStruct *childSFunctionPtrs[1]; (void)memset((char_T *)&childSFunctions[0], 0, sizeof(childSFunctions)); ssSetSFunctions(rtS, &childSFunctionPtrs[0]); { int_T i; for(i = 0; i < 1; i++) { ssSetSFunction(rtS, i, &childSFunctions[i]); } } /* Level2 S-Function Block: untitled//S-Function (foogain) */ { extern void foogain(SimStruct *rts); SimStruct *rts = ssGetSFunction(rtS, 0); /* timing info */ static time_T sfcnPeriod[1]; static time_T sfcnOffset[1]; static int_T sfcnTsMap[1]; { int_T i; for(i = 0; i < 1; i++) { sfcnPeriod[i] = sfcnOffset[i] = 0.0; } } ssSetSampleTimePtr(rts, &sfcnPeriod[0]); ssSetOffsetTimePtr(rts, &sfcnOffset[0]); ssSetSampleTimeTaskIDPtr(rts, sfcnTsMap); ssSetMdlInfoPtr(rts, ssGetMdlInfoPtr(rtS)); /* inputs */ { static struct _ssPortInputs inputPortInfo[1]; _ssSetNumInputPorts(rts, 1); ssSetPortInfoForInputs(rts, &inputPortInfo[0]); /* port 0 */ { static real_T const *sfcnUPtrs[1]; sfcnUPtrs[0] = &untitled_RGND; ssSetInputPortWidth(rts, 0, 1); ssSetInputPortSignalPtrs(rts, 0, (InputPtrsType)&sfcnUPtrs[0]); } } /* outputs */ { static struct _ssPortOutputs outputPortInfo[1]; _ssSetNumOutputPorts(rts, 1); ssSetPortInfoForOutputs(rts, &outputPortInfo[0]); ssSetOutputPortWidth(rts, 0, 1); ssSetOutputPortSignal(rts, 0, &rtB.S_Function); } /* path info */ ssSetModelName(rts, "S-Function"); ssSetPath(rts, "untitled/S-Function"); ssSetParentSS(rts, rtS); ssSetRootSS(rts, ssGetRootSS(rtS)); ssSetVersion(rts, SIMSTRUCT_VERSION_LEVEL2); /* parameters */ { static mxArray const *sfcnParams[1]; ssSetSFcnParamsCount(rts, 1); ssSetSFcnParamsPtr(rts, &sfcnParams[0]); ssSetSFcnParam(rts, 0, &rtP.S_Function_P1Size[0]); } /* registration */ foogain(rts); sfcnInitializeSizes(rts); sfcnInitializeSampleTimes(rts); /* adjust sample time */ ssSetSampleTime(rts, 0, 0.2); ssSetOffsetTime(rts, 0, 0.0); sfcnTsMap[0] = 0; /* Update the InputPortReusable and BufferDstPort flags for each input port */ ssSetInputPortReusable(rts, 0, 0); ssSetInputPortBufferDstPort(rts, 0, -1); /* Update the OutputPortReusable flag of each output port */ } }

薄层色谱文件内联函数foogain

避免不必要的调用功能,生成所需的最小代码功能,下面的TLC文件,foogain.tlc作为一个示例。

%实现“foogain”“C”%函数输出(块,系统)输出/ * % <类型>块:% <名称> * / % % %分配y = LibBlockOutputSignal(0,”“、”“0) %分配u = LibBlockInputSignal(0,”“、”“0) %分配p = LibBlockParameter(收益,”“、”“0)% < y > = % * % < p > <你>;% endfunction

实例数据块管理着眼于代码生成

实例数据是额外的数据或工作记忆,是独一无二的每个实例一个街区的仿真软件模型。万博1manbetx这并不包括参数或状态数据(存储在模型参数和状态向量,分别),而是用来缓存中间结果或派生的表征参数和模式。实例数据的一个例子是使用的缓冲区传输延迟。

分配和使用内存的访问权可以多种方式完成二级功能:通过ssSetUserData、工作向量(例如,ssSetRWorkValue,ssSetIWorkValue),或者称为向量数据类型工作DWork向量。最小的努力写作的功能和目标文件和自动静态和一致性malloc实例数据等目标写作时,使用向量数据类型工作S-functions与实例数据。

优点是双重的。首先,编写功能更简单,内存分配和释放是由仿真软件为你处理。万博1manbetx第二,DWork向量是书面的模型.rtw为您自动文件,包括DWork名称、数据类型和大小。这使得写块目标文件更容易,因为你不需要写TLC代码分配和释放DWork内存。

此外,如果你想包组DWork向量结构传递函数,你可以用指针填充结构DWork在你的s函数数组mdlStart功能和目标文件块的开始方法,实现功能之间的一致性和生成的代码的处理数据。

最后,用一个DWork使它简单的创建一个特定版本的代码(数据类型,标量与矢量化等)为每个功能块实例匹配的实现。两个实现使用DWork以同样的方式,这样可以使用内联代码万博1manbetx仿真软件加速器™软件没有改变C墨西哥人s函数或块的目标文件。

使用内联代码万博1manbetx加速器软件

默认情况下,万博1manbetx仿真软件加速器软件调用C墨西哥人s函数作为一个加速模型模拟的一部分。如果你喜欢有加速器内联函数在运行加速模型之前,告诉加速器使用你块内联函数与目标文件SS_OPTION_USE_TLC_WITH_ACCELERATOR国旗的调用ssSetOptions ()mdlInitializeSizes函数的功能。

注意,内存和工作矢量的大小和使用必须相同的TLC生成的代码和C墨西哥人s函数,或万博1manbetx仿真软件加速器软件不能正常执行内联代码。这是因为C墨西哥人s函数叫做初始化块及其工作向量,调用mdlInitializeSizes,mdlInitializeConditions,mdlCheckParameters,mdlProcessParameters,mdlStart功能。在恒定的信号传播的情况下,mdlOutputs从C墨西哥人被称为s函数在初始化阶段的模型执行。

加速模型的时域阶段执行,生成的代码输出更新块薄层色谱方法将执行,加上衍生品如果它们存在和零交点的方法。的开始方法的目标文件不是用于生成代码块的加速模型。

相关的话题