Engee 文档

代码生成器功能

生成的代码中的内部函数

AnyMath 代码生成器支持 虚拟原子 子系统进行代码生成。 虚拟子系统仅为模型中的可视层次结构服务,而原子子系统表示单个执行单元(或生成代码中的函数)。 子系统属性中的配置 视为原子单位 允许您使子系统虚拟或原子。 Virtual 子系统内的所有计算都直接嵌入(内联)到封闭子系统或模型的代码中。 这可以提高生成代码的性能,但会降低模型的可读性和可追溯性。 Atomic 子系统内的所有计算都在具有子系统名称的单独函数中生成。 然后在底层子系统或模型的代码中自动调用此函数。 这可以提高生成的代码对模型的可读性和可追溯性,但会降低性能。

例如,转 滚码机 从模型 autopilot_roll.工程师 (见 代码生成示例)到原子子系统:

gs atomic vs virtual cn

保存模型并再次生成代码。 生成的代码现在有一个名为 滚码机 (对应于模型中的子系统名称)。 该函数在函数内部调用 自动驾驶仪,其表示封闭模型的代码。 功能 滚码机 声明为 静态 因此,这是该模型的内部函数。

代码生成器会忽略已禁用的块,并且不会创建关联的代码。

comment out 1 cn

生成的代码中的参数

模型块中的参数

在模型块中,可以设置参数:

  • 以数字的形式(例如, 0.2);

  • 表达式的形式(例如, 0.2 + 0.7);

  • 以来自*AnyMath*工作区的变量名称的形式(例如, Kp).

在生成的代码中,参数与模型中设置的值嵌入(内联)。:

  • 简单的数值"按原样"添加到代码中,不需要额外的操作。;

  • 仅由数字组成的表达式可以简化(常量折叠),并且计算的数值将进入代码。;

  • 由变量名指定的值(例如, Kp),以及包含变量的表达式(例如, Kp+1),被认为是可调谐的,并落入结构 modelname_P —即使选择了"嵌入式"模式。

可配置参数

默认情况下,规则适用:对变量的任何引用(例如, Kp)或包含变量的表达式(例如, Kp+1)使参数可配置并将其放入 modelname_P —无论设置 内置/可定制。 在"可配置"模式中 modelname_P 所有参数都包括在内,包括数字文字。

一些块参数可以被设置为可配置的(可调谐),以便在代码生成后可以更改它们。 这些参数存储在结构中 modelname_P 看起来像这样:

  • 如果参数是通过变量名设置的(例如, Kp),则其名称保存在结构中:

    struct P_modelname_T_ {
        double Kp;
    };
  • 如果参数设置为带有变量的表达式(例如, Kp+1),则使用块中参数的名称(例如, 振幅):

    struct P_modelname_T_ {
        double Amplitude;
    };

在所有情况下,结构中的参数都是 modelname_P 它们填充有可从模型获得的计算值,例如:

P_modelname_T modelname_P = {
    0.5 // Значение параметра
};

使用选项 默认参数行为设置窗口 debug article icon 1 您可以控制哪些参数将在生成的代码中保持可配置。:

behavior setting 1 cn

  • Inline—​只有相同数字的数字文字和表达式直接插入到代码中,并且*不要*进入 modelname_P. 由变量名称或变量表达式指定的任何参数都保持可配置,并*落入 modelname_P.

  • 可调—​所有参数,包括数字参数,都放在 modelname_P;数值不是内联的。

example:内置模式,幅度由变量设置 a

当选择"Embedded"和block参数时 振幅=a:

  • In字段将出现在代码中。 modelname_P (例如, 双a; 或由参数标签字段的名称,如果表达式与使用 a);

  • 档案 model_data。c 获取原始值 a 从工作区;

  • * 值本身不会是固定的,它可以在不重新组装的情况下进行更改。

这是预期的行为:对变量的引用被视为"可配置"。

屏蔽块的参数

如果块有 掩码,则其参数基于所选模式进行处理"默认参数行为". 有两种模式可供选择:

  • "嵌入"模式--如果可能,屏蔽参数将作为数值嵌入到生成的代码中。

    • 如果将掩码参数用作表达式的一部分(即对其应用操作或函数),则会为相应的块属性生成具有类型名称的自定义参数。 块名称_property.

    • 如果直接插入屏蔽参数(无需额外计算),则将其作为数值常量插入代码中。

    • 但是,其他规则保持不变:来自工作区的变量(不是掩码参数)被视为可配置参数,数字字面量和简单数字表达式嵌入到代码中。

  • "可配置"模式--每个块的每个参数(包括屏蔽块的参数)变成单独的可配置参数。

    • 即使是简单的数值 也不会 嵌入到代码中,而是存储为结构的字段。 modelname_P (例如,正弦信号的幅度参数将成为场 新的,新的).

    • 对于来自工作区的变量,规则保持不变:一个变量对应于结构的一个字段(即使它在不同的块中使用)。

对于屏蔽块的每个实例,其参数被单独处理。

例如,两个不同的屏蔽块与参数 帕拉姆:

  • 在*"Embedded"*模式下,每个值都将在代码中有自己的嵌入值(或在 modelname_P 如果表达式中使用此参数);

  • 在*"可配置"*模式下,这些参数将反映在具有唯一名称的两个不同字段中(根据参数命名规则below)。

生成代码中变量的命名规则

AnyMath代码生成器使用单一机制来形成所有模型实体的名称:块、子系统、参数、临时变量和模型本身。 该方法基于顺序(即时)名称生成,其中以前创建的名称具有更高的优先级并且不再更改。 这种方式保证了变量命名的稳定性和可预测性。

基本命名原则:

  • * 任何名称都必须是有效的C语言标识符*。

  • 无效字符(空格,西里尔字母,特殊字符,表情符号)将被删除或替换为下划线。

  • 如果无法正确转换,则使用块类型或子系统*的名称*。

  • 名称在其作用域中必须是* 唯一*-在冲突的情况下添加后缀。 _1, _2, _3…​

  • 名称按顺序* 生成,以前创建的名称优先。

  • 解决冲突有利于遇到的第一个名字。

如果您希望生成的代码中的变量名称与块名称完全匹配,请为块指定一个名称,该名称是C语言的正确标识符。 在这种情况下,名称以 ,以及包含 _,也被认为是不正确的,将被转换。

名称转换规则:

  1. 如果块名称是C代码的正确标识符,则生成器会尝试保持不变。

  2. 如果块名称是英文的(拉丁字母,数字和符号),则 - 代之以 ,空格和其他字符被删除,字母,数字和 得救了。

  3. 如果块名称是俄语(西里尔文),则生成的代码使用 块类型 和来自原始名称的数字后缀(如果有的话)。

代码生成器保证生成的名称的唯一性,即使模型包含具有相同名称的块(例如,在不同的非原子子系统中)。 如果代码中出现相同的名称,则生成器会添加后缀。 _1, _2, _3 依此类推-这样名称保持唯一。

转换示例:

  • 我的锁我的锁

  • 正弦波-1SineWave_1

  • 入口1港口1

  • 增益因子-42盖恩42


块的命名遵循以下规则
  • 如果模型中的块名有效,则使用该块名。

  • 无效字符将被替换或删除。

  • 如果名称无法规范化,则使用块类型(例如, 增益, 步骤).

  • 如果名称匹配,则会自动添加数字后缀。

例子::

模型中的名称 代码中的名称

增益

增益

增益(子系统中的第二个)

Gain_1

无效

Gain_2

增益-1

增益_1_1


子系统命名规则:

  • 名称规范化的执行方式与块相同。

  • 如果子系统是原子的,则其名称将成为生成的C函数的名称。

  • 如果存在名称冲突,则会添加后缀。

  • 如果无法更正名称,则使用子系统类型名称(子系统).

例子::

模型中的名称 代码中的名称(函数)

子系统

子系统

Aaaab

Aaaab

子系统

副系统_1

不负责任-1

___1


可配置参数的命名(modelname_P)是基于参数源的类型:

如果参数设置为工作区变量:

  • 变量名使用不变。

  • 一个变量对应于一个字段,即使它在几个块中使用。

double Kp;
double x;

如果直接在块中设置参数:

  • 该方案用于 Block_name属性.

  • 如果块名称不正确,则使用 Block_name类型.

  • 如果存在名称冲突,则会添加后缀。 _1, _2, …

例子::

double MySine_Amplitude;
double SineWave_Amplitude_1;
double Step_Time;

函数内临时变量的形成:

  • 它们是自动按顺序创建的。

  • 临时变量的名称与块和参数的名称不重叠。

  • 它们被调整为有效的Si标识符。

  • 它们仅在功能范围内使用。

例子::

double tmp_3;

生成的代码的接口和集成到外部开发环境

生成代码的接口

生成的代码的外部接口可以在生成的文件中看到。 modelname.h. 外部接口包括用于处理生成的代码的函数和结构。:

  • modelname_init -是模型初始化函数-必须调用一次;

  • modelname_step —是模型的入口点,包含模型的算法—必须按照计算模型的步骤定期调用;

  • modelname_U -结构包含模型的外部输入端口;

  • 模型名称_y -结构包含模型的外部输出端口;

  • modelname_S -结构包含模型的内部状态;

  • modelname_P -结构包含可配置的模型参数。

集成到外部开发环境中

使用生成文件的功能和结构 modelname.h 在外部代码(手动编写)中,您需要执行以下操作:

  1. 附加生成的头文件:

    #include "modelname.h"
  2. 组织对生成函数的单个调用 初始化 在你的 主要:

    modelname_init();
  3. 组织对生成函数的定期调用 步骤 在你的 主要 用正确的步骤:

    modelname_step();
  4. 组织输入和输出数据与函数之间的传输 步骤:

    /* Устанавливаем значения входов */
    modelname_U.input1 = 42;
    /* Вызываем функцию step */
    modelname_step();
    /* Можно использовать modelname_Y.output1 */

生成的文件

AnyMath 中构建模型并生成其代码后(使用命令 恩吉。generate_code() 或按钮 生成代码 codegen icon 1)自动生成的文件被创建,其中包含c语言中模型的实现。 下面是这些文件及其用途的描述。

codegen all generated files cn

  • modelname.h -描述模型外部接口的头文件。 它包括从外部代码使用模型所需的函数和结构(有关详细信息,请参阅 )。 部分中还描述了将这些函数和结构连接到外部应用程序的过程

  • modelname.c -与模型的逻辑的实现的文件。 它包含所有变量的定义和模型关键功能的实现。:

    • 初始化() -设置变量和模型状态初始值的初始化函数;

    • 步骤() -主要计算功能。 执行一个仿真步骤的计算并更新输出值;

    • 期限() -模型的关闭功能。

  • model_data。c -具有模型参数初始初始化的文件。 它设置执行模型时使用的所有可配置参数的值。 例如:

    • 信号幅度和频率;

    • 相位,偏移;

    • 样数等参数。

      这些全局参数是可配置的,并且可以在可执行代码运行时更改。 这使您可以灵活地控制模型的行为,而无需重新组装逻辑或编辑主要功能。

      在"嵌入式"模式中 model_data。c 只包括通过变量或带有变量的表达式指定的参数;数字字面量和纯数字表达式 不是 写在那里(它们嵌入在代码中)。
  • 主要。c -带有使用模型示例的文件。 这是演示如何从C程序初始化和调用模型的主要可执行文件。 包含:

    • 初始化() -模型的初始化函数,在开始工作前调用一次;

    • 步骤() -执行计算模型的一个步骤的主要计算函数。 它通常被称为定期,根据指定的积分步骤。;

    • 期限() -模型的关闭功能。

      档案 主要。c 它不包含模型操作的算法,而只是演示如何在具有C代码支持的应用程序中正确启动和管理其执行。 主要。c 它应该用作将模型集成到用户项目中的模板。

支持的数据类型

生成的代码中的数据类型与 AnyMath 模型中的数据类型相对应。

如果用户未在模型中指定数据类型,则使用与该类型对应的双精度浮点数据类型。 双倍 在C.对于生成布尔结果的逻辑运算或计算(真(1)错误(0)),数据类型使用 布尔值,对应于Si中的八位无符号数据类型。

要在模型中显示数据类型,请在 设置窗口 debug article icon 1 在"调试参数"选项卡中,启用该选项 数据类型 .

矢量化

代码生成器支持模型中的矢量数据类型,包括矢量和矩阵。 向量运算的代码中生成标准循环。 而不调用特定的BLAS或LAPACK函数。

复数

代码生成器支持模型中的复杂数据类型。 对于复杂类型,使用标准头文件中的类型。 <复杂。h>.

多频型号

AnyMath 模型可以是多频率的,即它们包含几种不同的采样率。 应用区块 Rate Transition,以及通过设置参数 样本时间 块和子系统,用户可以控制与哪个计算步骤块或块组一起工作。

AnyMath代码生成器支持多频模型的代码生成。 为此,块按频率分组,并且用户可以控制这些不同频率在生成的代码中如何表示。

定制化 多速率代码生成 允许您控制多频率模型的生成代码的操作模式。 "单任务"代码允许您生成单个函数。 步骤 为模型。 "多任务"代码允许您生成多个功能。 步骤 对于模型,其中每一个对应于模型中的特定采样率。

multirate model setting cn

单任务代码 包含条件(以 如果)生成的函数内部 步骤,它包装模型中较慢频率的调用。 功能 步骤 它包含以模型的基本频率(最快频率)操作的块。 从自定义绑定,提供一个函数调用就足够了 步骤 与此同时,较慢频率的呼叫的调度和频率之间的信息交换在生成的代码本身中自动进行。

多任务代码 包含几个功能 步骤_n 在生成的代码中,每个代码都对应于其在模型中的频率。 功能 步骤_0 对应于模型中最快的频率(基频),函数 步骤_1 第二较慢的频率,等等。 需要从自定义绑定提供函数调用 步骤_n 用必要的计算步骤。 在生成的代码本身中自动提供不同频率之间的数据交互。

生成的代码中的注释

默认情况下,生成的代码包含注释,允许您将代码跟踪到模型中的块。

定制化 包括评论 在小组中 代码生成 它们允许您管理生成代码中的注释,并在必要时完全禁用它们。

代码验证

验证是指用块生成验证模型 C Function,其仿真结果必须与具有相同输入数据的原始模型的仿真结果相匹配。

C Function 它可以自动创建以验证生成的代码。 为此,请选中此框 生成 C 功能块 在设置窗口中 lk 5:

c function codegen cn

下次生成代码时(通过界面、上下文菜单或命令 generate_code)目录下 ouput_迪尔 该文件将出现 modelname_verification.jl (如果目录不存在,它将自动创建)。 此文件将包含一个可以在脚本编辑器中执行的脚本(通过双击) interactive scripts icon 或命令行 command line icon:

include("path/to/verification.jl")

该脚本将创建一个名称为AnyMath模型 modelname_verification.工程师 还有一个街区 C Function,其中使用生成的代码:

model generated cfunction cn

Verilog语言的代码生成也可在 AnyMath 中使用。 有关详细信息,请参阅文章 Verilog(HDL)代码生成.

基于自定义模板的代码生成

AnyMath 支持基于自定义模板的代码生成(有关更多信息,请参阅文章 根据自定义模板生成代码).

管理信号名称

代码生成器使用模型中用户指定的信号的名称,使生成的代码更清晰,更容易与模型匹配。 例如:

image14 cn

如果信号(块输出)具有名称,那么生成的代码将为此信号使用相同的变量名称。 只有当信号未被优化并且不包含C代码中不支持的字符时,这才是可能的。

支持的块

AnyMath 代码生成器支持以下库块: