zoukankan      html  css  js  c++  java
  • Simulink仿真入门到精通(十七) Simulink代码生成技术详解

    17.1 基于模型的设计

     基于模型设计是一种流程,较之传统软件开发流程而言,使开发者能够更快捷、更高效地进行开发。适用范围包括汽车电子信号处理、控制系统、通信行业和半导体行业。

    V字模型开发流程整体描述:

    模型本身就是一个可执行的规划书,开发者修改优化模型就是对设计的修缮,修缮之时立刻可以进行设计的验证,无需到编码实现之后通过测试再进行系统验证。

    使用基于模型设计流程开发软件有以下优势:

    1. 在整个项目开发过程中使用统一的设计环境;
    2. 可以直接将需求与设计链接起来,易于对比变更点,降低设计遗漏的可能性;
    3. 将测试集成到设计中以持续验证并纠正错误;
    4. 通过多域仿真优化算法;
    5. 自动产生嵌入式软件代码;
    6. 开发标准模块库便于重用;
    7. 自动生成文档;
    8. 支持针对硬件目标的设计重用。

     17.1.1 需求文档

                        Requirements for a fast filter
    1. Two input
    One for signal input and the other for filter coefficient. 
    2. One output
    The output for signals filterd by the filter. 
    3. Title
    There should be a title in the model. 
    4. Alogrithm
    The calculation equation should be display in the model. 

    17.1.2 根据需求进行设计

    17.1.3 需求与设计的挂接

    通常需求文档使用Word或者Doors管理,MATLAB为了能将设计规划书与模型关联起来,通过rmi setup注册Active-X controls后Simulink Model菜单栏增加了需求追踪功能,通过这个功能追加Simulink链接到需求设计规划书的Word文档中,在每一项需求设计条目后都会出现Simulink的小图标,能够从需求文档链接到模型;可通过链接检查需求变更是否及时反映到所设计的模型中,以保持设计文档和模型的一致性。

    17.1.4 模型的仿真

    17.1.5 模型的性能分析及修正

    使用模型生成代码,特别是产品级代码生成时,所用模型必须按照特定规则进行审查。在工业自动化生产、汽车电子开发过程中,随着模型复杂度的提高,人工检查模型属性、配置及对于MAAB标准的遵守度逐渐成为负担,使用Simulink工具栏中的Model Advisor工具可以自动进行标准及模型参数配置和属性的检查,并产生检查报告。

    检查的内容有:

    1. 是否会导致系统仿真出错;
    2. 是否会导致生成的代码无效;
    3. 生成的代码是否符合安全标准。

    17.1.6 模型效率分析与优化

    使用Profile Report了解模型每个环节的时间消耗和各种子方法的调用次数。

    17.1.7 模型的代码生成

    Simulink的Simulink Coder工具箱提供了将模型转换为可优化的嵌入式C代码的功能,将模型的信号源和信号接收部分模块替换为输入/输出端口,系统文件使用ert.tlc,负责统筹调用代码生成的整个过程,将模块转换为相应的C代码,只不过这时的C代码并非专门面向某种嵌入式芯片的,而是未经过优化的通用性嵌入式代码,可读性不强。

    17.1.8 模型生成代码的优化

    Simulink的Embedded Coder工具箱提供了两方面的优化,一是通过对信号线的存储类型进行设置改变代码生成时的变量生成方式,二是通过结构化的思想将算法模型构成一个原子子系统,并将代码生成在指定文件的指定函数内,便于移植或重用。

    17.1.9 代码的有效性验证

    Processor In the Loop Simulation(PILS,处理器在环仿真)提供了验证算法有效性的方法。

    17.2 Simulink代码生成流程及技巧

    在Simulink环境中,嵌入式代码是由Embedded Coder、Simulink Coder为主导,MATLAB Coder辅助器进行生成代码优化。主要应用目标为嵌入式MCU,片上快速原型开发板,以及应用于民生电子、工业领域的MCU微处理器等。

    17.2.1 代码生成时的模型配置方法

    example.slx

    Configuration Parameter中集中管理着模型的代码生成方法、格式等约束条件。为了生成嵌入式代码,至少需要配置3部分:解算器Solver、系统目标文件(如ert.tlc)、硬件实现规定Hardware Implementation。

    solver

    解算器必须采用固定点类型,没有连续状态时可选discrete,步长默认为auto,在简单通用嵌入式代码生成过程中此参数没有实际作用。

    当模型中使用参数变量,如Gain的增益值,在生成代码是,如果希望使用该参数的值直接展开到代码中,就需要设置参数内联选项,在Code Generation→Optimization中有Default parameter behavior选项。

    可调:

    P_example_T example_P = {
      5.0                                  /* Variable: k
                                            * Referenced by: '<Root>/Gain'
                                            */
    };
    
    void example_step(void)
    {
      example_Y.Out1 = (example_P.k * example_U.In1 + example_U.In2) * example_U.In3;
    }

    内联:(此时缺少model_data.c文件)

    void example_step(void)
    {
      example_Y.Out1 = (5.0 * example_U.In1 + example_U.In2) * example_U.In3;
    }

    当选择Inlined后,代码生成时模型的参数将以常数方式直接生成到代码逻辑中,不再以一个参数变量的形式生成。当模型中的参数需要作为实时可以调节的参数生成到代码中时,选择Tunable,参数将作为变量生成。如果不需要实时调节参数,可以选择节省存储空间的方式Inlined。

    MATLAB2014a中该选项以勾选框的形式给出。

    Hardware Implementation

    Hardware Implementation选项是规定目标硬件规格的选项。在这个选项卡中可以配置芯片的厂商和类型,设置芯片的字长、字节顺序等。

    另一个关键的设置选项是控制整个代码生成过程的系统目标文件System Target File,ert.tlc文件是Embedded Coder提供的能够生成专门用于嵌入式系统C代码的系统目标文件。在Code Generation页面中的Browser按钮可以选择系统目标文件。

    Code Generation对比:

    另外2018a拥有搜索功能:

    Report

    在Report子标签中有关于生成代码报告的页面,通过勾选框可以选择是否在模型编译结束后自动打开。

    在Advanced parameters中可以选择是否在代码报告中追加模型与代码的双向追踪,并选择追踪的内容

    勾选Metrics中的Static code metrics时,将会在代码生成报告中包含静态代码的参数指标。

    Comments

    在comments子标签中包含对生成代码中注释内容的配置。

    Include comments选项的勾选决定是否在生成代码中添加Simulink自带的注释。注释中带有可以从代码跳转到对应模块的超链接,方便读者追溯模块与代码的对应关系,建议勾选。

    Symbol

    symbol子标签页面用于设置ert.tlc一族系统目标文件控制下的代码生成不变定义规则。这些符号包括数据变量和数据类型定义、常亮宏、子系统方法、模块的额输出变量、局部临时变量及命令的最长字符数等。

    控制代码生成的标示符:

    标示符 作用说明
    $R 表示根模型的名字,将C语言不支持的字符替换为下划线
    $N 表示Simulink对象:模块、信号或信号对象、参数、状态等的名字
    $M 为了避免命名冲突,必要时追加后缀以示区分
    $A 表示数据类型
    $H 表示系统层级标示符,对于根层次模块root_,对于子系统模块sN_,N是Simulink分配的系统编号
    $F 表示函数名,如表示更新函数时使用_Update
    $C 校验和标示符,用于防止命名冲突
    $I 表示输入/输出标示符,输入端口使用u表示,输出端口则用y表示

    通过上表中各种标示符的不同组合,即可规定生成代码中各部分的名称的生成规则。推荐使用默认设置。

    Custom Code

    Custom Code子标签主要用于添加用户自定义的或者编译模型时必需的源文件、头文件、文件夹或者库文件等。

    Debug

    原Debug子标签页面,新版Code Generation→Advanced parameters中,可以对编译过程和TLC过程的相关选项进行设置。

    Verbose build的勾选可以将编译过程信息显示在Command Window中。Retain .rtw file则能够保留编译模型生成的rtw文件。rtw文件是代码生成过程中从Simulink模型得到的中间文件,它记录了模型相关的所有需要被TLC文件使用的信息。下面关于TLC的几组参数能够启动TLC文件的profile功能和调试功能,使得开发者能够对TLC语言文件进行断点调试、单步调试等动作,以及了解TLC语句的覆盖度等情况。

    Interface

    Software E、environment组的参数中提供CPL(Code replacement library)的选择,CPL中定义一个表,根据表格将Simulink模块与所对应的目标语言的数学函数及操作函数库挂接,以便从模型生成代码。Support参数组中每个选择框代表一种嵌入式编码器对代码生成的支持功能,其中一些功能需要Simulink提供的头文件来支持才能编译为目标文件的,这些头文件一部分存储在MATLABrootsimulinkinclude文件夹中,一部分是在模型生成代码的过程中自动生成的(rt_开头的文件)。

    选择框条目 所需头文件
    floating-point numbers rtw_solver.h
    non-finite numbers rt_nonfinite.h
    complex numbers -
    absolute time -
    continuous time rt_continuous.h
    variable-size signals -

    Code interface与Data Exchange参数组用来配置生成代码的接口及数据记录的方式,如无特殊要求建议使用默认配置。

    Verification

    Verification子标签页面主要是关于代码验证方式SIL与PIL的配置,是否使能代码中函数执行时间记录、代码覆盖度记录,以及是否创建用于SIL与PIL的模型等。

    Code Style

    Code Style子标签页面提供了一些关于代码风格的选择框选项,如if else分支的完整性确保,if else与switch case语句的选用,生成括号的频度,是否保留函数声明中extern关键字等。

    Template

    Template子标签页面内为嵌入式编码器提供了一族默认的代码生成模板。

    ert_code_template.cgt中使用TLC变量方式规定了文件生成的顺序及添加模型信息注释的位置。模型生成的源文件、头文件及全局数据存储和外部方法声明文件的生成可以使用统一模板。

    File customization Template则提供给用户自定义代码生成过程的文件输入,用户根据应用场景需要可以调用读入/写入目标硬件的TLC文件、自定义函数或注释,甚至根据模型的单速率/多速率不同分别调用不同的主函数模板等。

    ert_code_template.cgt中主要规定了代码段的顺序。 

     Generate an example main program提供是否生成一个示例主函数的选项。这个示例主函数名为ert_main.c,包含一个main()函数和一个调度器代码。主函数调用模型初始化函数model_initialize()初始化模型需要的数据,以及复位异常状态标志;调度器代码仅提供一个模型每个采样时间点应该执行的函数模板rt_Onestep(),此函数应该绑定到目标硬件的定时器中断上作为其中断服务函数(ISR),执行周期应该与模型基频(即固定点解算器的步长)一致,内部应该调用模型单步函数model_step()。另外,rt_Onestep()内部应该对其调用进行溢出检测。

    Code Placement

    Code Placement子标签页面提供的选项将影响生成代码的组织方式和数据存储方式及头文件包含的分隔符选择等。

    File packaging format表示文件的组织方式。

    File packaging format 生成的文件列表 省去的文件列表
    Modular

    model.c

    subsystem files(optional)

    model.h

    model_types.h

    model_private.h

    model_data.c(conditional)

    -
    Compact(with separate data file)

    model.c

    model.h

    model_data.c(conditional)

    model_types.h

    model_private.h

    Compact

    model.c

    model.h

    model_types.h

    model_private.h

    model_data.c

    省去的只是文件个数,其内容被合并到了其他文件中。

    省去的文件 内容转移目标
    model_data.c model.c
    model_private.h model.c和model.h
    model_types.h model.h

    Data Type Replacement

    该子标签页提供一个选择框,勾选之后出现3列数据类型列表。

    前两列按照数据类型的对应关系给出了每种数据类型在Simulink和嵌入式编码器生成代码中的类型名,第3列工用户设置,填入自定义的类型名之后 ,生成代码时将使用自定义的类型名替换Code Generation Name。用户填入的自定义类型名不仅是一个别名字符串,还必须在Base Workspace中定义其作为Simulink.AliasType类型对象才可以。第3列不必全部填满。

    Memory section

    Memory section(新版Code Generation→Advanced parameters中)可以设置函数、常数、输入/输出、数据和参数的存储段。存储段的设置主要面向模型等级函数和顶层模型的内部数据。

    完成配置后按下Ctrl+B或者在Command Window中输入rtwbuild(gcs),即启动模型编译。

    >> rtwbuild(gcs)
    ### Starting build procedure for model: example
    ### Generating code and artifacts to 'Model specific' folder structure
    ### Generating code into build folder: C:UserslenovoDesktopexample_ert_rtw
    ### Invoking Target Language Compiler on example.rtw
    ### Using System Target File: D:matlab2018a
    twcertert.tlc
    ### Loading TLC function libraries
    ......
    ### Initial pass through model to cache user defined code
    .
    ### Caching model source code
    .......................
    ### Writing header file example_types.h
    ### Writing header file example.h
    .
    ### Writing header file rtwtypes.h
    ### Writing source file example.c
    ### Writing header file example_private.h
    ### Writing source file example_data.c
    ### Writing source file ert_main.c
    ### TLC code generation complete.
    .### Creating HTML report file example_codegen_rpt.html
    ### Using toolchain: LCC-win64 v2.4.1 | gmake (64-bit Windows)
    ### Creating 'C:UserslenovoDesktopexample_ert_rtwexample.mk' ...
    ### Successful completion of code generation for model: example

    若勾选了生成报告的选项,则编译完成会自动弹出Code Generation Report。

    若配置无误,编译成功,在与模型名相同的.c文件中会包含model_step()函数,此处为example_step(),这里的代码表示模型所搭建的逻辑。

    17.2.2 代码生成的流程

    模型生成代码的顺序之前已经提及,首先通过 rtwbuild命令将模型编译为rtw文件,Simulink Coder中的目标语言编译器(Target Language Compiler)将rtw文件转换为一系列的源文件,在这个过程中TLC所使用的文件包括3类:系统目标文件(ert.tlc、grt.tlc等)、模块的目标文件(如与S函数配套的TLC文件)和支持代码生成的TLC函数库等文件。

    模型的源代码全部生成之后,可以使用Simulink提供的模板自动生成makefile来编译链接得到目标文件,也可以将生生成的源代码加入到目标芯片所使用的编译集成环境IDE的工程项目中去,使用IDE编译链接,最终通过仿真器下载到目标硬件中进行实机运行。

     6个更细致的阶段:Entry、Before TLC、After TLC、Before Make、After Make和Exit。在保持顺序执行的前提下,每个阶段都可以由用户追加一些自定义行为,进行模型内部约束关系的检查,或者是链接外部第三方开发工具等。

    在Entry阶段,可以对自定义目标进行预配置参数配置和检验等操作;Before TLC是代码生成之前的阶段,可以将需要用到的编译信息存储到一个结构体中管理,或者将编译需要的头文件、源文件和库文件等进行路径定位和添加;After TLC是代码生成之后的阶段,可以将生成代码文件夹需要的文件拷贝到目标芯片的集成编译环境工程文件夹内以备使用;在Before Make阶段可以对代码进行分析、验证和模型或模块的用户设置检测等;After Make则可以通过MATLAB控制集成编译环境自动生成工程文件,更新其中生成的代码列表,并自动编译链接及下载到目标硬件中;Exit阶段则可以将整个过程是否顺利执行的信息进行显示或临时变量清除等操作。

    rtw文件

    rtw文件作为模型编译器的输入文件和编译过程的中间产物,记录了模型创建信息和编译信息、名字与版本号、配置参数集、输入输出、参数等所有信息。在原Debug子标签页面,新版Code Generation→Advanced parameters中,可以选择保留。

    rtw文件的构成元素是record,称为记录,格式如下:

    recordName{itemName itemValue}
    

    rtw文件的这一条条记录是按照层次进行划分的,最上层是CompiledModel,具有全局的访问范围,向内注册呢个分别是System、block,每条记录都由一个统领关键字和一对{ }构成,{ }内部成为统领关键字的域,访问域中成员与结构体访问的方法一致。如:

    CompiledModel.Subsystem[0].Block[0].Parameter.Value;

    追加信息使用addtorecord命令,如:

    % addtorecord CompiledModel Author{Name "Custom"}
    

    TLC文件

    tlc文件即TLC编译器所编译的目标文件。

    • 系统目标文件:规定生成代码的全局结构,以匹配所支持的目标芯片群及目标语言。
    • 模块目标文件:规定Simulink模块生成代码时的代码实现,一般与模块的S函数同名,存储在同一文件夹下,并从S函数中获取参数信息以生成代码。

    在TLC运行阶段,首先运行的就是系统目标文件,如ert.tlc,系统目标文件是TLC运行的起点,其他TLC文件会被其调用,整个执行过程按照TLC命令行逐一执行。TLC文件执行过程中,会读取、增加或修改rtw文件中的记录信息。

    17.2.3 代码生成方法与技巧

    Simulink模代码生成的结构

    Simulink信号线在不同存储类型下的代码生成

    右击某根信号线,打开属性对话框,第2个标签页是关于信号线代码生成的配置页面。

    Configuration Parameter→Simulation Target→Signal storage reuse

     

    勾选此项时,生成代码会为了节省存储用量而不为中间信号生成中间变量;反之,不勾选时,Simulink为每一个模块的额输出生成一个中间变量。在模型规模很大时,不勾选Signal storage reuse将会增加很多存储用量,建议勾选。 

    Signal object class默认时部分不同存储类型下信号线生成代码比较方式:

    信号线存储类型 生成代码声明方式 生成代码
    Auto(signal storage reuse:on)  -
    codegen_01_Y.Out1=(codegen_01_P.Gain_Gain*codegen_01_U.In1+codegen_01_U.In2)*codegen_01_U.In3;
    Auto(signal storage reuse:off)
    In model.h:
        typedef struct{
            real_T Gain
            real_T line
        }B_codegen_01_T;
    codegen_01_B.Gain=codegen_01_P.Gain_Gain*codegen_01_U.In1;
    codegen_01_B.line=codegen_01_B.Gain+codegen_01_U.In2;
    codegen_01_Y.Out1=codegen_01_B.line*codegen_01_U.In3;
    ExportedGlobal
    In model.h:
        extern real_T line;
    In model.c:
        real_T line;
    line=codegen_01_P.Gain_Gain*codegen_01_U.In1+codegen_01_U.In2;
    codegen_01_Y.Out1=line*codegen_01_U.In3;
    ImportedExtern  
    In model_private.h:
        extern real_T line;
    line=codegen_01_P.Gain_Gain*codegen_01_U.In1+codegen_01_U.In2;
    codegen_01_Y.Out1=line*codegen_01_U.In3;
    ImportedExternPointer  
    In model_private.h:
        extern real_T *line;
    *line=codegen_01_P.asg_Gain*codegen_01_U.In1+codegen_01_U.In2;
    codegen_01_Y.Out1=*line*codegen_01_U.In3;

    Simulink模块代码生成的接口

    默认ert.tlc作用下生成的接入点函数有2个:model_initialize()和model_step(),model_initialize()将在model_step()函数运行之前调用一次对模型进行初始化,model_step()函数将在每个rt_Onestep中被周期性调用(需要绑定到目标硬件上实现)。其实model_step()函数内部包含2个子函数model_update()和model_output(),分别用于计算模型中的离散状态变量及模型的输出,通过Single output/update function选项可以选择合并生成或分开生成。

    通过勾选Terminate function required,可以生成model_terminate()函数。

    Classic call interface默认不勾选,生成的代码层次较少,执行效率较高;若勾选此选项,模型生成的代码将按照C MEX S函数的各个子方法组织,得到非常复杂的处理机制。

    模型的信号和状态,二者相辅相成,信号作为模型输入/输出和连接的桥梁,状态则为模型不同时刻的数据缓冲提供支持。默认情况下它们会分别生成到各自的结构体中,如果勾选了Combine signal/state structures,那么生成代码时模型中的信号变量和状态变量会结合在一个结构体变量中。

    Configure Model functions按钮在真正意义上提供了一个自定义模型入口函数和子系统函数接口的方式,这个按钮仅在系统目标文件为ert.tlc及以ert.tlc为基础系统目标的文件中存在。

    (1)Simulink模型入口函数接口自定义

    在这里用户可以修改模型初始化函数名及Step函数名。Get default能够获取自定义默认参数列表。Port Name为端口名,只读;Port Type为端口类型,只读;C Type Qualifier为变量限定符,C Identifier Name为参数变量名。

    Validate按钮会对模型进行检验。

    (2)Simulink模型子系统函数接口自定义(原子子系统)

    子系统的代码生成:右击子系统→C/C++ Code→Build This Subsystem。

    RTW.configSubsystembuild(gcbh)

    为了定义子系统的入口函数,使用该命令启动子系统Model Interface对话框,使用这个命令的前提是模型系统目标文件是ert.tlc。

    整个模型生成时,上述配置完全不起作用,要使在整个模型编译生成代码时自定义子系统的函数接口,需要右击子系统→Block Parameters(Subsystem)。

    Function packaging:

    选项 功能
    Auto Simulink Coder基于模型中子系统的个数和类型自动选取最优的代码生成格式,此时不能控制子系统生成的函数名及所存放的文件
    Inline 直接将子系统代码内联展开
    Nonreusable function 子系统生成一个函数,函数的参数列表由Function Interface参数决定,函数名及函数所存放的文件都可以指定
    Reusable function 当模型中存在同一个子系统的多个实例时,Simulink Coder为其生成带有可重用参数列表的函数,函数名及函数所存放的文件都可以指定

    Simulink自定义存储类型与信号/参数数据对象

    信号是信号线中传递的数据,随着模型的采样时刻不断变化,通常都是计算得出的量;参数是模型中的各种常数,如Gain的增益,既可以是算法的参数也可以是实验得到的数据,在模型执行过程中不发生变化。在MCU中,信号存储在RAM中,参数存储在ROM中。

    (1)Simulink包与数据对象

    CSC名 功能 是否可用于信号 是否可用于参数
    Default 数据对象的属性CoderInfo.CustomStorageClass的默认设置,直接使用模型中的变量或参数名到代码中
    Bitfield 声明支持布尔类型的位域结构体类型
    Volatile 生成Volatile类型标示符变量
    ExportToFile 生成一个头文件,用户指定其名称,内部包含全局变量声明,model.h中会生成包含此头文件的#include命令
    ImportFormFile 生成头文件包含命令,include包含全局变量声明的头文件,所包含的文件名由用户指定,在model_private.h中生成#include命令
    FileScope 为变量声明时生成静态后缀以限定访问范围在当前文件
    Struct 将信号或变量生成结构体结构
    GetSet 跟Data Store Memory Block联合使用支持特殊函数调用,如对某地址的读取与写入接口函数
    Reusable 当一对I/O信号设置为Reusable并且有相同信号名时

    位域是嵌入式C代码中常用的数据结构。对于有些变量,它不需要占据一个完整的字节,如果单独给它分配一个字节太过浪费,特别对于嵌入式MCU芯片而言,资源紧张,必须使用紧凑的存储空间排布。位域可以将一个完整的字节划分为多个不同的二进制位区域,每个二进制位域存放一个0或1。

    也可以通过在Base Workspace中创建数据对象,再将其绑定到信号线上以生成代码。

    dataobj=Simulink.Signal;

    双击这个变量启动数据对象的属性对话框。

    通过k=Simulink.Parameter可以创建一个参数的数据对象。

    in1 = Simulink.Signal;
    in1.InitialValue = '0';
    in1.StorageClass = 'Struct (Custom)';
    in1.CoderInfo.CustomStorageClass = 'Struct';
    in1.CoderInfo.CustomAttributes.StructName = 'input';
    
    in2 = Simulink.Signal;
    in2.InitialValue = '0';
    in2.StorageClass = 'Struct (Custom)';
    in2.CoderInfo.CustomStorageClass = 'Struct';
    in2.CoderInfo.CustomAttributes.StructName = 'input';
    
    out = Simulink.Signal;
    out.InitialValue = '0';
    out.StorageClass = 'Struct (Custom)';
    out.CoderInfo.CustomStorageClass = 'Struct';
    out.CoderInfo.CustomAttributes.StructName = 'output';
    
    
    line_h = find_system(gcs, 'findall' , 'on', 'Type', 'line');
    set(line_h, 'MustResolveToSignalObject', 1);
    

    将信号线绑定同名数据对象后,信号线张有一个蓝色三叉标记。

    取消绑定通过set(line_h, 'MustResolveToSignalObject', 1);实现。

    GetSet这个存储类型的使用有些特殊,需要Data Store Memory模块、Data Store Read/Write模块配合使用。Data Store Memory模块定义一个变量名指向一片存储区域,在同一层模型或子模型的Data Store Read/Write模块都可以对这块存储区域进行读/写操作。Data Store Memory中的信号名与Base Workspace中定义的信号数据对象绑定以后,可以设置生成代码中读取/写入此信号的接口函数。当数据对象的存储类型被设置为GetSet之后,其CustomAttribute属性的3个子属性用于设置生成代码时的函数接口。

    属性名 功能
    GetFunction 读取存储地址的函数名
    SetFunction 写入存储地址的函数名
    HeaderFile 可选项,设置需要包含的头文件全名,该头文件中应该声明上述2个参数中配置的函数原型

    (2)mpt包CSC与数据对象

    mpt包是Simulink软件提供的另一个内建类,包括信号与参数2中数据对象,分别使用mpt.Signal和mpt.Parameter创建。

    它比Simulink能够提供更多的CSC类型,如Global和StructVolatile。

    Global存储类型将信号或参数数据对象作为全局变量声明及定义在代码中,是mpt包的默认CSC选项。HeaderFile和DefinitionFile即为声明和定义全局变量的文件名。全局变量声明时以extern作为限定符。MemorySection提供了数据对象生成代码时的限定符。

    StructVolatile存储类型将在生成的机构体变量前面增加Volatile限定符。

    数据对象的创建和设定既可以通过信号线属性对话框、Data Store Memory参数对话框或M代码,也可以使用Model Explorer创建和管理。启动Model Explorer有3种方式。

    1. 工具栏
    2. 在Command Window中输入sfexplr或者slexplr命令;
    3. 选中模型Ctrl+H。

    Model Explorer为Simulink模块、信号、工作空间的变量和数据对象提供了一个集中管理和编辑的场所。

    通过这些按钮可以新建一个变量、信号数据对象或参数数据对象。

    Simulink其他数据对象

    除了Simulink.Signal和Simulink.Parameter这两个数据对象以外,Simulink类还有AliasType、NumericType和Bus等子类。

    其中Simulink.Bus和Simulink.BusElement用来配合Bus Creator模块创建和管理Bus变量对象及其成员。

    Simulink.AliasType是为一个数据类型定义别名的类;Simulink.NumericType提供了一个定义数据类型的功能。

    custom_float=Simulink.AliasType;
    

    Base type是别名对象的基础类型;Data scope是代码生成的相关属性,表示这个别名数据类型的定义所存放的位置;Header file中填写定义数据类型别名的头文件名;Description中可以添加此别名对象相关的文本信息,对模型生成没有影响。

    模型开启Replace data type names in the generated code时,即可使用数据类型别名定义功能,这样做的好处是方便代码移植。

    例如,下面提供了一种替换样例:

    replaced_type = {'FLOAT64','FLOAT32','INT32','INT16','INT8','UINT32','UINT16','UINT8','BOOL','INT32','UINT32','CHAR'};
    base_type = {'double','single','int32','int16','int8','uint32','uint16','uint8','boolean','int32','uint32','uint8'};
    type_num = length(replaced_type);
    for ii = 1: type_num
        eval([replaced_type{ii},' = Simulink.AliasType; ']);
        eval([replaced_type{ii},'.BaseType = base_type{ii};']);
        assignin('base', replaced_type{ii}, eval(replaced_type{ii}));
    end

    此时工作区可以查看这些定义好的数据类型别名对象。

    定义后在信号属性对话框中Data Type下拉框中可以使用自定义的数据类型别名对象。。

    Simulink.NumericType数据对象比Simulink.AliasType功能更多一些,不仅可以创建一个数据别名对象继承既有数据类型,也可以创建一个全新的自定义数据类型。

    Simulink模型创建数据词典

    当模型所包含的Simulink包和mpt包的数据对象个数较少时,使用M语言或者属性对话框及Model Explorer来创建数据对象都可以。当一个模型结构复杂,包含成百上千个信号和参数时,其数据对象的创建和存储可以通过数据词典(Data Dictionary,简称DD)管理。

    数据词典的内容包括信号量和参数量,可根据信号/参数数据对象的属性编制DD的表头,例如:

    clc
    clear 
    % read dd
    [sig_data, sig_str] = xlsread('DataDic.xls',1);
    sig_name = sig_str(2:end, 1);
    sig_dimensions = sig_data(:,1:2);
    sig_description = sig_str(2:end,4);
    sig_min = sig_data(:,4);
    sig_max = sig_data(:,5);
    sig_initval = sig_data(:,6);
    sig_units = sig_str(2:end, 8);
    sig_datatypes = sig_str(2:end, 9);
    sig_csc = sig_str(2:end, 10);
    
    % get num of signals
    sig_num = size(sig_data, 1);
    
    % create signal ojects 
    for ii = 1: sig_num
        eval([sig_name{ii}, ' = Simulink.Signal;']);
        eval([sig_name{ii}, '.Dimensions = [', num2str(sig_dimensions(ii,:)),'];']);
        eval([sig_name{ii}, '.Description = ''', sig_description{ii},''';']);
        eval([sig_name{ii}, '.Min = ', num2str(sig_min(ii)),';']);
        eval([sig_name{ii}, '.Max = ', num2str(sig_max(ii)),';']);
        eval([sig_name{ii}, '.InitialValue = ''', num2str(sig_initval(ii)),''';']);
        eval([sig_name{ii}, '.DocUnits = ''', sig_units{ii},''';']);
        eval([sig_name{ii}, '.DataType = ''', sig_datatypes{ii},''';']);
        eval([sig_name{ii}, '.CoderInfo.StorageClass = ''', sig_csc{ii},''';']);
    end
    
    %% if user create model with lines named as Simulink.Signal name then it is ok to run codes below.
    % line_h = find_system(gcs, 'findall' , 'on', 'Type', 'line');
    % set(line_h, 'MustResolveToSignalObject', 1);

    Simulink中的实时任务调度及代码生成

    模式 单速率 多速率
    单任务 支持 支持
    多任务 不支持 支持

    当模型中所有模块都按照同一个采样时间设置时,成为单频率系统,当存在多个不同的采样时间时,称为多频率系统。所谓任务,在模型中由不同的子系统来表现。

    (1)单速率单任务系统调度代码生成

    这种情况下rt_OneStep()将在每一个采样时刻调用model_step()函数一次。

    (2)多速率多任务系统调度代码生成

     在多速率多任务系统中,生成的代码采用一种按优先级分类的可抢占式的机制。模型中包括了NumTask个任务,与模型的固定解算器步长相同周期的任务为基速率,其他任务的执行周期都是基速率的整数倍,称为子速率。基速率的子系统生成的代码为model_step0,其余子速率的任务按照执行周期的快慢生成的代码为model_step1~model_stepNumTask-1。

    在NumTask个任务中,基速率的任务是周期最短,执行频率最高的一个,同时也具有最高的优先级;其他子任务则按照执行周期从短到长依次具有逐渐降低的优先度。

    在每个MCU定时器中断时刻,对每个子速率系统是否需要被执行进行检测,这些标志位存储在eventFlags数组中,数组中每个成员表示一任务的执行标志,只有eventFlags[n]为真时,才会在当前rt_OneStep()中执行model_stepn。是否将eventFlags数组中的元素置位,取决于数组taskCounter,其元素表示各个任务的计数值。taskCounter在每次rt_Onestep()被调用时对各子速率对应的计数值+1,当达到该子速率周期/基速率周期值时taskCounter被清零,接着eventFlags的对应位变为1,从而形成了rt_OneStep()调用对应model_stepn()函数的条件。

    (3)多速率单任务系统调度代码生成

    模型生成的rt_OneStep()函数的代码同单速率单任务的代码相似,区别在于model_step()函数的内部,不同速率的调度代码在内部生成。代码通过数组对多个子速率分别进行计数,当计数值达到阈值后被清零并执行对应的子速率代码。

  • 相关阅读:
    IP地址分类整理
    PHP
    [转载]数组的全排列问题
    使用 Homebrew 安装 Git
    Homebrew简介及安装
    iOS开发~CocoaPods使用详细说明
    关于目前自己iOS项目使用的第三方开源库
    IOS 时间格式 时间转换 大总结
    Xcode磁盘空间大清理
    Swift百万线程攻破单例(Singleton)模式
  • 原文地址:https://www.cnblogs.com/dingdangsunny/p/12269461.html
Copyright © 2011-2022 走看看