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

保存模型并再次生成代码。 生成的代码现在有一个名为 滚码机 (对应于模型中的子系统名称)。 该函数在函数内部调用 自动驾驶仪_roll_step,其表示封闭模型的代码。 功能 滚码机 声明为 静态 因此,这是该模型的内部函数。
|
代码生成器会忽略已禁用的块,并且不会创建关联的代码。
|
生成的代码中的参数
模型块中的参数
在模型块中,可以设置参数:
以数字形式(例如, 0.2);
*以表达式的形式(例如, 0.2 + 0.7);
*以工作区变量名的形式 *AnyMath (例如, Kp).
在生成的代码中,参数与模型中指定的值嵌入(内联)。:
*简单的数值被添加到代码中 «因为它是»,并且不需要额外的操作; *仅由数字组成的表达式可以简化(常量折叠),计算的数值将包含在代码中。;
|
由变量名称指定的值(例如, |
可配置参数
默认情况下,规则适用:对变量的任何引用(例如, Kp)或包含变量的表达式(例如, Kp+1)使参数可配置并将其放入 modelname_P —无论设置如何 内联/{frontendengeepp_modelcardpp_codegenerationpp_defaultparameterbehavportunable} 。 在模式 可调 在 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 // Значение параметра
};
|
使用选项 默认参数行为 在 设置窗口
|
example:模式 内联 ,幅度由变量设置 a
选择时 内联 和块参数 振幅=a:
*一个字段将出现在代码中 modelname_P (例如, 双a; 或由参数标签字段的名称,如果表达式与使用 a);
*档案 model_data。c 获取原始值 a 从工作区;
*值本身*不会*被指定,它可以在不重新组装的情况下进行更改。
这是预期的行为:对变量的引用被解释为 «可定制».
屏蔽块的参数
如果块有 mask,然后根据所选模式对其参数进行处理 «默认参数行为». 有两种模式可供选择:
模式 *内联 --如果可能,掩码参数将作为数值嵌入到生成的代码中。
如果将掩码参数用作表达式的一部分(即对其应用操作或函数),则会为相应的块属性生成具有类型名称的自定义参数。 块名称_property.
如果直接插入屏蔽参数(无需额外计算),则将其作为数值常量插入代码中。
**但是,其他规则保持不变:来自工作区的变量(不是掩码参数)被视为可配置参数,数字字面量和简单数字表达式嵌入到代码中。
模式 *可调 --每个块的每个参数(包括屏蔽块的参数)变成一个单独的可配置参数。
即使是简单的数值*也不会*嵌入到代码中,而是存储为结构的字段。 modelname_P (例如,正弦信号的幅度参数将成为场 新的,新的).
对于来自工作区的变量,规则保持不变:一个变量对应于结构的一个字段(即使它在不同的块中使用)。
|
对于屏蔽块的每个实例,其参数被单独处理。 例如,两个不同的屏蔽块与参数 在模式 *内联 它们将在代码中有自己的嵌入值(或在 |
生成代码中变量的命名规则
代码生成器 AnyMath 使用单一机制来形成模型的所有实体的名称:块、子系统、参数、临时变量和模型本身。 该方法基于一致的(«飞来飞去»)名称生成,其中以前创建的名称具有更高的优先级并且不再更改。 这种方式保证了变量命名的稳定性和可预测性。
基本命名原则:
*任何名称都必须是有效的C语言标识符。
无效字符(空格,西里尔文,特殊字符,表情符号)被删除或替换为下划线。
*如果无法正确转换,则使用块类型或子系统*的名称。
名称必须是*唯一*在他们的范围-后缀被添加在碰撞的情况下。 _1, _2, _3…
*名称按顺序生成,以前创建的名称优先。
*解决冲突有利于遇到的第一个名字。
|
如果您希望生成的代码中的变量名与块名完全匹配,则为块指定一个名称,该名称是C语言的正确标识符。 在这种情况下,名称以 |
名称转换规则:
-
如果块名称是C代码的正确标识符,则生成器会尝试保持不变。
-
如果块名称是英文的(拉丁字母,数字和符号),则
-代之以,空格和其他字符被删除,字母,数字和得救了。 -
如果块名称是俄语(西里尔文),则生成的代码使用
块类型和来自原始名称的数字后缀(如果有的话)。
代码生成器保证生成的名称的唯一性,即使模型包含具有相同名称的块(例如,在不同的非原子子系统中)。 如果代码中出现相同的名称,则生成器会添加后缀。 _1, _2, _3 以此类推—这样名字就保持唯一了。
转换示例:
-
我的锁→我的锁 -
正弦波-1→SineWave_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 在外部代码(手动编写)中,您需要执行以下操作:
-
附加生成的头文件:
#include "modelname.h" -
组织对生成函数的单个调用
初始化在你的主要:modelname_init(); -
组织对生成函数的定期调用
步骤在你的主要用正确的步骤:modelname_step(); -
组织输入和输出数据与函数之间的传输
步骤:/* Устанавливаем значения входов */ modelname_U.input1 = 42; /* Вызываем функцию step */ modelname_step(); /* Можно использовать modelname_Y.output1 */
生成的文件
在构建模型后 AnyMath 并生成其代码(使用命令 恩吉。generate_code() 或按钮 生成代码
)自动生成的文件被创建,其中包含c语言中模型的实现。 下面是这些文件及其用途的描述。

-
modelname.h-描述模型外部接口的头文件。 它包括从外部代码使用模型所需的函数和结构(有关详细信息,请参阅 上)。 部分中还描述了将这些函数和结构连接到外部应用程序的过程 上。 -
modelname.c-与模型的逻辑的实现的文件。 它包含所有变量的定义和模型关键功能的实现。:-
初始化()-设置变量和模型状态初始值的初始化函数; -
步骤()-主要计算功能。 执行一个仿真步骤的计算并更新输出值; -
期限()-模型的关机功能。
-
-
model_data。c-具有模型参数初始初始化的文件。 它设置执行模型时使用的所有可配置参数的值。 例如:信号幅度和频率; 相位、偏移; **样本数和其他参数。
这些全局参数是可配置的,并且可以在可执行代码运行时更改。 这使您可以灵活地控制模型的行为,而无需重新组装逻辑或编辑主要功能。
在模式 内联 在 model_data。c只包括通过变量或带有变量的表达式指定的参数;数字字面量和纯数字表达式*不是*写在那里(它们嵌入在代码中)。 -
主要。c-带有使用模型示例的文件。 这是演示如何从C程序初始化和调用模型的主要可执行文件。 包含:-
初始化()-模型的初始化函数,开始工作前调用一次; -
步骤()-执行计算模型的一个步骤的主要计算函数。 它通常被称为定期,根据指定的积分步骤。; -
期限()-模型的关闭功能。档案
主要。c它不包含模型操作的算法,而只是演示如何在具有C代码支持的应用程序中正确启动和管理其执行。主要。c它应该用作将模型集成到用户项目中的模板。
-
支持的数据类型
生成的代码中的数据类型与模型中的数据类型相对应 AnyMath .
如果用户尚未在模型中指定数据类型,则使用与该类型对应的双精度浮点数据类型。 双倍 在C.对于产生布尔结果的逻辑运算或计算(真(1) 或 错误(0)),数据类型使用 布尔值,对应于Si中的八位无符号数据类型。
|
要在模型中显示数据类型,请在 设置窗口 |
多频型号
模型 AnyMath 它们可以是多频率的,即它们包含几个不同的采样频率。 应用区块 速率转换,以及设置参数 采样时间 块和子系统,用户可以控制哪些计算步骤块或块组一起工作。
代码生成器 AnyMath 支持多频模型的代码生成。 为此,块按频率分组,并且用户可以控制这些不同频率在生成的代码中如何表示。
定制化 多速率代码生成 允许您控制多频率模型的生成代码的操作模式。 单任务 代码允许您生成单个函数 步骤 为模型。 多任务 代码允许您生成多个函数 步骤 对于模型,其中每一个对应于模型中的特定采样率。

*单任务 代码*包含条件(在表单中 如果)生成的函数内部 步骤,它包装模型中较慢频率的调用。 功能 步骤 它包含以模型的基本频率(最快频率)操作的块。 从自定义绑定中,提供函数调用就足够了 步骤 与此同时,较慢频率的呼叫的调度和频率之间的信息交换在生成的代码本身中自动进行。
*多任务 代码*包含几个函数 步骤_n 在生成的代码中,每个代码都对应于其在模型中的频率。 功能 步骤_0 对应于模型中最快的频率(基频),函数 步骤_1 第二较慢的频率,等等。 需要提供来自自定义绑定的函数调用 步骤_n 用必要的计算步骤。 在生成的代码本身中自动提供不同频率之间的数据交互。
代码验证
验证是指用块生成验证模型 *C函数*其仿真结果必须与具有相同输入数据的原始模型的仿真结果相匹配。
座 C函数*可以自动创建以验证生成的代码。 为此,请选中此框 *生成 C 函数模块 在设置窗口
:

下次生成代码时(通过界面、上下文菜单或命令 generate_code)目录下 ouput_迪尔 该文件将出现 modelname_verification.jl (如果目录不存在,它将自动创建)。 此文件将包含一个可以在脚本编辑器中执行的脚本(通过双击)
或命令行
:
include("path/to/verification.jl")
该脚本将创建一个模型 AnyMath 带名字 modelname_verification.工程师 还有一个街区 C函数,它使用生成的代码:

在 AnyMath 还提供Verilog语言的代码生成,有关更多信息,请参阅文章 Verilog(HDL)代码生成.
基于自定义模板的代码生成
AnyMath 支持基于自定义模板的代码生成(有关详细信息,请参阅文章 根据自定义模板生成代码).
管理信号名称
代码生成器使用模型中用户指定的信号的名称,使生成的代码更清晰,更容易与模型匹配。 例如:

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

