主要内容

S-Functions结合了遗留的C代码

概述

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

double double (double u){返回(u * 2.0);}

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

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

  • 使用S-Function生成器块.使用这种方法,您可以在块对话框中输入s函数的特征。这种方法不需要任何关于s函数的知识。然而,对s -函数结构的基本理解可以使s -函数生成器对话框更易于使用。

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

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

以下部分描述如何创建在Simulink仿真中使用的s函数仿真软件编码器™代码生成,使用前三种方法。示例模型包含使用这些s函数的块。如果您计划创建模型,请复制文件doubleIt.c而且doubleIt.h从文件夹中docroot /工具/模型/例子进入你的工作文件夹。

使用手写的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。*/ static void mdlOutputs(SimStruct *S, int tid){InputRealPtrsType uPtrs = ssGetInputPortRealSignalPtrs(S,0);real_T *y = ssGetOutputPortRealSignal(S,0);*y = doubleIt(*uPtrs[0]);}

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

. mex wrapsfcn.c doubleIt.c

方法生成s函数的代码仿真软件编码器代码生成器,您需要编写一个目标语言编译器(TLC)文件。下面的TLC文件wrapsfcn.tlc使用BlockTypeSetup函数来声明函数原型doubleIt.c.TLC文件输出函数然后告诉仿真软件编码器代码生成器如何内联调用doubleIt.c.例如:

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

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

使用S-Function生成器合并遗留代码

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

extern real_T doubleIt(real_T in1);

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

  • 功能名称参数窗格定义名称。builder_wrapsfcn为生成的s函数。

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

  • 窗格提供遗留代码的接口。

    • 图书馆/对象/源文件字段包含源文件名doubleIt.c

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

      # include < doubleIt.h >
  • 输出窗格使用以下行调用遗留函数:

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

当你点击构建, S-Function Builder生成三个文件。

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

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

  • 文件以一组#定义包含S-Function Builder信息的语句。例如,下面几行定义了第一个输入端口:

    #define INPUT_0_WIDTH 1 #define INPUT_DIMS_0_COL 1 #define INPUT_0_DTYPE real_T #define INPUT_0_COMPLEX COMPLEX_NO #define input_0_dims 1- d #define INPUT_0_FEEDTHROUGH 1
  • 中找到的所有包装器函数builder_wrapsfcn_wrapper.c文件。类的包装器函数输出代码。

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

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

    / *功能:mdlOutputs  ============================================= * */ 静态孔隙mdlOutputs (SimStruct *年代,int_T tid) {const real_T *三机= (const real_T *) ssGetInputPortSignal (S, 0);real_T *out1 = (real_T *)ssGetOutputPortRealSignal(S,0);builder_wrapsfcn_Outputs_wrapper (in1,着干活);}
  • 该文件builder_wrapsfcn.c以必要的mdlTerminate方法。

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

  • 包含文件部分包括doubleIt.h文件,以及标准的s函数头文件:

    /* * Include Files * */ #if defined(MATLAB_MEX_FILE) # Include "tmwtypes.h" # Include "simstruc_types.h" #else # Include "rtwtypes.h" #endif /* %%%- sfunwiz_wrapper_incles_changes_begin——EDIT HERE TO _END */ # Include  # Include  /* %%%- sfunwiz_wrapper_incles_changes_end——EDIT HERE TO _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——在这里编辑_BEGIN */}

请注意

与手写的s -函数相比,S-function Builder通过包装器文件将对遗留C函数的调用降低到一个额外的级别builder_wrapsfcn_wrapper.c

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

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

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

一节用遗留代码工具集成C函数到Simulink模型在“用C编写s -函数”中,展示了如何使用遗留代码工具创建合并的s -函数doubleIt.c.对于执行该示例中的步骤的脚本,复制该文件lct_wrapsfcn.m到您的工作文件夹。确保doubleIt.c而且doubleIt.h文件在您的工作文件夹中,然后通过键入运行脚本lct_wrapsfcn在MATLAB命令提示符。脚本创建并编译s函数legacy_wrapsfcn.c并创建TLC文件legacy_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函数legacy_code('sfcn_cmex_generate', def);%编译墨西哥文件legacy_code(' Compile ', def);%生成tlc文件legacy_code('sfcn_tlc_generate', def);

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

static void mdlOutputs(SimStruct *S, int_T tid){/* *获取参数/输入/输出/DWork/size信息*/ real_T *u1 = (real_T *) ssGetInputPortSignal(S, 0);real_T *y1 = (real_T *) ssGetOutputPortSignal(S, 0);/* *调用遗留代码函数*/ *y1 = doubleIt(*u1);}

遗留代码工具生成的s函数与s函数生成器生成的s函数的区别如下:

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

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

  • 默认情况下,S-Function Builder和遗留代码工具都指定继承的采样时间。然而,S-Function Builder使用的偏移时间为0.0而遗留代码工具指定偏移时间固定在小时间步长。

TLC文件legacy_wrapsfcn.tlc通过定义支持表达式折叠BlockInstanceSetup而且BlockOutputSignal功能。TLC文件还包含BlockTypeSetup函数来声明函数原型doubleIt.c和一个输出函数来告诉仿真软件编码器代码生成器如何内联调用doubleIt.c.:

%% Function: BlockTypeSetup =============================================== %% % Function BlockTypeSetup(block, system) void %% %%目标语言必须是C %if::GenCPP==1 % %endif % % %% %endfunction %%函数:BlockInstanceSetup  =========================================== %% % 函数BlockInstanceSetup(块、系统)无效% % % < LibBlockSetIsExpressionCompliant(块)> % % % endfunction % %功能:输出  ====================================================== %% % 函数输出(块、系统)输出% % % ! LibBlockOutputSignalIsExpr(0) %分配u1_val = LibBlockInputSignal (0 , "", "", 0) %分配y1_val = LibBlockOutputSignal (0 , "", "", 0) % % % < y1_val = doubleIt (% < u1_val >);%endif %% %endfunction %% Function: BlockOutputSignal ============================================ %% % Function BlockOutputSignal(block,system,portIdx,ucv,lcv,idx,retType) void %% %assign u1_val = LibBlockInputSignal(0, "", "", 0) %assign y1_val = LibBlockOutputSignal(0, "", "", 0) %% %switch retType %case "Signal" %if portIdx == 0返回"doubleIt(%)"%else %assign errTxt = "块输出端口索引不支持:%" %endif %default %assign errTxt = "不支持返回类型:%" %< libblockreporterterror (Block,errTxt)> %endswitch %% %endfunction
Baidu
map