代码生成器功能
生成代码中的内部功能
恩基*代码生成器支持*虚拟*和*原子*子系统用于代码生成。虚拟子系统仅用于模型中的可视化层次结构,而原子子系统则代表单个执行单元(或生成代码中的函数)。子系统属性中的 "作为原子单元处理 "设置允许您将子系统设置为虚拟或原子。
虚拟*子系统中的所有计算都会直接嵌入(内联)到包含子系统或模型的代码中。这可能会提高生成代码的性能,但会降低模型的可读性和可操作性。
所有*原子*子系统内的计算都会生成一个名为子系统的独立函数。然后,在包含子系统或模型的代码中自动调用该函数。这可能会提高生成代码的可读性和对模型的可追溯性,但会降低性能。
例如,将 autopilot_roll.engee
模型(见代码生成示例)中的 RollMode
变成一个原子子系统:
保存模型并再次生成代码。现在生成的代码包含一个名为 "RollMode"(与模型中子系统的名称相对应)的函数。该函数在 autopilot_roll_step
函数中调用,该函数代表体积模型的代码。RollMode "函数被声明为 "静态 "函数,因此是该模型的内部函数。
代码生成器会忽略已禁用的代码块,因此不会生成相关代码。 |
生成代码中的参数
模型块中的参数
可以在模型块中设置参数:
-
作为数字(例如
0.2
); -
表达式(例如:
0.2 + 0.7
); -
作为 Engee 工作区的变量名(如
Kp
)。
在生成的代码中,参数与模型中指定的值一起嵌入(内联):
-
简单的数值会 "按原样 "添加到代码中,无需额外操作;
-
表达式可以简化,只有最终计算值会出现在代码中;
可定制参数
某些程序块参数可以自定义(可调),以便在代码生成后更改。这些参数存储在 modelname_P
结构中,如下所示:
-
如果参数是通过变量名(如
Kp
)指定的,则其名称存储在该结构中:struct P_modelname_T_ { double Kp; };
-
如果参数以表达式形式指定(例如
Kp + 1
),则使用参数的名称(例如Amplitude
):struct P_modelname_T_ { double Amplitude; };
在任何情况下,"modelname_P "结构中的参数都将使用模型中的计算值,例如
P_modelname_T modelname_P = {
0.5 // Значение параметра
};
使用 参数的默认行为 在设置窗口
|
生成代码接口并集成到外部开发环境中
生成代码界面
生成代码的外部接口可以在生成的 modelname.h
文件中看到。外部接口包括与生成代码一起工作的函数和结构:
-
modelname_init
- 是模型初始化函数 - 必须调用一次; -
modelname_step
- 是模型入口点,包含模型算法 - 应根据模型计算步骤定期调用; -
modelname_U
- 包含模型外部输入端口的结构; -
modelname_Y
- 包含模型外部输出端口的结构; -
modelname_S
- 结构包含模型的内部状态; -
modelname_P
- 结构包含模型的自定义参数。
集成到外部开发环境
要在外部代码(手动编写)中使用生成的 modelname.h
文件中的函数和结构,需要执行以下操作:
-
连接生成的头文件:
#include "modelname.h"
-
在您的
main
中组织一次对生成的init
函数的调用:modelname_init();
-
在您的
main
中定期调用生成的step
函数:modelname_step();
-
组织输入和输出数据向`step`函数的传输:
/* Устанавливаем значения входов */ modelname_U.input1 = 42; /* Вызываем функцию step */ modelname_step(); /* Можно использовать modelname_Y.output1 */
生成文件
在 Engee 中建立模型并生成代码(使用 engee.generate_code()
命令或按钮 生成代码 ),生成的文件将自动包含模型的 C 语言实现。下文将介绍这些文件及其用途。
-
modelname.h "是描述模型外部接口的头文件。它包括从外部代码中使用模型所需的函数和结构(详见上)。将这些函数和结构连接到外部应用程序的过程在上 中也有描述。
-
modelname.c
- 包含模型逻辑实现的文件。它包含所有变量的定义和模型关键功能的实现:-
init()
- 设置变量初始值和模型状态的初始化函数; -
step()` - 主要计算函数。执行一个模拟步骤的计算并更新输出值;
-
term()
- 模型终止函数。
-
-
model_data.c
- 模型参数初始化文件。它规定了执行模型时使用的所有可配置参数的值。例如-
信号幅度和频率;
-
相位、偏移;
-
采样数和其他参数。
这些全局参数可自定义,并可在可执行代码运行时更改。这样,您就可以灵活控制模型的行为,而无需重建逻辑或编辑基本功能。
-
-
main.c`是一个包含模型使用示例的文件。这是主可执行文件,展示了如何通过 C 程序初始化和调用模型。包含
-
init()
- 模型初始化函数,启动前调用一次; -
step()
- 主计算函数,执行模型计算的一个步骤。通常根据指定的积分步骤定期调用; -
term()
- 模型完成函数。main.c "文件并不包含模型的算法,而只是演示如何在支持 C 代码的应用程序中正确运行和控制其执行。main.c`文件应作为将模型集成到用户项目中的模板。
-
支持的数据类型
生成代码中的数据类型与 Engee 模型中的数据类型相对应。
如果用户未在模型中指定数据类型,则使用与 C 语言中的 double
类型相对应的双精度浮点数据类型。对于产生布尔结果("真(1)"或 "假(0)")的逻辑运算或计算,则使用与 C 语言中八位无符号数据类型相对应的 "布尔 "数据类型。
要在模型中显示数据类型,请在设置窗口![]() |
多频率模型
*Engee*模型可以是多频率的,即包含多个不同的采样频率。通过应用块Rate Transition ,以及设置块和子系统的 "采样时间 "参数,用户可以控制块或块组运行的步进率。
Engee*代码生成器支持多频率模型的代码生成。为此,程序块按频率分组,用户可控制如何在生成的代码中表示这些不同的频率。
自定义 多频代码生成 允许您控制多频率模型生成代码的运行模式。单任务 "代码允许为模型生成单个 "步骤 "函数。多任务 "代码可为模型生成多个 "步骤 "函数,每个函数对应模型中的特定采样频率。
*单任务代码*在生成的 "step "函数中包含条件(以 "if "的形式),可绕过模型中对较慢频率的调用。step "函数包含以模型基本频率(最快频率)运行的块。用户只需提供对`step`函数的调用流水线,而调度对较慢频率的调用和频率间的信息交换则由生成的代码本身自动完成。
多任务代码*在生成的代码中包含多个`step_N`函数,每个函数对应模型中不同的频率。step_0 "函数对应模型中最快的频率(基准频率),"step_1 "函数对应第二个较慢的频率,以此类推。在用户流水线操作中,需要调用具有所需计算步骤的 step_N
函数。不同频率之间的数据交互在生成的代码中自动提供。
代码验证
验证是指生成一个带有块C Function 的验证模型,其仿真结果应与原始模型在输入数据相同的情况下的仿真结果一致。
可以自动创建C Function 块来验证生成的代码。为此,请勾选 生成 C 功能块 复选框:
下一次生成代码时(通过界面、上下文菜单或命令generate_code),modelname_verification.jl
文件将出现在 ouput_dir
目录中(如果该目录不存在,则将自动创建)。该文件将包含一个脚本,可在脚本编辑器(双击) 或命令行
中执行:
include("path/to/verification.jl")
该脚本将创建一个名为`modelname_verification.engee`的 Engee 模型和一个使用生成代码的块C Function :
Verilog 代码生成在 Engee 中也可用,详情请参见Verilog (HDL) 代码生成 。
基于自定义模板的代码生成
*Engee*支持基于自定义模板的代码生成(详见文章根据自定义模板生成代码 )。
信号名称管理
代码生成器使用用户在模型中定义的信号名称,使生成的代码更易懂,更容易与模型匹配。例如
如果信号(块输出)有一个名称,生成的代码将为该信号使用相同的变量名。这只有在信号未被优化且不包含 C 代码不支持的字符的情况下才有可能。