文档

手工编写功能和TLC文件

你可以选择几种方法手工编写功能和TLC文件。

写Noninlined s函数和TLC文件

关于Noninlined S-Functions

Noninlined S-functions是确定的没有一个sfunction.tlc文件的功能。文件名要取决于您的平台。例如,在一个64位的微软®窗户®系统,文件名称sfunctionmexw64。类型mexext在MATLAB®命令窗口看到哪些扩展你的系统使用。

写作指南Noninlined S-Functions

  • MEX-file不能调用MATLAB函数。

  • 如果MEX-file使用在MATLAB外部接口函数库,包括头文件cg_sfun.h而不是mex.h万博1manbetxsimulink.c。来处理这种情况,包括以下行结束时你的s函数:

    # ifdef MATLAB_MEX_FILE / *文件被编译为一个MEX-file吗?* / # include万博1manbetx”模型。c / * MEX-file接口机制* /其他# #包括“cg_sfun。h " / * * / # endif登记代码生成功能
  • 只使用MATLAB代码生成器支持API函数,其中包括:万博1manbetx

    mxGetEps
    mxGetInf
    mxGetM
    mxGetN
    mxGetNaN
    mxGetPr
    mxGetScalar
    mxGetString
    mxIsEmpty
    mxIsFinite
    mxIsInf
  • 墨西哥人不支持库调用生成的代码。万博1manbetx使用这样的呼吁在MEX-file而不是在生成的代码中,conditionalize代码如下:

    # ifdef MATLAB_MEX_FILE # endif
  • 只使用完整的包含唯一真正的数据矩阵。

  • 没有指定调用的返回值吗mxGetString。如果你指定一个返回值,MEX-file不会编译。相反,使用该函数的第二个输入参数,返回一个指针指向一个特征向量。

  • 确保#定义s-function_name声明是正确的。您所指定的函数名称必须匹配功能的文件名。

  • 使用的数据类型real_Tint_T而不是int(如果可能的话)。的数据类型real_Tint_T更通用的,可以在多个环境中使用。

  • 为构建过程提供模块用于构建s函数的名称。你可以通过使用一个模板文件,set_param函数,或功能模块场的功能块参数对话框。例如,假设您构建您的s函数使用下面的命令:

    墨西哥人sfun_main。c sfun_module1。c sfun_module2.c

    然后,您可以使用下面的调用set_param包括所需的模块:

    set_param (sfun_block“SFunctionModules”、“sfun_module1 sfun_module2”)

    当你准备来生成代码,代码生成器力量重建模型顶部,解释控制再生的模型代码

Noninlined s函数参数类型的限制

参数noninlined S-functions只能是以下类型:

  • 双精度

  • 字符在标量、向量或二维矩阵

更灵活的类型参数可以供应S-functions或操作功能,内联函数,考虑使用一个mdlRTW功能程序。

使用MATLAB的其他功能matrix.hAPI或其他MATLAB API,如mex.hmat.h,不支持。万博1manbetx如果你叫不受支持的api函数万博1manbetx的源文件,编译器错误发生。看到这些文件matlabroot/ rtw / c / src /rt_matrx.hmatlabroot/ rtw / c / src /rt_matrx.c有关支持MATLAB API函万博1manbetx数。

如果你使用mxGetPr在一个空的矩阵,这个函数不返回;相反,它返回一个随机值。因此,你应该保护的呼声mxGetPrmxIsEmpty

编写包装功能和TLC文件

本主题描述如何创建S-functions与仿真软件无缝工作万博1manbetx®和代码生成器使用的产品s manbetx 845包装器的概念。这个话题首先描述如何接口算法在仿真软件模型通过编写墨西哥人s函数包装器(万博1manbetxsfunction.mex)。它完成的描述如何直接插入你的算法的代码生成器生成的代码通过创建一个TLC s函数包装器(sfunction.tlc)。

墨西哥人s函数包装器

使用一个s函数包装器允许您创建S-functions C / c++代码插入算法仿真软件模型和生成的代码与很少或没有改变原来的C / c++函数。万博1manbetx一个墨西哥人s函数包装器是一个函数,调用驻留在另一个模块的代码。一个TLC s函数包装器是一个薄层色谱文件,指定代码生成器应该如何调用您的代码(相同的代码,从C墨西哥人被称为s函数包装器)。

请注意

一个墨西哥人s函数包装器必须在MATLAB版本只用于创建包装器。

假设您有一个算法(即一个C函数)调用my_alg驻留在文件my_alg.c。你可以集成my_alg为仿真软件模型万博1manbetx通过创建一个墨西哥人s函数包装器(例如,wrapsfcn.c)。一旦做出了选择,可以调用仿真软件模型万博1manbetxmy_alg从一个功能块。然而,仿真软件功能包含一组万博1manbetx空函数,仿真软件引擎需要各种API-related目的。例如,尽管只有mdlOutputs调用my_alg,引擎调用mdlTerminate,尽管这功能程序执行任何行动。

你可以集成my_alg在生成的代码(即嵌入调用my_alg在生成的代码)通过创建一个TLC s函数包装器(例如,wrapsfcn.tlc)。创建一个TLC s函数包装器的优点是空函数调用可以消除和执行的开销mdlOutputs函数,然后my_alg函数可以被消除。

包装S-functions是有用的,当你创建新的算法过程的性质或当你将遗留代码集成到一个仿真软件模型。万博1manbetx然而,如果您想要创建的代码

  • 解释在本质上(即高度参数化操作模式)

  • 大量优化(即,没有额外的测试来决定什么模式的代码操作)

然后您必须创建一个完全内联TLC文件你的功能。

下一个图显示包装器函数的概念。

使用一个函数包装器进口算法在仿真软件模型意味着s函数作为一个接口,调用你的C / c++算法万博1manbetxmdlOutputs。s函数包装器的优势,您可以快速将大型独立的C / c++程序集成到您的模型,而无需更改代码。

下面的示例模型包括一个s函数包装器。

有两个相关的文件wrapsfcn块,s函数包装器和C / c++代码包含算法。的s函数包装器代码wrapsfcn.c下面出现。第一个三条语句执行以下操作:

  1. 定义了函数的名称(输入什么仿真软件功能块对话框)。万博1manbetx

  2. 指定函数使用级别2的格式。

  3. 提供了访问SimStruct期间使用的数据结构,其中包含指针数据模拟和代码生成和定义了宏,数据存储和检索数据SimStruct

有关更多信息,请参见模板C S-Functions(万博1manbetx模型)。

#定义S_FUNCTION_NAME wrapsfcn # define S_FUNCTION_LEVEL 2 #包括“simstruc。h”走读生real_T my_alg (real_T u);/ *声明my_alg走读生* // * * mdlInitializeSizes -初始化数组大小* /静态孔隙mdlInitializeSizes (SimStruct * S) {ssSetNumSFcnParams (S, 0);/ *输入参数数量* /如果!ssSetNumInputPorts(年代,1))返回;ssSetInputPortWidth (0, 1);ssSetInputPortDirectFeedThrough (0, 1);如果(! ssSetNumOutputPorts(年代,1))返回;ssSetOutputPortWidth (0, 1);ssSetNumSampleTimes (S, 1);}/ * * mdlInitializeSampleTimes -表明该功能运行的速度*源(驱动块)* /静态孔隙mdlInitializeSampleTimes (SimStruct * S) {ssSetSampleTime(年代,0,INHERITED_SAMPLE_TIME);ssSetOffsetTime(年代,0,0.0);}/ * * mdlOutputs——计算输出通过调用my_alg *驻留在另一个模块,my_alg。c * / static void mdlOutputs(SimStruct *S, int_T tid) { InputRealPtrsType uPtrs = ssGetInputPortRealSignalPtrs(S,0); real_T *y = ssGetOutputPortRealSignal(S,0); *y = my_alg(*uPtrs[0]);/ *调用my_alg mdlOutputs * /}/ * * mdlTerminate——模拟时终止。* /静态孔隙mdlTerminate (SimStruct * S) {} # ifdef MATLAB_MEX_FILE / *文件被编译为一个MEX-file吗?* / # include万博1manbetx”模型。c / * MEX-file接口机制* /其他# #包括“cg_sfun。h " / * * / # endif登记代码生成功能

功能的例程mdlOutputs包含一个函数调用my_alg,这是包含算法的C函数,函数执行。这是代码my_alg.c:

# ifdef MATLAB_MEX_FILE tmwtypes # include”。h rtwtypes其他# # include。h”# endif real_T my_alg (real_T u){返回(u * 2.0);}

有关更多信息,请参见构建过程管理文件的依赖关系

包装器函数wrapsfcn调用my_alg,计算u * 2.0。构建wrapsfcn.mex使用以下命令:

墨西哥人wrapsfcn。c my_alg.c

TLC s函数包装器

这个主题描述了如何内联调用my_algmdlOutputs生成的代码。在上面的示例中,调用my_alg是嵌在mdlOutputs节,

* y = my_alg (* uPtrs [0]);

当你创建一个TLC s函数包装器,我们的目标是将相同类型的调用嵌入到生成的代码。

看看代码生成器是指导执行S-functions不内联。一个noninlined功能是没有确认的文件sfunction.tlc和的存在sfunction.mex。当生成代码noninlined s函数,代码生成器生成调用mdlOutputs通过一个函数指针,在这个例子中,然后调用my_alg

包装器示例包含一个函数,wrapsfcn.mex。你必须编译和链接一个额外的模块,my_alg,生成的代码。要做到这一点,指定

set_param(“包装/ s函数”、“SFunctionModules”,“my_alg”)

代码开销Noninlined S-Functions

当使用生成的代码grt.tlc随着系统的目标文件没有wrapsfcn.tlc

<为包装器模型生成的代码注释noninlinedwrapsfcn功能> # include <数学。h > # include <字符串。h > # include“包装器。h”# include“包装器。人口、难民和移民事务局“/ *启动模式* /空白mdlStart (void){/ *(启动代码不需要)* /}* / / *计算块输出无效mdlOutputs (int_T tid){/ *罪:< Root > / * / rtB的罪。罪= rtP.Sin。一个mplitude * sin(rtP.Sin.Frequency * ssGetT(rtS) + rtP.Sin.Phase); /* Level2 S-Function Block: /S-Function (wrapsfcn) */ {/ * Noninlined S-functions创建SimStruct对象和*生成调用功能常规mdlOutputs * /SimStruct * rts = ssGetSFunction (rts, 0);sfcnOutputs (rts, tid);}/ *外港布洛克:< Root > / * /而无。= rtB.S_Function;}/ *执行模型更新* /空白mdlUpdate (int_T tid){/ *(更新代码不需要)* /}/ * * /终止函数void mdlTerminate (void){/ *二级功能块:< Root > / s函数(wrapsfcn) * / {/ * Noninlined S-functions需要SimStruct对象和* s函数调用例程mdlTerminate * /SimStruct * rts = ssGetSFunction (rts, 0);sfcnTerminate (rts);}}# include“包装器。注册“/ * (EOF)包装。c * /

除了上面列出的开销,wrapper.reg生成的文件包含的初始化SimStruct包装的功能块。有一个孩子SimStruct模型中每个功能块。通过创建一个可以显著减少开销TLC s函数的包装器。

如何内联

生成的代码调用你的函数,wrapsfcn.c,在mdlOutputs通过使用这段代码:

SimStruct * rts = ssGetSFunction (rts, 0);sfcnOutputs (rts, tid);

这叫有与之关联的计算开销。首先,仿真软件引擎创建万博1manbetx一个SimStruct功能块的数据结构。第二,代码生成器构造调用通过一个函数指针来执行mdlOutputs,然后mdlOutputs调用my_alg。通过内联调用C / c++算法,my_alg,你可以消除的SimStruct和额外的函数调用,从而提高效率和减少生成的代码的大小。

内联一个包装器函数需要一个sfunction.tlc文件功能(参见目标语言编译器详情)。薄层色谱文件必须包含的函数调用my_alg。下面的图显示了算法之间的关系,包装器函数,sfunction.tlc文件。

内联这个电话,你必须把你的函数调用的sfunction.tlc文件名称相同的功能(在这个例子中,wrapsfcn.tlc)。这将导致目标语言的编译器来覆盖默认的方法将调用你的函数生成的代码。

这是wrapsfcn.tlc文件,内联wrapsfcn.c

% %文件:wrapsfcn。tlc % %文摘:% % s函数内联tlc文件例子wrapsfcn。c % % %实现“wrapsfcn”“c”% %功能:BlockTypeSetup = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = % %文摘:% %在模型创建函数原型。h: % %”走读生real_T my_alg (real_T u);“%% %function BlockTypeSetup(block, system) void %openfile buffer extern real_T my_alg(real_T u);/ *这条线是放置在包装。h * /% closefile缓冲% < LibCacheFunctionPrototype(缓冲区)> % endfunction % % BlockTypeSetup % %功能:输出= = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = % %文摘:% % y = my_alg (u);% % %函数输出(块,系统)输出/ * % <类型>块:% <名称> * / %分配u = LibBlockInputSignal(0,”“、”“0) %分配y = LibBlockOutputSignal(0,”“、”“0) % %提供声明中呼吁“算法”% %以下线是扩大和放置在mdlOutputs wrapper.c之内% < y > = my_alg (% < u >);% endfunction % %输出

这段代码内联的第一部分wrapsfcn功能块中的代码并生成C:

%实现“wrapsfcn”“C”

下一个任务是告诉代码生成器my_alg需要声明外部生成的wrapper.h申请任何wrapsfcn在模型中功能块。你只需要做这一次wrapsfcn功能块,所以使用BlockTypeSetup函数。在这个函数中,你告诉目标语言编译器创建一个缓冲区和缓存my_alg作为走读生wrapper.h生成的头文件。

最后一步是调用的内联函数my_alg。这是做的输出函数。在这个功能中,您访问块的输入和输出,并将直接调用my_alg。调用嵌入wrapper.c

内联代码

当你内联包装器函数所生成的代码类似于默认生成的代码。的mdlTerminate不包含函数调用和一个空的函数mdlOutputs现在函数直接调用my_alg

空白mdlOutputs (int_T tid){/ *罪:< Root > / * / rtB的罪。罪= rtP.Sin。一个mplitude * sin(rtP.Sin.Frequency * ssGetT(rtS) + rtP.Sin.Phase); /* S-Function Block: /S-Function */ rtB.S_Function = my_alg(rtB.Sin);/ *内联调用my_alg * // *外港块:< Root > / * /而无。= rtB.S_Function;}

此外,wrapper.reg不创建一个孩子SimStruct的功能,因为生成的代码调用my_alg直接。这就消除了超过1 KB的内存使用。

写完全内联S-Functions

使用的例子编写包装功能和TLC文件,你可以消除调用my_alg完全由指定明确的代码(即2.0 * u)wrapsfcn.tlc。这是被称为完全内联函数。虽然这可以提高性能,如果你是使用大量的C / c++代码,这可能是一个冗长的任务。此外,你现在必须保持算法在两个地方,C / c++函数本身和相应的TLC文件。然而,性能提升可能利大于弊。内联在这个示例中,使用的算法输出你的节wrapsfcn.tlc文件,而不是写作

% < y > = my_alg (% < u >);

使用

% < y > = 2.0 * % < u >;

这是生产的代码mdlOutputs:

空白mdlOutputs (int_T tid){/ *罪:< Root > / * / rtB的罪。罪= rtP.Sin。一个mplitude * sin(rtP.Sin.Frequency * ssGetT(rtS) + rtP.Sin.Phase); /* S-Function Block: /S-Function */ rtB.S_Function = 2.0 * rtB.Sin;/ * * /明确的嵌入算法/ *外港块:< Root > / * /而无。= rtB.S_Function;}

目标语言编译器取代了电话my_alg算法本身。

多端口的功能

更先进的多端口内联函数的例子sfun_multiport.csfun_multiport.tlc。这个功能演示了如何创建一个完全内联TLC文件为一个包含多个端口的功能。你会发现看这个例子能帮助你充分理解内联TLC文件。

写完全内联S-Functions mdlRTW例程

你可以内联更加复杂S-functions使用功能mdlRTW例行公事。的目的mdlRTW例程为代码生成过程提供更多的信息关于s函数内联,通过创建一个参数的记录nontunable参数用TLC文件。的mdlRTW程序通过将信息模型.rtw文件。的mdlRTW函数是描述的文本文件matlabroot/万博1manbetx模型/ src /sfuntmpl_doc.c

作为一个如何使用的例子mdlRTW函数,这个话题讨论你必须采取的步骤,以创建一个直接索引查找功能。查找表的有序数据点集合的一个函数。通常,这些表使用一些近似插值方案之间的关联函数值已知的数据点。将查找表算法为仿真软件模型的例子中,第一步是编写一个函数,执行算法万博1manbetxmdlOutputs。产生最有效的代码,下一步是创建一个相应的TLC文件消除计算开销和提高查找的速度计算。

为了方便,仿真软件产品支持两个通用查询一维,二维算法万博1manbetx。万博1manbetx您可以使用这些算法或创建一个自定义查找表功能以适应您的需求。这一主题演示如何创建一个一维查找功能,sfun_directlook.c,及其相应的内联sfun_directlook.tlc文件(见目标语言编译器更多的细节)。这一维直接索引查找表的例子说明了以下概念,你需要知道创建自己的自定义查找表:

  • 错误检查功能参数

  • 缓存信息的功能,不改变模型执行期间

  • 如何使用mdlRTW功能定制代码生成器生成最优代码对于一个给定的块参数集

  • 如何生成一个内联吗薄层色谱文件的组合完全内联的函数形式和/或包装形式

s函数RTWdata

有一个块的属性RTWdata,可以使用目标语言编译器内联函数时。RTWdata是特征向量的结构,您可以附加到一个街区。它保存了模型和放置在模型.rtw文件在生成代码。例如,这组MATLAB命令,

mydata。field1 field1 = '信息';mydata。field2 field2 = '信息';set_param (gcb RTWdata, mydata) get_param (gcb, RTWdata)

产生这一结果:

ans = field1:“信息field1的field2:“field2信息”

模型.rtw文件关联功能块这个信息。

块{类型“功能”RTWdata {field1 field1“信息”field2 field2“信息”}

请注意

RTWdata保存在模型文件S-functions不与一个图书馆。然而,RTWdata不持久与图书馆的功能块。

直接索引查找表算法

模型库中提供的一维查找表块时使用内插或外推法计算输出。万博1manbetx这种额外的准确性可能不是必需的。在本例中,您创建一个查找表,直接索引输出向量(y拼向量)基于当前输入(x拼点。

这种直接一维查找例子计算一个近似解p (x)部分已知函数f (x)x = x0给定数据点对(x, y)的形式x拼向量和一个y拼向量。对于一个给定的数据(例如,i两人),y_i = f (x_i)。它是假定x拼值是单调递增的。如果x0范围以外的吗x拼向量,返回第一或最后一点。

函数的参数

XData、YData XEvenlySpaced

XDataYData是双向量相等的长度代表未知函数的值。XDataEvenlySpaced是一个标量,0.0假和1.0为真实的。如果XData向量是均匀间隔的,XDataEvenlySpaced1.0和生成更高效的代码。

下面的图显示了参数XData = [1:6]YData = [1、2、7、4、5、9)处理。例如,如果输入(x值)功能块是3,输出(y值)7。

直接索引查找表的例子

这一主题展示了如何提高查找表通过内联直接索引与TLC文件功能。这直接索引查找表功能不需要TLC文件。这里的示例使用薄层色谱文件直接索引查找表功能来减少代码生成的代码的规模和提高效率。

与内联TLC文件直接索引算法的实现要求功能主模块,sfun_directlook.c和相应的lookup_index.c模块。的lookup_index.c模块包含GetDirectLookupIndex函数是用来定位的指数XData对当前x输入值时XData间隔是不均匀的。的GetDirectLookupIndex例程从功能和生成的代码。这里的示例使用包装器之间共享C / c++代码的概念模型mex files和生成的代码。万博1manbetx

如果XData是等间距的,那么这两个主要功能模块和生成的代码包含查找算法(不是调用算法)来计算y一个给定的值x值,因为该算法是短暂的。这说明了一个完全的使用内联函数生成优化的代码。

内联TLC文件sfun_directlook.tlc,用于执行一个包装器调用或最优嵌入C / c++代码的功能。(见中的示例mdlRTW用法)。

错误处理

sfun_directlook.tlc,mdlCheckParameters常规检查:

  • 新的参数设置是有效的。

  • XDataYData是向量包含真正的有限长度相同的数字。

  • XDataEvenlySpaced是一个标量。

  • XData向量是一个单调递增向量和等间距的。

mdlInitializeSizes函数显式地调用mdlCheckParameters验证后的参数传递给函数。在仿真软件引擎调用万博1manbetxmdlInitializeSizes,然后调用mdlCheckParameters当你改变参数或需要重新评估。

用户数据缓存

sfun_directlook.tlc,mdlStart程序显示了如何缓存信息,不会改变在模拟(或在生成的代码执行)。缓存的值的例子XDataEvenlySpaced参数用户数据的领域SimStruct。下面的行mdlInitializeSizes讲述了仿真软件引擎不万博1manbetx允许更改XDataEvenlySpaced

ssSetSFcnParamTunable (S iParam SS_PRM_NOT_TUNABLE);

在执行期间,mdlOutputs访问的价值XDataEvenlySpaced用户数据而不是打电话mxGetPrMATLAB API函数。

mdlRTW用法

代码生成器调用mdlRTW常规而生成模型.rtw文件。生产最优代码仿真软件模型,您可以添加信息万博1manbetx模型.rtw文件的功能块的操作模式。

下面的例子将参数设置添加到模型.rtw文件。在执行过程中不改变参数设置。在这种情况下,XDataEvenlySpaced功能参数不能改变执行期间(ssSetSFcnParamTunable被指定为false (0),在mdlInitializeSizes)。这个例子写出来作为一个参数设置(XSpacing)使用函数ssWriteRTWParamSettings

因为xDatayData注册为运行时参数吗mdlSetWorkWidths,代码生成器处理写的模型.rtw自动文件。

检查功能和内联TLC文件之前,考虑为以下模型生成的代码。

模型采用等间距的XData在功能块和不均匀间隔的XData在底部功能块。在创建这个模型时,您需要指定以下为每个功能块。

set_param (“sfun_directlook_ex / s函数”、“SFunctionModules”,“lookup_index”) set_param (‘sfun_directlook_ex / S-Function1’,‘SFunctionModules’,‘lookup_index’)

这通知构建过程使用模块lookup_index.c当创建可执行文件。

为这个模型生成代码时,代码生成器使用功能mdlRTW方法来生成一个模型.rtw文件的值EvenlySpacedXSpacing参数功能块,顶部和价值UnEvenlySpacedXSpacing参数功能块底部。TLC-file使用的价值XSpacing确定算法包括在生成的代码中。当生成的代码包含查找算法XData是等间距的,但是调用吗GetDirectLookupIndex常规的时XData间隔是不均匀的。生成的模型。c模型. cpp查找表的代码示例模型是类似如下:

/ * * sfun_directlook_ex。c * * *“sfun_directlook_ex万博1manbetx.slx”模型的代码生成模型。*……* / # include“sfun_directlook_ex。h sfun_directlook_ex_private # include。h " / *外部输出(根外港美联储通过信号自动存储)* / ExtY_sfun_directlook_ex_T sfun_directlook_ex_Y;/ * * /实时模型RT_MODEL_sfun_directlook_ex_T sfun_directlook_ex_M_;RT_MODEL_sfun_directlook_ex_T * const sfun_directlook_ex_M = &sfun_directlook_ex_M_;/ *模型输出函数* /空白sfun_directlook_ex_output (void){/ *本地块i / o变量* / real_T rtb_SFunction;real_T rtb_SFunction1; /* Sin: '/Sine Wave' */ rtb_SFunction1 = sin(sfun_directlook_ex_M->Timing.t[0]);/ *代码内联功能块顶部的* * / sfun_directlook_ex模型/ *功能(sfun_directlook):‘< Root > / s函数* / {const real_T * xData = sfun_directlook_ex_ConstP.SFunction_XData;const real_T * yData = sfun_directlook_ex_ConstP.SFunction_YData;real_T间距= xData [1]——xData [0];如果(rtb_SFunction1 < = xData [0]) {rtb_SFunction = yData [0];}else if (rtb_SFunction1 > = yData [20]) {rtb_SFunction = yData [20];其他}{int_T idx = (int_T) ((rtb_SFunction1 xData[0]) /间距);rtb_SFunction = yData [idx];}}/ *外港:< Root > /着干活的* / sfun_directlook_ex_Y。着干活= rtb_SFunction;/ *内联的代码的功能块底部* / * sfun_directlook_ex模型/ *功能(sfun_directlook):“< Root > / S-Function1”* / {const real_T * xData = sfun_directlook_ex_ConstP.SFunction1_XData;const real_T * yData = sfun_directlook_ex_ConstP.SFunction1_YData;int_T idx;idx = GetDirectLookupIndex (xData 5 rtb_SFunction1);rtb_SFunction1 = yData [idx];}/ *外港:“< Root > / Out2”* / sfun_directlook_ex_Y。Out2 = rtb_SFunction1;}/ *模型更新函数* /空白sfun_directlook_ex_update (void){/ *信号主要停止模拟* /{/ *样品时间:[0.0,0.0 s] * /如果((rtmGetTFinal (sfun_directlook_ex_M) ! = 1) & & ! ((rtmGetTFinal (sfun_directlook_ex_M) -sfun_directlook_ex_M - > Timing.t [0]) > sfun_directlook_ex_M - >时机。t [0] * (DBL_EPSILON))) {rtmSetErrorStatus (sfun_directlook_ex_M,“模拟完成”);}}/ *更新绝对时间为基准利率* / / *“clockTick0”项的次数这个任务的代码被执行。“clockTick0”的绝对时间是乘法*和“Timing.stepSize0”。大小的“clockTick0”确保计时器不会*溢出在应用程序生命周期选择。 * Timer of this task consists of two 32 bit unsigned integers. * The two integers represent the low bits Timing.clockTick0 and the high bits * Timing.clockTickH0. When the low bit overflows to 0, the high bits increment. */ if (!(++sfun_directlook_ex_M->Timing.clockTick0)) { ++sfun_directlook_ex_M->Timing.clockTickH0; } sfun_directlook_ex_M->Timing.t[0] = sfun_directlook_ex_M->Timing.clockTick0 * sfun_directlook_ex_M->Timing.stepSize0 + sfun_directlook_ex_M->Timing.clockTickH0 * sfun_directlook_ex_M->Timing.stepSize0 * 4294967296.0; } ...

编写内联S-Functions指南

  • 考虑使用块属性RTWdata(见s函数RTWdata)。这个属性是一个特征向量的结构,你可以联想到一块。代码生成器保存的模型结构模型.rtw文件,使.rtw文件可读性更强。例如,假设您在MATLAB命令窗口中输入以下命令:

    mydata。field1 field1 = '信息';mydata。field2 field2 = '信息';set_param (sfun_block, RTWdata, mydata);

    .rtw文件的代码生成器产生块包括注释中指定的结构mydata

  • 考虑使用mdlRTW函数内联C墨西哥人s函数生成的代码。当你想这是有用的

    • 在生成的代码中重命名可调参数

    • nontunable参数引入到TLC文件

折叠S-Functions支持表达万博1manbetx式

关于折叠S-Functions支持表达式万博1manbetx

这个主题描述了如何利用折叠增加效率的表达式自己内联函数所生成的代码块,通过调用宏功能提供的API。这个话题假定您熟悉:

s函数API允许您指定一个给定的功能块是否应该名义上接受表达式在给定的输入端口。一块不应该总是接受表达式。例如,如果使用地址信号的输入,输入表达式不应该接受,因为它是不可能的一个表达式的地址。

s函数API还允许您指定一个表达式是否能代表与一个给定的输出端口相关的计算。当你要求一个表达式在一块的输入或输出端口,仿真软件引擎决定了是否可以荣誉请求,鉴于块的上下文。万博1manbetx例如,发动机可能否认一个街区的要求输出表达式,如果目的地块不接受在其输入表达式,如果目的地块有一个更新函数,或如果存在多个输出目的地。

决定荣誉或拒绝一个请求的输出表达式也可以依赖于块输出表达式的类别使用(见类别的输出表达式)。

接下来的主题解释

  • 何时以及如何要求一块接受表达式的输入端口

  • 何时以及如何要求一块生成表达式输出港

  • 的条件模型引擎将荣誉或拒绝此类请求万博1manbetx

利用表达S-functions折叠,你应该明白什么时候请求接受为特定的块和一代的表情。你不需要理解的算法仿真软件引擎选择接受或拒绝这些请求。万博1manbetx然而,如果你想跟踪模型和生成的代码,它有助于理解的一些比较常见的情况,导致拒绝请求。

类别的输出表达式

当你实现一个C墨西哥人s函数,您可以指定是否对应的代码块的输出是生成一个表达式。如果块生成一个表达式,您必须指定表达式常数,微不足道的,或通用的

一个常数输出表达式直接访问块的一个参数。例如,恒定的输出块被定义为一个常数表达式,因为输出表达式只是一块直接访问的价值参数。

一个微不足道的输出表达式是一个表达式,可以重复,没有性能损失,当输出端口有多个输出目的地。例如,的输出单位延迟块定义为一个简单的表达式,因为输出表达式只是一块直接访问的状态。因为输出表达式没有计算,它可以重复多次没有降解生成的代码的性能。

一个通用的输出表达式是一个表达式,应该认为有性能损失如果重复。这样,一个通用的输出表达式时不适合重复输出端口有多个输出目的地。例如,和块的输出是一个通用的,而不是一个简单的表达式,因为它是昂贵的验算和块输出表达式作为输入多个块。

琐碎的和通用的输出表达式的例子。考虑下面的框图。延迟块有多个目的地,然而它的输出被指定为一个简单的输出表达式,以便它可以使用不止一次没有降低代码的效率。

下面的代码片段显示了生成的代码单位延迟块在这个框图。三根输出直接分配的状态单位延迟块,这是存储在一个全局数据结构的字段rtDWork。因为作业是直接,没有表情,没有性能损失与使用多个目的地的简单表达式。

空白MdlOutputs (int_T tid) {…/ *输出港:< Root > /着干活了:* UnitDelay: < Root > /单位* /而延迟。着干活= rtDWork.Unit_Delay_DSTATE;/ *输出港:< Root > / Out2包含:* UnitDelay: < Root > /单位* /而延迟。Out2 = rtDWork.Unit_Delay_DSTATE;/ *输出港:< Root > / Out3包含:* UnitDelay: < Root > /单位* /而延迟。Out3 = rtDWork.Unit_Delay_DSTATE;…}

另一方面,考虑和块以下模型:

上层块和在前面的模型生成标记信号non_triv。计算这个输出信号包括两个乘法和加法。如果允许和块的输出来生成一个表达式即使块有多个目的地,块的操作会在生成的代码重复。在插图中,生成的表达式将扩散四个乘法和两个补充。这将降低程序的效率。相应的输出和块不允许一个表达式,因为它有多个目的地

生成的代码生成前框图显示代码和街区与单个和多个目的地。

仿真软件万博1manbetx引擎不允许上和块的输出是一个表达式,因为这个信号non_triv被路由到两个输出目的地。相反,乘法和加法操作的结果存储在一个临时变量(rtb_non_triv)两次引用的语句,如下代码摘录中看到的一样。

相比之下,低和块,只有一个输出目的地(Out2),并生成一个表达式。

空白MdlOutputs (int_T tid){/ *本地块i / o变量* / real_T rtb_non_triv;real_T rtb_Sine_Wave;/ *金额:< Root > /金额包含:*获得:< Root > /获得*尺寸:< Root > / u1 *获得:< Root > / Gain1 *尺寸:< Root > / u2关于< Root > /增益:* * *获得价值:rtP。关于< Root > / Gain1 Gain_Gain * *: *增益值:rtP。Gain1_Gain * / rtb_non_triv = (rtP。Gain_Gain * rtU.u1) + (rtP。Gain1_Gain * rtU.u2);/ *输出港:< Root > /着干活* /而无。着干活= rtb_non_triv;/ *罪:< Root > /正弦波* / rtb_Sine_Wave = rtP。Sine_Wave_Amp * sin (rtP。Sine_Wave_Freq * rtmGetT (rtM_model) + rtP.Sine_Wave_Phase) + rtP.Sine_Wave_Bias;/ *输出港:< Root > / Out2包含:*金额:< Root > / Sum1 * /而无。Out2 = (rtb_non_triv + rtb_Sine_Wave);}

指定输出表达式的类别。功能的API提供了宏,让您声明一个块的输出是否应该一个表达式,如果是这样的话,指定表达式的类别。下面的表指定当宣布块输出是一个常数,琐碎,或通用的输出表达式。

类型的输出表达式

类别的表达式

什么时候使用

常数

使用只有块输出是一块直接内存访问参数。

微不足道的

使用只有块输出是一个表达式,可以出现多次在代码中没有减少效率(例如,一个直接内存访问的字段DWork向量,或文字)。

通用的

如果输出是一个表达式,但不是常数或微不足道的。

你必须声明输出的表达式mdlSetWorkWidths使用宏定义在函数API函数。宏有以下参数:

  • SimStruct *年代:块的指针SimStruct

  • int idx:输出端口的从零开始的索引。

  • bool值:通过真实如果端口生成输出表达式。

下面的宏可以设置一个输出是一个常数,琐碎,或通用表达式:

  • 空白ssSetOutputPortConstOutputExprInRTW (int idx SimStruct *年代,bool值)

  • 空白ssSetOutputPortTrivialOutputExprInRTW (int idx SimStruct *年代,bool值)

  • 空白ssSetOutputPortOutputExprInRTW (int idx SimStruct *年代,bool值)

以下宏用于查询之前设定的状态调用宏上图:

  • bool ssGetOutputPortConstOutputExprInRTW (SimStruct * S, int idx)

  • bool ssGetOutputPortTrivialOutputExprInRTW (SimStruct * S, int idx)

  • bool ssGetOutputPortOutputExprInRTW (SimStruct * S, int idx)

的通用表达式是一个简单的集合表达式的超集,和简单的集合表达式是集的超集常数表达式。

因此,当你查询一组输出一直是一个常数表达式ssGetOutputPortTrivialOutputExprInRTW,它返回真正的。一个常数表达式被认为是一个简单的表达式,因为它是一个直接存储器存取,可以重复没有降解生成的代码的效率。

同样,一个输出,被配置为一个常数或简单的表达式返回真正的当查询地位一般表达式。

接受或拒绝请求输入表达式

一块要求其输出可以在代码中表示为一个表达式。这样的请求会被拒绝,如果目的地块不能接受表达式的输入端口。此外,条件独立的请求块和目的地块可以防止接受表达式。

这个话题讨论屏蔽一些条件要求输入表达式是否认。信息在其他条件,防止接受的表情,明白了拒绝请求块输出表达式

一块不应在其输入端口配置为接受表达式在下列条件:

  • 块必须把其输入数据的地址。它是不可能大多数类型的输入的地址表达式。

  • 生成的代码块引用的输入(例如,不止一次腹肌马克斯块)。这可能会导致重复的复杂表达式和随后的退化的代码效率。

如果一块拒绝接受表达式一个输入端口,然后一块连接到输入端口是不允许输出一个通用的或简单的表达式。

要求输出一个常数表达式并不否认,因为没有性能损失一个常数表达式,和软件可以把参数的地址。

s函数API指定输入表达式验收。让你的s函数API提供了宏:

  • 指定一个块的输入是否应该接受非常数的表达式(即琐碎或通用表达式)

  • 查询是否一块输入接受非常数的表达式

默认情况下,块输入不接受非常数的表达式。

你应该叫你的宏mdlSetWorkWidths函数。宏有以下参数:

  • SimStruct *年代块的SimStruct:指针。

  • int idx:输入端口的从零开始的索引。

  • bool值:通过真实如果港口接受输入表达式;否则传入错误的。

宏用于指定块的输入是否应该接受一个非常数的表达式如下:

空白ssSetInputPortAcceptExprInRTW (int portIdx SimStruct *年代,bool值)

相应的宏可以查询任何调用之前设定的状态ssSetInputPortAcceptExprInRTW如下:

bool ssGetInputPortAcceptExprInRTW (SimStruct * S, int portIdx)

拒绝请求块输出表达式。即使在一个特定的块的请求,它可以生成一个输出表达式,请求可以否认通用的原因。这些原因包括,但不限于

  • 输出表达式是重要的,并且有多个目的地的输出。

  • 非常数的输出表达式,输出连接到至少一个目的地,不接受表达式的输入端口。

  • 输出一个测试点。

  • 输出被分配一个外部存储类。

  • 输出必须使用全局数据存储(例如是一个合并的输入块或一块状态)。

  • 输出信号是复杂的。

你不需要考虑这些通用的因素在决定是否使用表达式折叠为一个特定的块。然而,这些规则可以帮助当你检查生成的代码和分析的情况下表达折叠优化抑制。

表达折叠在TLC块实现

利用表达式折叠,您必须修改的TLC块实现一个内联函数,这样它通知仿真软件引擎是否产生或接受的表达万博1manbetx

这个话题讨论需要修改TLC实现。

表达折叠合规。BlockInstanceSetup函数的功能,注册您的块符合表达折叠。否则,表达式折叠要求或允许在块的输出或输入将被禁用,并且将使用临时变量。

寄存器表达式折叠合规、TLC库函数的调用LibBlockSetIsExpressionCompliant(块)中定义matlabroot/ rtw / c / tlc / lib / utillib.tlc。例如:

% %功能:BlockInstanceSetup = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = % % %函数BlockInstanceSetup(块,系统)无效% % % < LibBlockSetIsExpressionCompliant(块)> % % % endfunction

你可以有条件地禁用表达式折叠在一块的输入和输出通过有条件地调用这个函数。

如果覆盖一个薄块的实现提供的代码生成器使用您自己的实现,您不应该打前面的电话,直到你更新您的实现,作为表达式的指导方针所描述的折叠在接下来的话题。

输出表达式。BlockOutputSignal一个标量函数用于生成代码输出表达式或nonscalar输出表达式的一个元素。如果你的块输出表达式,你应该添加一个BlockOutputSignal函数。的原型BlockOutputSignal

%函数BlockOutputSignal(块,系统、portIdx ucv,液位控制阀,idx, retType)无效

的参数BlockOutputSignal如下:

  • :记录块产生一个输出表达式

  • 系统:记录系统包含块

  • portIdx:从零开始的索引表达式的输出端口被生成

  • ucv:用户控制变量定义的输出元素正在生成的代码

  • 液位控制阀:循环控制变量定义的输出元素正在生成的代码

  • idx:信号指数定义的输出元素正在生成的代码

  • retType:特征向量定义的信号类型访问所需:

    “信号”指定了输出信号的内容或地址。

    “SignalAddr”指定的地址输出信号

BlockOutputSignal函数返回一个特征向量为输出信号或地址。特征向量应执行表达式的优先通过开放和终止括号,除非表达式由一个函数调用。一个表达式的地址只能返回常数表达式;这是参数的内存访问的地址。代码实现BlockOutputSignal函数的常数块如下所示。

% %功能:BlockOutputSignal = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = % %文摘:% %返回引用参数。这个函数* * % %可能使用的仿真软件优化块时输入输出的数据结构。万博1manbetx% % %函数BlockOutputSignal(块,系统、portIdx ucv,液位控制阀,idx, retType)无效%开关retType %例“信号”%返回LibBlockParameter(价值、ucv液位控制阀,idx) %例“SignalAddr”%返回LibBlockParameterAddr(价值、ucv液位控制阀,idx) %默认%分配errTxt =“不支持的返回类型:% < retType > % < LibBlockReportError(块,errTxt) > % e万博1manbetxndswitch % endfunction

代码实现BlockOutputSignal函数关系操作符块如下所示。

% %功能:BlockOutputSignal = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = % %文摘:% %返回一个输出表达式。这个函数* * % %可能使用的仿真软件优化块时输入输出的数据结构。万博1manbetx% % %函数BlockOutputSignal(块,系统、portIdx ucv,液位控制阀,idx, retType)无效%开关retType %例%分配logicOperator = ParamSettings“信号”。运算符%如果ISEQUAL (logicOperator " ~ = ") %分配op = " != " elseif ISEQUAL (logicOperator " = = ") %分配op = " = = " % %其他分配op = logicOperator % endif %分配情况= LibBlockInputSignal (0 ucv液位控制阀,idx) %分配u1 = LibBlockInputSignal (1 ucv液位控制阀,idx) %回报”(% <情况> % < op > % < u1 >)”%default %assign errTxt = "Unsupported return type: %" % %endswitch %endfunction

与多个输出表达式折叠块。当一块只有一个输出,输出功能块的TLC文件叫做只有在输出端口不是一个表达式。否则,BlockOutputSignal函数被调用。

如果一块有多个输出,输出函数如果任何输出端口不是一个表达式。的输出函数应该防备生成代码的输出端口表达式。这是通过保护部分对应的代码和调用各个输出端口LibBlockOutputSignalIsExpr ()

例如,考虑一个函数有两个输入和两个输出,

  • 第一个输出,y0,等于两倍的第一个输入。

  • 第二个输出,y1,等于第二个输入的四倍。

输出BlockOutputSignal函数功能下面的代码片段所示。

% %功能:BlockOutputSignal = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = % %文摘:% %返回一个输出表达式。这个函数* * % %可能使用的仿真软件优化块时输入输出的数据结构。万博1manbetx% % %函数BlockOutputSignal(块,系统、portIdx ucv,液位控制阀,idx, retType)无效%开关retType %例“信号”%分配u = LibBlockInputSignal (portIdx、ucv, lcv idx) %例“信号”%如果portIdx = = 0%的回报”(2 * % u > <)%elseif portIdx == 1 %return "(4 * %)" %endif %default %assign errTxt = "Unsupported return type: %" % %endswitch %endfunction %% %% Function: Outputs ================================================= %% Abstract: %% Compute output signals of block %% %function Outputs(block,system) Output %assign rollVars = ["U", "Y"] %roll sigIdx = RollRegions, lcv = RollThreshold, block, "Roller", rollVars %assign u0 = LibBlockInputSignal(0, "", lcv, sigIdx) %assign u1 = LibBlockInputSignal(1, "", lcv, sigIdx) %assign y0 = LibBlockOutputSignal(0, "", lcv, sigIdx) %assign y1 = LibBlockOutputSignal(1, "", lcv, sigIdx) %if !LibBlockOutputSignalIsExpr(0) % = 2 * %; %endif %if !LibBlockOutputSignalIsExpr(1) % = 4 * %; %endif %endroll %endfunction

Expression-Folding-Compliant注释块。在过去,之前他们的输出代码块与评论的形式

/ * % <类型>块:% <名称> * /

expression-folding-compliant块时,上面所示的初始线是自动生成的。你不应该包括评论块的TLC实现的一部分。应该注册使用的额外信息LibCacheBlockComment函数。

LibCacheBlockComment函数接受一个特征向量作为输入,定义的评论,除了头,开幕式的最后换行单一或多行注释,拖车和结束。

下面的TLC代码说明了注册一个街区的评论。请注意函数的使用LibBlockParameterForComment返回一个特征向量,适合一块评论,指定块参数的值。

% openfile commentBuf $ c(*)增益值:% < LibBlockParameterForComment(获得)> % closefile commentBuf % < LibCacheBlockComment(块,commentBuf) >

S-Functions指定端口范围和可重用性

您可以使用以下SimStruct宏的mdlInitializeSizes方法指定的范围和可重用性的内存用于你的s函数的输入和输出端口:

你声明一个输入或输出当地或全球,并指出它的可重用性,通过以下四个选项之一ssSetInputPortOptimOptsssSetOutputPortOptimOpts宏:

  • SS_NOT_REUSABLE_AND_GLOBAL:表明输入和输出端口存储在单独的内存位置在全球块输入和输出结构

  • SS_NOT_REUSABLE_AND_LOCAL个人:表明代码生成器可以声明局部变量的输入和输出端口

  • SS_REUSABLE_AND_LOCAL:表明代码生成器可以重用一个本地变量的输入和输出端口

  • SS_REUSABLE_AND_GLOBAL:表明这些输入和输出端口存储在单个元素在全球块输入和输出结构

请注意

将一个输入或输出端口标记为一个局部变量并不意味着代码生成器生成的代码使用一个局部变量。如果你的s函数访问只在它的输入和输出mdlOutputs习惯,代码生成器声明局部变量的输入和输出。然而,如果输入和输出功能的其他地方使用,代码生成器包括他们在全球块输入和输出结构。

可重用性设置指示如果与一个输入或输出端口相关联的内存可以被覆盖。重用输入和输出端口内存:

  1. 显示端口是可重用的使用SS_REUSABLE_AND_LOCALSS_REUSABLE_AND_GLOBAL选项ssSetInputPortOptimOptsssSetOutputPortOptimOpts

  2. 表明overwritable输入端口内存使用ssSetInputPortOverWritable

  3. 如果你的s函数有多个输入和输出端口,使用ssSetOutputPortOverwritesInputPort显示输出和输入端口共享内存

下面的例子显示了如何不同的范围和可重用性设置影响生成的代码。下面的模型包含一个功能块指向C墨西哥人功能matlabroot/工具/模型/ s万博1manbetximdemos / simfeatures / src /sfun_directlook.c,该模型直接一维查找表。

功能的mdlInitializeSizes方法声明的输入端口为可重用的、当地overwritable和输出端口作为可重用和地方,如下:

静态孔隙mdlInitializeSizes (SimStruct * S){/ *剪* / ssSetInputPortOptimOpts(年代,0,SS_REUSABLE_AND_LOCAL);ssSetInputPortOverWritable(年代,0,真实);/ *剪* / ssSetOutputPortOptimOpts(年代,0,SS_REUSABLE_AND_LOCAL);/ *剪* /}

为这个模型所生成的代码存储在一个本地变量的输入和输出信号rtb_SFunction,如以下输出所示功能:

静态孔隙sl_directlook_output (int_T tid){/ *本地块i / o变量* / real_T rtb_SFunction [2];/ *罪:< Root > /正弦波的* / rtb_SFunction[0] =罪(((real_T) sl_directlook_DWork。计数器[0]+ sl_directlook_P.SineWave_Offset) * 2.0 * 3.1415926535897931 e + 000 / sl_directlook_P.SineWave_NumSamp) * sl_directlook_P。SineWave_Amp [0] + sl_directlook_P.SineWave_Bias;罪rtb_SFunction [1] = (((real_T) sl_directlook_DWork。计数器[1]+ sl_directlook_P.SineWave_Offset) * 2.0 * 3.1415926535897931 e + 000 / sl_directlook_P.SineWave_NumSamp) * sl_directlook_P。SineWave_Amp [1] + sl_directlook_P.SineWave_Bias;/ *功能块:< Root > / s函数* / {const real_T * xData = &sl_directlook_P.SFunction_XData [0];const real_T * yData = &sl_directlook_P。SFunction_YData [0];real_T间距= xData [1]——xData [0];如果(rtb_SFunction [0] < = xData [0]) {rtb_SFunction [0] = yData [0];}else if (rtb_SFunction [0] > = yData [20]) {rtb_SFunction [0] = yData [20]; } else { int_T idx = (int_T)( ( rtb_SFunction[0] - xData[0] ) / spacing ); rtb_SFunction[0] = yData[idx]; } if (rtb_SFunction[1] <= xData[0] ) { rtb_SFunction[1] = yData[0]; } else if (rtb_SFunction[1] >= yData[20] ) { rtb_SFunction[1] = yData[20]; } else { int_T idx = (int_T)( ( rtb_SFunction[1] - xData[0] ) / spacing ); rtb_SFunction[1] = yData[idx]; } } /* Outport: '/Out1' */ sl_directlook_Y.Out1[0] = rtb_SFunction[0]; sl_directlook_Y.Out1[1] = rtb_SFunction[1]; UNUSED_PARAMETER(tid); }

下面的表显示了该模型生成的代码变化当使用通用实时目标(GRT)。每一行解释了不同的设置范围和可重用性的s函数的输入和输出端口。

范围和可重用性 功能mdlInitializeSizes代码 生成的代码

输入:地方、可重用、overwritable

输出:当地的、可重用的

ssSetInputPortOptimOpts(年代,0,SS_REUSABLE_AND_LOCAL);ssSetInputPortOverWritable(年代,0,真实);ssSetOutputPortOptimOpts(年代,0,SS_REUSABLE_AND_LOCAL);

模型。c文件声明一个局部变量在函数的输出。

/ *本地块i / o变量* / real_T rtb_SFunction [2];

输入:全球、可重用、overwritable

输出:全球、可重用

ssSetInputPortOptimOpts(年代,0,SS_REUSABLE_AND_GLOBAL);ssSetInputPortOverWritable(年代,0,真实);ssSetOutputPortOptimOpts(年代,0,SS_REUSABLE_AND_GLOBAL);

模型。h文件定义了一个块信号结构,单个元素来存储函数的输入和输出。

/ *块信号(自动存储)* / typedef struct {real_T SFunction [2];}BlockIO_sl_directlook;

模型。c文件使用这个元素计算结构的s函数的输入和输出信号。

/ *罪:< Root > /正弦波的* / sl_directlook_B。SFunction[0] =罪……/ *剪* / / *功能块:< Root > / s函数* / {const real_T * xData = &sl_directlook_P.SFunction_XData [0]

输入:当地,而不是可复用的

输出:当地,而不是可复用的

ssSetInputPortOptimOpts(年代,0,SS_NOT_REUSABLE_AND_LOCAL);ssSetInputPortOverWritable(年代,0,假);ssSetOutputPortOptimOpts(年代,0,SS_NOT_REUSABLE_AND_LOCAL);

模型。c文件声明局部变量s函数的输入和输出在输出函数

/ *本地块i / o变量* / real_T rtb_SineWave [2];real_T rtb_SFunction [2];

输入:全球,而不是可复用的

输出:全球,而不是可复用的

ssSetInputPortOptimOpts(年代,0,SS_NOT_REUSABLE_AND_GLOBAL);ssSetInputPortOverWritable(年代,0,假);ssSetOutputPortOptimOpts(年代,0,SS_NOT_REUSABLE_AND_GLOBAL);

模型。h文件定义了一个块信号结构与各个元素来存储函数的输入和输出。

/ *块信号(自动存储)* / typedef struct {real_T SineWave [2];real_T SFunction [2];}BlockIO_sl_directlook;

模型。c文件使用不同的元素在这个结构在计算函数的输入和输出。

/ *罪:< Root > /正弦波的* / sl_directlook_B。SineWave[0] =罪……/ *剪* / / *功能块:< Root > / s函数* / {const real_T * xData = &sl_directlook_P.SFunction_XData [0]

S-Functions指定样品时间继承规则

仿真软件引擎,以万博1manbetx确定一个模型可以继承一个样本时间,模型中的S-functions需要指定如何使用示例。您可以指定该信息通过调用宏ssSetModelReferenceSampleTimeInheritanceRulemdlInitializeSizesmdlSetWorkWidths。使用这个宏:

  1. 检查功能是否调用下列宏:

    • ssGetSampleTime

    • ssGetInputPortSampleTime

    • ssGetOutputPortSampleTime

    • ssGetInputPortOffsetTime

    • ssGetOutputPortOffsetTime

    • ssGetSampleTimePtr

    • ssGetInputPortSampleTimeIndex

    • ssGetOutputPortSampleTimeIndex

    • ssGetSampleTimeTaskID

    • ssGetSampleTimeTaskIDPtr

  2. 检查以下你的s函数TLC代码:

    • LibBlockSampleTime

    • CompiledModel.SampleTime

    • LibBlockInputSignalSampleTime

    • LibBlockInputSignalOffsetTime

    • LibBlockOutputSignalSampleTime

    • LibBlockOutputSignalOffsetTime

  3. 根据您的搜索结果,使用ssSetModelReferenceSampleTimeInheritanceRule显示在下表中。

    如果…… 使用……
    所有的宏和函数存在,继承的功能并不排除模型样本。
    USE_DEFAULT_FOR_DISCRETE_INHERITANCE ssSetModelReferenceSampleTimeInheritanceRule(年代)

    用于任何宏或功能

    • 把错误如果样品时间是遗传的,连续的,或常数

    • 检查ssIsSampleHit

    • 检查样品是否时间是遗传的mdlSetInputPortSampleTimemdlSetOutputPortSampleTime之前的设置

    ssSetModelReferenceSampleTimeInheritanceRule……(年代,USE_DEFAULT_FOR_DISCRETE_INHERITANCE)
    功能使用的样品时间计算参数,输出,等等
    DISALLOW_SAMPLE_TIME_INHERITANCE ssSetModelReferenceSampleTimeInheritanceRule(年代)

请注意

如果一个函数不设置ssSetModelReferenceSampleTimeInheritanceRule宏,默认情况下,模型引擎假设s函数并不排除s万博1manbetx函数的模型包含继承一个示例。然而,发动机发出一个警告,表明这个宏的模型包括S-functions没有设置。

您可以使用设置配置参数>诊断>先进的参数控制仿真软件引擎如何回答当遇到S-fu万博1manbetxnctions样本时,指定继承规则。切换的配置参数>诊断>样品时间>未指明的继承性的样品时间诊断为没有一个,警告,或错误。默认值是警告

S-Functions支持代码重用万博1manbetx

您可以重用相同的子系统生成的代码,发生在多个实例模型和跨中引用的模型。更多信息子系统的代码生成代码重用,明白了控制生成子系统的功能。如果你想让你的功能来支持代码重用的一个子系统,s函数必须满足以万博1manbetx下要求:

  • 必须内联函数。

  • 生成的代码的功能不能使用静态变量。

  • s函数必须初始化向量指针工作mdlStart而不是之前。

  • 日志数据的功能不能水槽的工作区。

  • 功能必须登记其参数在运行时参数mdlSetWorkWidths。(它不能使用ssWriteRTWParameters在其mdlRTW函数。)

  • s函数不能是一个设备驱动程序。

除了满足前面的需求,你的s函数必须设置SS_OPTION_WORKS_WITH_CODE_REUSE标志(见的描述ssSetOptions在仿真软件编写万博1manbetx功能文档)。这个标志表明子系统功能满足要求代码重用。

S-Functions多重速率的多任务环境中

关于S-Functions多重速率的多任务环境

S-functions可用于模型与多个样本率和部署在多任务目标环境。同样,S-functions自己可以有多个利率他们的运作方式。代码生成器生成的代码使用的方法称为多重速率的多任务模型率分组。ERT-based目标代码生成,生成单独的分组模型_step功能基本利率任务和每个subrate任务模型。尽管率分组是一个代码生成特性中发现ERT目标只有S-functions可以使用它在其它情况下当你代码如下解释。

在S-Functions率分万博1manbetx组支持

利用分组,你必须内联多重速率的S-functions如果你还没有这么做的话)。你需要遵循一定的目标语言编译器协议利用分组。编码TLC利用速率分组不阻止你的内联S-functions GRT正常运作的。同样,内联S-functions还会生成有效的ERT代码即使你不让他们rate-grouping-compliant。然而,如果你这样做,他们将为多重速率的模型生成更高效的代码。

指令和目标语言编译器的示例代码演示了如何创建和升级S-functions生成rate-grouping-compliant代码,看看率分组遵从性和兼容性问题(嵌入式编码)。

为每个多重速率的功能,不是利率grouping-compliant,代码生成器问题当你构建以下警告:

警告:仿真软件编码万博1manbetx器:代码的输出函数多重速率的块< Root > / s函数的守卫的样品检查而不是达到速率分组。这将生成相同的代码块使用的利率,可能产生死代码。为了避免死代码,您必须更新的TLC文件块。

你也会找到一个评论如以下代码为每个不合规的s函数生成:

/ *因为多重速率的块的输出函数< Root > / s函数不是率分组,下面的代码可能包含的代码块。为了避免这种情况,你必须更新块薄层色谱文件。* /

“更新函数”代替“输出函数”这些警告。

创建多任务、多频和出口S-Functions样品时间

下面的说明显示如何同时支持数据在多频S-functions决定论和数据完整性。万博1manbetx他们不覆盖的情况下没有决定论和完整性。万博1manbetx支持框架处理不影响需求。

请注意

缓慢的利率必须最快的倍数。说明不适用当两个利率时界面上的不是倍数或利率不是周期性的。

妥善处理规则Fast-to-Slow转换。多频S-functions应该遵守的规则输入

  • 输入只能阅读速度与输入端口相关联的示例。

  • 通常,输入数据写入DWork,DWork然后可以访问速度较慢(下游)。

输入可以阅读每个样本的输入速率和写入DWork记忆,但这DWork记忆并不能直接访问速度较慢。DWork记忆,将阅读速度缓慢只能快速当写的特殊的样品了。特殊样本袭击发生在两个输入端口速率和速率接口有一个打击。根据他们的需求和设计,算法可以处理数据在几个位置。

输出的多频S-functions应该遵守的规则

  • 输出不应该写的速度除了率分配到输出端口,除了在下面描述的优化情况。

  • 输出应该写在输出端口的采样率。

如果这些条件得到满足,功能块可以指定输入端口和输出端口都可以使当地的和可重用的。

你可以包括一个优化时很少或不需要进行处理的数据。在这种情况下,输入代码可以直接写入输出速度(而不是通过使用DWork)时,是一种特殊的样本。如果你这样做,但是,你必须声明输出港港口全球没有可重用。这种优化的结果在一个更少memcpy但引入非均匀速度处理需求。

你是否使用这种优化,最近的输入数据,所看到的速度较慢,是在速度和速度较慢,他们的支安打(和可能的输入数据,根据算法)。后续步骤的速度和相关的输入数据更新不被缓慢的速度较慢,直到下一个打击率。

伪代码Fast-to-Slow率转换的例子。下面的伪代码抽象应该如何编写C墨西哥人代码来处理fast-to-slow过渡,说明输入率的0.1秒输出一秒的速度开车。时可以采取类似的方法内联代码。块有以下特点:

  • 文件:sfun_multirate_zoh.c方程:y = u (tslow)

  • 输入:本地和可重用性

  • 输出:本地和可重用性

  • DirectFeedthrough:是的

    OutputFcn如果(ssIsSampleHit(“1”)){如果(ssIsSepcialSampleHit (" 1 ")) {DWork = u;}}如果(ssIsSampleHit (" 1 ")) {y = DWork;}

另一个稍微简单的算法优化方法:

  • 输入:本地和可重用性

  • 输出:全球而不是可重用的,因为它需要之间存在特殊的样本

  • DirectFeedthrough:是的

    OutputFcn如果(ssIsSampleHit(“1”)){如果(ssIsSpecialSampleHit (" 1 ")) {y = u;}}

示例添加一个简单的算法:

  • 文件:sfun_multirate_avg.c;方程:y =平均(u)

  • 输入:本地和可重用性

  • 输出:本地和可重用性

  • DirectFeedthrough:是的

    (假设DWork [0:10]DWork [mycounter]初始化为零)

    OutputFcn如果(ssIsSampleHit(“1”)){/ *一般来说,处理“u”这里就可以完成,它运行在每一个快速的冲击。* / DWork [DWork [mycounter] + +] = u;如果(ssIsSpecialSampleHit(" 1 ")){/ *一般的处理DWork[0:10]可以做,但它确实导致更快的速度非均匀处理要求(每10打,更多的代码需要运行)。* / DWork[10] =总和(DWork [0:9]) / 10;DWork [mycounter] = 0;}}如果(ssIsSampleHit(" 1 ")){/ *处理DWork[10]可以在输出完成。这段代码运行在每一个慢的任务。* / y = DWork [10];}

规则妥善处理低到高转换。当输出率高于输入,输入只能阅读速度与输入端口相关联样本,观察以下规则:

  • 总是读取输入的更新功能。

  • 使用没有特殊示例检查阅读时输入。

  • 写输入DWork。

  • 当有特殊的样本之间的利率,DWork复制到第二个DWork输出函数。

  • 写第二个DWork输出每个输出的采样率。

块可以要求输入端口是当地但不能被设置为可重用的。输出端口可以被设置为本地和可重用性。

在fast-to-slow过渡情况下,输入不应该阅读速度比分配的其他输入端口。同样,输出不应写入速度除了率分配到输出端口。

一个优化算法实现时可以只需要运行速度缓慢。在这种情况下,你只使用一个DWork。输入仍然写DWork更新函数。当有特殊的样本之间的利率,直接输出函数复制相同的DWork输出。你必须设置输出端口是全球性的,而不是在这种情况下可重用。这种优化的结果在一个更少memcpy操作/特殊的样本。

在这两种情况下,快速计算的数据操作总是延迟,即前一步的数据速率缓慢的代码。

伪代码低到高速率转换的例子。下面的伪代码抽象功能需要做些什么来处理低到高转换,说明与输入一秒的速度驱动输出率为0.1秒。块有以下特点:

  • 文件:sfun_multirate_delay.c方程:y = u (tslow-1)

  • 输入:设置为本地,将当地如果输出/更新相结合(ERT)否则将是全球性的。设置为不重用,因为输入需要保存,直到更新功能运行。

  • 输出:本地和可重用性

  • DirectFeedthrough:不

    OutputFcn如果ssIsSampleHit(“1”){如果ssIsSpecialSampleHit (“1”) {DWork [1] = DWork [0];}y = DWork [1];}UpdateFcn如果(ssIsSampleHit (" 1 ")) {DWork [0] = u;}

一种替代方法,可以使用优化方法通过一些算法:

  • 输入:设置为本地,将当地如果输出/更新相结合(ERT)否则将是全球性的。设置为不重用,因为输入需要保存,直到更新功能运行。

  • 输出:全球而不是可重用的,因为它需要之间存在特殊的样本。

  • DirectFeedthrough:不

    OutputFcn如果ssIsSampleHit(“1”){如果ssIsSpecialSampleHit (“1”) {y = DWork;}}UpdateFcn如果(ssIsSampleHit (" 1 ")) {DWork = u;}

示例添加一个简单的算法:

  • 文件:sfun_multirate_modulate.c方程:y =罪(tfast) + u (tslow-1)

  • 输入:设置为本地,将当地如果输出/更新相结合(ERT特性)否则将是全球性的。设置为不重用,因为输入需要保存,直到更新功能运行。

  • 输出:本地和可重用性

  • DirectFeedthrough:不

    OutputFcn如果ssIsSampleHit(“1”){如果ssIsSpecialSampleHit(“1”){/ *处理不可能在这里完成。它会导致*非均匀的速度处理*要求(每10打,更多的代码需要*运行)。* / DWork [1] = DWork [0];}/ *处理在快速完成* / y =罪(ssGetTaskTime (“1”)) + DWork [1];}UpdateFcn如果(ssIsSampleHit(" 1 ")){/ *处理“u”可以在这里完成。有一个缓慢的延迟率快速看到它之前。* / DWork [0] = u;}

另请参阅

相关的话题

这个主题有帮助吗?