主要内容

s -函数合并了遗留C代码

概述

C MEX s -函数允许您在Simulink中调用现有的C代码金宝app®模型。例如,考虑简单的C函数doubleIt.c输出的值是函数输入值的两倍。

double doubleIt(double u) {return(u * 2.0);}

你可以创建一个s函数来调用doubleIt.c通过:

  • 编写包装器S函数. 使用此方法,您可以手工编写一个新的C S函数和相关的TLC文件。这种方法需要对CS函数的结构有最多的了解。

  • 使用S函数生成器块.使用这种方法,您可以将s函数的特征输入到一个块对话框中。这种方法不需要任何关于编写s函数的知识。但是,对S-function结构的基本了解可以使S-function Builder对话框更容易使用。

  • 使用遗留代码工具.使用这个命令行方法,您可以在MATLAB的数据结构中定义s函数的特征®工作区。这种方法需要的s函数知识最少。

您还可以使用MATLAB函数块从Simulink模型调用外部C代码。金宝app有关更多信息,请参见利用MATLAB函数块集成C代码

以下部分描述如何创建在Simulink仿真中使用的s -函数金宝app金宝app仿真软件编码器™代码生成,使用前三种方法。示例模型包含使用这些s -函数的块。如果您计划创建模型,请复制文件doubleIt.c加倍从文件夹中docroot/toolbox/金宝appsimulink/examples放入您的工作文件夹。

使用手写s函数合并遗留代码

的功能wrapsfcn.c调用遗留函数doubleIt.c在其mdlOutputs方法拯救wrapsfcn.c如果计划创建示例模型,请将文件保存到工作文件夹中。

要将遗留代码合并到S函数中,wrapsfcn.c首先声明doubleIt.c用下面的行:

extern real_T doubleIt(real_T u);

一旦声明,S函数就可以使用doubleIt.c在其mdlOutputs方法。例如:

/*函数:mdlOutputs====================================================*摘要:*调用doubleIt.c函数将输入乘以2。*/静态void mdlOutputs(SimStruct*S,int tid){InputRealPtrsType uPtrs=ssGetInputPortRealSignalPtrs(S,0);real_T*y=ssgetoutputprealsignal(S,0);*y=doubleIt(*uPtrs[0])}

来编译wrapsfcn.cs函数,运行以下命令墨西哥人命令。确保doubleIt.c文件在您的工作文件夹中。

墨西哥人wrapsfcn.c doubleIt.c

使用金宝appSimulink编码器代码生成器,您需要编写一个目标语言编译器(TLC)文件wrapsfcn.tlc使用BlockTypeSetup函数来声明函数原型doubleIt.c.TLC文件输出函数告诉金宝appSimulink编码器代码生成器如何内联调用doubleIt.c.例如:

%%实现"wrapsfcn" "C" %% File: wrapsfcn. "在model.h中创建函数原型为:%% "extern double doubleIt(double u);"%% %function BlockTypeSetup(block, system) void %openfile buffer %%提供一行代码作为函数原型extern double doubleIt(double u);% closefile缓冲% < LibCacheFunctionPrototype(缓冲)> % % endfunction % % BlockTypeSetup % %功能:输出  ======================================= %% 文摘:% %调用遗留功能:y = doubleIt (u);%% %function Outputs(block, system) Output /* % block: % */ %assign u = LibBlockInputSignal(0, "", "", 0) %assign y = libblocoutputsignal (0, "", "", 0) %% PROVIDE THE CALLING STATEMENT FOR "doubleIt" % = doubleIt(%);% endfunction % %输出

有关TLC的更多信息,请参阅目标语言编译器基础(金宝app仿真软件编码器)

使用S函数生成器合并旧代码

S-Function Builder自动创建包含遗留代码的S-Function和TLC文件。对于本例,除了doubleIt.c,则需要头文件加倍这声明doubleIt.c函数格式,如下所示:

extern real_T doubleIt(real_T in1);

使用S-Function Builder块配置块对话框来调用遗留函数doubleIt.c.在S-Function Builder块对话框中:

  • 功能名称字段参数窗格定义名称建筑商对于生成的s函数。

  • 数据属性窗格将输入和输出端口命名为着干活,分别。

  • 图书馆窗格提供到遗留代码的接口。

    • 库/对象/源文件字段包含源文件名doubleIt.c

    • 包括字段包含以下行,以包含声明遗留函数的头文件:

      #包括
  • 输出窗格使用以下行调用旧函数:

    /*调用函数,将输入乘以2 */ *out1 = doubleIt(*in1);
  • 建立信息窗格中选择生成包装TLC选择。

当你点击建筑,S函数生成器生成三个文件。

文件名称 描述
builder_wrapsfcn.c 主要的功能。
builder_wrapsfcn_wrapper.c 控件中输入的代码包含独立函数的包装器文件输出连续的衍生品离散更新窗格的S-Function Builder。
builder_wrapsfcn.tlc s函数的TLC文件。

builder_wrapsfcn.c文件遵循标准格式:

  • 该文件以一组#定义包含S函数生成器信息的语句。例如,以下行定义了第一个输入端口:

    #定义数字输入1/*输入端口0*/#定义输入端口0名称1#定义输入0宽度1#定义输入DIMS 0列1#定义输入0数据类型实数#定义输入0复杂复数#定义基于帧的帧#定义输入0 DIMS 1-D#定义输入1
  • 接下来,该文件声明在builder_wrapsfcn_wrapper.c文件。的示例只需要一个包装器函数输出代码。

    extern void builder_wrapsfcn_Outputs_wrapper(const real_T *in1, real_T *out1);
  • 在这些定义和声明之后,该文件包含S函数方法,例如中密度,初始化S函数的输入端口、输出端口和参数。看见流程视图获取在s函数初始化阶段调用的方法列表。

  • mdlOutputs方法调用builder_wrapsfcn_wrapper.c函数。该方法使用输入和输出名称着干活的定义数据属性窗格,调用包装器函数时。例如:

    /*函数:mdlOutputs================================================**/静态无效mdlOutputs(SimStruct*S,int_T tid){const real_T*in1=(const real_T*)ssGetInputPortSignal(S,0);real_T*out1=(real_T*)ssGetOutputPortRealSignal(S,0);builder_wrapsfcn输出包装器(in1,0)}
  • 该文件builder_wrapsfcn.c以所需的内容结束mdlTerminate方法。

包装函数builder_wrapsfcn_wrapper.c分为三个部分:

  • 包括文件部分包括加倍文件,连同标准的S-function头文件:

    / * *包含文件* * #如果定义(MATLAB_MEX_FILE) # Include“tmwtypes.h”#包括其他“simstruc_types.h”# #包括“rtwtypes.h”# endif / * % % % -SFUNWIZ_wrapper_includes_Changes_BEGIN——编辑这里_END * / # Include < math.h > # Include < doubleIt.h > / * % % % -SFUNWIZ_wrapper_includes_Changes_END——编辑_BEGIN * /
  • 外部参照节包含来自外部引用声明场的图书馆窗格。此示例不使用此部分。

  • 输出函数节声明函数builder_wrapfcn_Outputs_wrapper,它包含在S-Function Builder块对话框中输入的代码输出窗格:

    /* *输出函数* */ void builder_wrapfcn_Outputs_wrapper(const real_T *in1, real_T *out1) {/* %%%-SFUNWIZ_wrapper_Outputs_Changes_BEGIN——EDIT HERE TO _END */ /*调用函数,将输入乘以2 */ *out1 = doubleIt(*in1);/* %%%-SFUNWIZ_wrapper_Outputs_Changes_END——EDIT HERE TO _BEGIN */}

请注意

与手写S函数相比,S函数生成器通过包装文件将对传统C函数的调用降低了一个附加级别builder_wrapsfcn_wrapper.c

TLC文件builder_wrapsfcn.tlc生成的S-Function Builder类似于以前的手写版本。文件中声明了遗留函数BlockTypeSetup并在输出方法。

%%在%%生成的代码中为包装器函数设置外部引用。%% %函数BlockTypeSetup(block, system)输出%openfile externs extern void builder_wrapsfcn_Outputs_wrapper(const real_T *in1, real_T *out1);% closefile走读生% < LibCacheExtern(外来的)> % % % endfunction % %功能:输出  =========================================== %% %% 目的:% % mdlOutputs函数代码生成规则。/* S-Function "builder_wrapsfcn_wrapper" block:% */ %assign pu0 = LibBlockInputSignalAddr(0, "", "", 0) %assign py0 = libblocoutputsignaladdr (0, "", "", 0) %assign py_width = LibBlockInputSignalWidth(0) %assign pu_width = LibBlockInputSignalWidth(0) builder_wrapsfcn_Outputs_wrapper(%, %);% % % endfunction

使用遗留代码工具合并遗留代码

部门使用遗留代码工具将C函数集成到Simulink模型中金宝app在“用C编写S-Functions”中展示了如何使用遗留代码工具创建一个合并的S-functiondoubleIt.c.对于执行该示例中的步骤的脚本,复制该文件lct_wrapsfcn.m到您的工作文件夹。确保doubleIt.c加倍文件位于您的工作文件夹中,然后通过键入来运行脚本lct_wrapsfcn在MATLAB命令提示符处。该脚本创建并编译s函数legacy_wrapsfcn.c并创建TLC文件遗产_wrapsfcn.tlc通过以下命令。

创建数据结构def = legacy_code('initialize');%填充数据结构def.SourceFiles = {'doubleIt.c'};def.HeaderFiles = {' doubleIt.h '};def.SFunctionName =“legacy_wrapsfcn”;def.OutputFcnSpec = 'double y1 = doubleIt(double u1)';def.SampleTime = (1,0);%生成S-function legacy_code('sfcn_cmex_generate', def);%编译MEX-file legacy_code(' Compile ', def);%生成一个tlc文件legacy_code('sfcn_tlc_generate', def);

的功能legacy_wrapsfcn.c由遗留代码工具生成的加倍头文件。的mdlOutputs方法然后直接调用doubleIt.c功能如下:

static void mdlOutputs(SimStruct *S, int_T tid) {/* * Get access to Parameter/Input/Output/DWork/size information */ real_T *u1 = (real_T *) ssGetInputPortSignal(S, 0);real_T *y1 = (real_T *) ssGetOutputPortSignal(S, 0); / /输出信号/* *调用遗留代码函数*/ *y1 = doubleIt(*u1);}

Legacy Code Tool生成的s函数与S-function Builder生成的s函数的区别如下:

  • 由S函数生成器生成的S函数调用旧函数doubleIt.c通过包装器函数builder_wrapsfcn_wrapper.c.传统代码工具生成的S函数直接调用doubleIt.c从它的mdlOutputs方法。

  • S-Function Builder使用输入和输出名称数据属性窗格,允许您在s -函数中自定义这些名称。遗留代码工具使用默认名称yu分别为输出和输入。当使用遗留代码工具时,您不能指定要在生成的s -函数中使用的自定义名称。

  • 默认情况下,S-Function Builder和遗留代码工具都指定继承的示例时间。但是,S-Function Builder使用的偏移时间为0.0而传统代码工具指定偏移时间固定在较小的时间步长中。

TLC文件遗产_wrapsfcn.tlc金宝app通过定义支持表达式折叠BlockInstanceSetupBlockOutputSignal功能。TLC文件还包含一个BlockTypeSetup函数来声明函数原型doubleIt.c和一个输出函数来告诉金宝appSimulink编码器代码生成器如何内联调用doubleIt.c.:

% %功能:BlockTypeSetup  =============================================== %% % 函数BlockTypeSetup(块,系统)无效% % % %目标语言必须C %如果::GenCPP = = 1% < LibReportFatalError(“这功能由遗留代码生成工具必须只使用C目标语言”)> % endif % < LibAddToCommonIncludes (doubleIt.h) > % < LibAddToModelSources (doubleIt) > % % % endfunction % %功能:BlockInstanceSetup  =========================================== %% % 函数BlockInstanceSetup(块、系统)无效% % % < LibBlockSetIsExpressionCompliant(块)> % % % endfunction % %功能:输出  ====================================================== %% % 函数输出(块、系统)输出% % % ! LibBlockOutputSignalIsExpr(0) %分配u1_val = LibBlockInputSignal (0 , "", "", 0) %分配y1_val = LibBlockOutputSignal (0 , "", "", 0) % % % < y1_val = doubleIt (% < u1_val >);%endif %% endfunction %%BlockOutputSignal  ============================================ %% % 函数BlockOutputSignal(块,系统、portIdx ucv,液位控制阀,idx, retType)无效% % %分配u1_val = LibBlockInputSignal (0 , "", "", 0) %分配y1_val = LibBlockOutputSignal (0 , "", "", 0) % % %开关retType %例“信号”%如果portIdx = = 0%的回报”doubleIt (% < u1_val >)”%else %assign errTxt = "Block output port index not 金宝appsupported: %" %endif %default %assign errTxt = "Unsupported return type: %" % %endswitch %% %endfunction .