Code Generator Features
Internal functions in the generated code
The Engee code generator supports virtual and atomic subsystems for code generation. Virtual subsystems serve only for the visual hierarchy in the model, while atomic subsystems represent a single execution unit (or function in the generated code). The setting in the properties of the subsystem Treat as atomic unit
allows you to make the subsystem virtual or atomic.
All calculations within virtual subsystems are embedded (inline) directly into the code of the enclosing subsystem or model. This can improve the performance of the generated code, but degrade readability and traceability to the model.
All calculations inside atomic subsystems are generated in a separate function with the subsystem name. This function is then called automatically in the code of the underlying subsystem or model. This can improve the readability and traceability of the generated code to the model, but degrade performance.
For example, transform the RollMode
from the autopilot_roll.engee
model (see Code generation example) to the atomic subsystem:
Save the model and generate the code again. The generated code now has a function named RollMode' (corresponding to the subsystem name in the model). This function is called inside the `autopilot_roll_step
function, which represents the code of the enclosing model. The 'RollMode` function is declared as `static' and is thus an internal function of this model.
The code generator ignores disabled blocks, and the associated code is not created. |
Parameters in the generated code
Parameters in the model blocks
In the model blocks, the parameters can be set:
-
In the form of numbers (for example,
0.2
); -
In the form of expressions (for example,
0.2 + 0.7
); -
In the form of variable names from the Engee workspace (for example,
Kp
).
In the generated code, the parameters are embedded (inline) with the values specified in the model.:
-
Simple numerical values are added to the code "as is", and no additional actions are required.;
-
Expressions can be simplified, and only the final calculated value will appear in the code.;
Configurable parameters
Some block parameters can be made configurable (tunable) so that they can be changed after code generation. Such parameters are stored in the modelname_P
structure, which looks like this:
-
If the parameter is set using the variable name (for example,
Kp
), then its name is stored in the structure.:struct P_modelname_T_ { double Kp; };
-
If the parameter is set as an expression (for example,
Kp + 1
), then the parameter name is used (for example,Amplitude
):struct P_modelname_T_ { double Amplitude; };
In all cases, the parameters in the modelname_P
structure are filled with calculated values available from the model, for example:
P_modelname_T modelname_P = {
0.5 // Parameter value
};
Using the option Default parameter behaviour in settings window
|
Interfaces of the generated code and integration into the external development environment
Interfaces of the generated code
The external interfaces of the generated code can be seen in the generated file `modelname.h'. External interfaces include functions and structures for working with generated code.:
-
'modelname_init' — is the initialization function of the model — must be called once;
-
'modelname_step' is the entry point to the model and contains the model’s algorithm. It should be called periodically in accordance with the step of calculating the model;
-
modelname_U
— the structure contains the external input ports of the model; -
modelname_Y
— the structure contains the external output ports of the model; -
modelname_S
— the structure contains the internal states of the model; -
modelname_P
— the structure contains configurable model parameters.
Integration into an external development environment
To use the functions and structures of the generated modelname' file.h
in the external code (written manually), you need to do the following:
-
Attach the generated header file:
#include "modelname.h"
-
Organize a single call to the generated
init
function in yourmain
:modelname_init();
-
Organize a periodic call to the generated
step
function in yourmain
with the required step:modelname_step();
-
Organize the transfer of input and output data to and from the
step
function:/* Setting the values of the inputs */ modelname_U.input1 = 42; /* Calling the step function */ modelname_step(); /* You can use modelname_Y.output1 */
Generated files
After building the model in Engee and generating its code (using the engee' command.generate_code()
or buttons Generate code ) automatically generated files are created that contain the implementation of the model in the C language. Below is a description of these files and their purpose.
-
modelname.h
is the header file that describes the external interfaces of the model. It includes the functions and structures necessary to work with the model from external code (for more information, see above). The process of connecting these functions and structures to an external application is also described in the section above. -
`modelname.c' is a file with the implementation of the model logic. It contains definitions of all variables and the implementation of key functions of the model.:
-
'init()` is an initialization function that sets the initial values of variables and model states`;
-
'step()` is the main computational function. Performs the calculation of one simulation step and updates the output values;
-
term()
is the shutdown function of the model.
-
-
`model_data.c' is a file with initial initialization of the model parameters. It sets the values of all the configurable parameters that are used when executing the model. For example:
-
Signal amplitude and frequency;
-
Phase, offset;
-
The number of samples and other parameters.
These global parameters are configurable and can be changed while the executable code is running. This allows you to flexibly control the behavior of the model without having to reassemble the logic or edit the main functions.
-
-
'main.c' is a file with an example of using the model. This is the main executable file that shows how to initialize and invoke a model from a C program. Contains:
-
'init()` is the initialization function of the model, called once before starting work.;
-
'step()` is the main computational function that performs one step of calculating the model. It is usually called periodically, according to the specified integration step.;
-
term()
is the shutdown function of the model.The 'main.c` file does not contain the algorithm of the model, but only demonstrates how to correctly launch and manage its execution in an application with C code support.
main.c
should be used as a template for integrating the model into user projects.
-
Supported data types
The data types in the generated code correspond to the data types in the Engee model.
If the user has not specified the data type in the model, then the double-precision floating-point data type corresponding to the double
type in C is used. For logical operations or calculations that generate Boolean results (true (1)
or false (0)
), the boolean data type is used, corresponding to the eight-bit unsigned data type in C.
To display data types in the model, in settings window ![]() |
Vectorization
The code generator supports vector data types in models, including vectors and matrices. For vector operations, standard for
loops are generated in the code without calling specific BLAS or LAPACK functions.
Complex numbers
The code generator supports complex data types in models. For complex types, types from the standard header file <complex.h>
are used.
Multi-frequency models
Engee models can be multi-frequency, that is, they contain several different sampling rates. Applying blocks Rate Transition By setting the Sample Time
parameter of blocks and subsystems, the user can control which calculation step blocks or groups of blocks work with.
The Engee code generator supports code generation for multi-frequency models. To do this, the blocks are grouped by frequency, and the user can control how these different frequencies are represented in the generated code.
Customization Multirate code generation allows you to control the mode of operation of the generated code for a multi-frequency model. The "single-task" code allows you to generate a single "step" function for the model. The "multitasking" code allows you to generate several "step" functions for the model, each of which corresponds to a specific sampling rate in the model.
Single-task code contains conditions (in the form of if
) inside the generated 'step` function that wrap calls to slower frequencies in the model. The step
function contains blocks operating at the base frequency of the model (the fastest frequency). It is sufficient to provide a call to the step
function from the user harness, while scheduling calls to slower frequencies and exchanging information between frequencies is carried out automatically in the generated code itself.
Multitasking code contains several step_N
functions in the generated code, each of which corresponds to its frequency in the model. The function step_0' corresponds to the fastest frequency in the model (the base frequency), the function `step_1
corresponds to the second slower frequency, and so on. From the custom binding, it is required to provide a call to the step_N
functions with the necessary calculation steps. Data interactions between different frequencies are provided automatically in the generated code itself.
Comments in the generated code
By default, the generated code contains comments that allow you to trace the code to the blocks in the model.
Customization Include comments in the panel Code generation they allow you to manage comments in the generated code and, if necessary, disable them completely.
Code verification
Verification refers to the generation of a verification model with a block C Function, whose simulation results must match the simulation results of the original model with the same input data.
Block C Function it can be created automatically to verify the generated code. To do this, check the box Generate C Function block in the settings window :
The next time the code is generated (via the interface, context menu, or command generate_code) the file modelname_verification.jl
will appear in the directory ouput_dir
(if the directory does not exist, it will be created automatically). This file will contain a script that can be executed in the script editor (by double-clicking) or the command line
:
include("path/to/verification.jl")
The script will create an Engee model with the name modelname_verification.engee
and a block C Function, which uses the generated code:
Code generation in the Verilog language is also available in Engee. For more information, see the article Verilog (HDL) code generation.
Code generation based on custom templates
Engee supports code generation based on custom templates (for more information, see the article Code generation based on custom templates).
Managing signal names
The code generator uses the names of the signals specified by the user in the model to make the generated code clearer and easier to match with the model. For example:
If the signal (block output) has a name, then the generated code will use the same variable name for this signal. This is possible only if the signal has not been optimized and does not contain characters that are not supported in the C code.