C 功能
在模型中使用 C 代码。
类型: CFunction
图书馆中的路径:
|
说明
C 功能 块允许 Engee 模型使用 C 代码和具有 C API 的共享库。
在连接使用内部静态变量的动态链接库时,应确保它提供了用于初始化/取消初始化这些变量的 API。应在源代码编辑器的 "StartCode "和 "TerminateCode "选项卡中调用相应的函数。否则,静态变量将在两次模拟之间保留其最后的值,这可能会导致模型重新运行时出现不正确的结果。 |
源代码编辑器
源代码编辑器工作区由四个选项卡组成:
-
输出代码"(OutputCode)- 包含模型计算过程中每一步执行的代码;
-
StartCode"(开始代码)- 包含模型初始化时执行一次的代码;
-
终止代码"(TerminateCode)- 包含模型停止时执行一次的代码;
-
共享代码
SharedCode
- 包含允许在块 C 功能 的实例之间交换全局(共享)变量和函数的代码。
每个部分都有 C 语法高亮显示。
输出代码 "部分包含对模拟器和代码生成器非常重要的特殊注释块。
通过注释,您可以将源代码中的变量与块 C 功能 的信号(输入和输出)相关联,还可以指定构建代码和在模型中使用代码所需的其他信息。
从程序块生成 C 代码的特点C 功能
C 功能 程序块支持 C 代码生成。生成代码时, C 功能 代码块会被转换成函数,这些函数会封装源代码的所有四个部分的内容。
目前,C 代码生成器不会根据 C 功能 代码块的指令向构建系统提供额外信息。这些指令在代码块设置的 建造选项 部分中指定:
区块重用
通过 C 功能 程序块源代码中的 "共享代码 "选项卡,可以在 功能名称 参数中指定可用于 C 功能 程序块实例之间共享数据和函数的通用代码。
为了使用 "共享代码 "功能,您需要创建一个程序块 C 功能 ,在参数 功能名称 中为其指定名称,然后将该程序块保存到用户库 。然后,就可以在模型的多个位置添加该块,使其保留对常用数据和功能的访问。因此,建模只需创建一个通用共享库和一组函数,供块 C 功能 的所有实例使用。
为 功能名称 参数中具有相同名称的程序块生成代码时,只创建共享函数 init
、step
和 term
,并将 SharedCode
选项卡中的代码一次性添加到项目中。这简化了代码管理,并提供了在块的所有实例中访问通用数据的途径 C 功能 。
工作变量
通过 工作变量 标签,您可以在 C 功能 块中设置静态工作变量,即使多个块具有相同的 功能名称 值,这些变量仍是每个块实例所特有的。这些工作变量与参数类似,但不同之处在于,它们可以在运行时更改块源代码中的值。这种方法允许你存储和修改只在特定程序块实例中使用的数据。
对于每个工作变量, 工作变量 标签指定了名称 和大小(字节 。在源代码中,可以通过指向 Work
结构的指针访问这些变量,该结构存在于所有三个代码块函数的接口中:step
、init
和 term
。示例
这里的对齐是在源代码中使用的,其中 is_aligned
宏检查变量是否正确对齐。变量 work_variable1
和 work_variable3
在 工作变量 标签中预定义,可通过结构 Work
获取。
使用数组
当数据从 Julia 传递到 C 代码时,必须考虑索引和数组结构的差异。这与多维数组相关,因为在传输过程中,多维数组可能会被移调(改变索引顺序)。以下是处理数组时需要考虑的要点:
有关使用数组的更多信息_.
-
一维数组 - 将一维数组从 Julia 传递到 C 时,数组保留其结构。C 语言中的索引是从 "0 "开始的,因此在访问数组元素时需要考虑这一变化。例如,如果在块参数 C 功能 中将一维数组写成 a =
[1,2,3]
,那么在 C.D.C++ 中,数组的结构就会发生变化:#include <stdio.h> int main() { int a[3] = {1, 2, 3}; printf("%d", a[2]); // Выведет 3 return 0; }
在本例中,调用
a[2]
是为了获取索引为2
的数组元素的值,返回值为 `3'。 -
多维数组 - 从 Julia 传递到 C 代码时,多维数组会改变索引顺序。在 C 代码中,数组将被转置,这意味着在访问数组元素时,必须考虑索引顺序的变化。例如,Julia 中有一个数组:
a = [1 2 3; 4 5 6] #Julia интерпретирует это как матрицу 2x3 2x3 Matrix{Int64} 1 2 3 4 5 6 #доступ к элементу массива a [1,2] 2
然后用 C
#include <stdio.h> int main() { int a[3][2] = { {1, 4}, {2, 5}, {3, 6} }; printf("%d", a[1][0]); // Выведет 2 return 0; }
Julia 中的数组
[1 2 3; 4 5 6]
在 C 语言中变成了数组a[2][3]
,其中第一个索引指向一行,第二个索引指向一列。在这个 C 示例中,索引`a[1][0]`用于获取值为`2`的元素。因此,C 语言中的数组实际上存储的是 Julia 转置数组的元素,在访问元素时必须考虑到这一点。
在处理三维和更复杂的数组时,索引也会发生变化。例如,如果一个数组在 Julia 中的维数是"[2, 3, 4]",那么在 C 语言中将表示为"[4][3][2]"。在 C 代码中引用数组元素时必须考虑到这一点。
Julia 中的三维数组示例:
a = reshape(1:24, 2, 3, 4)
[:, :, 1] =
1 3 5
2 4 6
[:, :, 2] =
7 9 11
8 10 12
[:, :, 3] =
13 15 17
14 16 18
[:, :, 4] =
19 21 23
20 22 24
println(a[1, 2, 3]) # Выведет 13
IN S:
#include <stdio.h>
int main() {
int a[4][3][2] = {
{
{1, 4},
{2, 5},
{3, 6}
},
{
{7, 10},
{8, 11},
{9, 12}
},
{
{13, 16},
{14, 17},
{15, 18}
},
{
{19, 22},
{20, 23},
{21, 24}
}
};
printf("%d", a[2][1][0]); // Выведет 13
return 0;
}
将 Julia 索引转换为 C 索引的一般规则是改变顺序: (D1,D2,…,Dn)->[Dn][Dn-1]…[D1]`。 这意味着 C 语言中的索引以相反的顺序书写。 |
使用总线
C 功能 程序块在输入/输出端口和程序块参数中都支持总线操作。下文将介绍设置和使用总线的具体方法:
端口上的总线
在输入或输出端口上设置总线:
-
在相应端口的*类型*参数中(程序块设置中的*端口选项卡*),选择 "总线信号 "类型。
-
输入总线类型*(或输出总线类型*)参数将自动采用以下形式:
BusSignal{(), Tuple(), ()}
应该在这里说明:
-
明确说明总线类型,例如
BusSignal{(:s1, :s2), Tuple(Float64, Int54), ), (}
。:s1
,:s2
- 总线中信号的名称;Tuple(Float64, Int64)
- 它们的类型;), (
- 它们的尺寸; -
或在 Engee 工作区(variables 窗口)或 C 代码中定义的包含总线类型说明的变量名称。
-
必须*明确*指定所有总线类型—这是 C 功能 块的一个功能。 总线名称*不应包含空格*,因为它们用于 C 代码中,而 C 代码不允许在变量名中使用空格。 |
主页
输入端口数 -
输入端口数
1(默认值)
Details
指定程序块的输入端口数。 输入端口数 的值将与输入端口数相对应。
输出端口数 -
输出端口数
1(默认值)
Details
指定程序块的输出端口数。 输出端口数 的值将与输出端口数相对应。
功能名称 -
多个区块通用代码的标识符
否(默认)`
Details
指定一个字符串值,用于合并区块 C 功能 的代码。参数 功能名称 中具有相同名称的区块将使用共同代码,并通过区块 C 功能 的源代码选项卡 SharedCode
共享数据。
如果该字段留空,则所选 C 功能 区块将保持独立(默认)。
在 功能名称 参数中,您可以指定绝对路径(以 只指定文件名也是可以接受的:在这种情况下,Engee 首先在当前目录下查找文件,然后在Engee 路径编辑器 中描述的搜索路径中查找。 |
取样时间 -
计算步骤之间的间隔
-1 (默认)
Details
以非负数指定计算步骤之间的间隔。要继承计算步骤,请将此参数设置为 -1
。
端口
输入
输入端口 1 -
输入端口 #1
标量 | 向量 | 矩阵
Details
填写/设置以下字段以操作输入端口:
-
Label - 输入端口的名称(文本标签)。默认情况下,名称单元格未填写(未设置名称)。
-
变量名 - 输入端口变量在源 C 代码中的名称。默认为
input1
。/* Этот код вызывается на каждом шаге расчета модели */ output1 = input1 * param1;
其中,
input1
是输入端口变量的名称;output1
是输出端口变量的名称;param1
是参数变量的名称。 -
类型 - 输入端口变量在源 C 代码中的数据类型。变量的数据类型必须与信号的数据类型一致。支持基本的 C 语言数据类型:
double(默认)` |
float
|int8_t
|uint8_t
|int16_t
|uint16_t
|int32_t
|uint32_t
|int64_t
|uint64_t
|uint128_t
|__uint128_t
|bool
|BusSignal
. -
Size - 输入信号尺寸
1(默认)
。Size 字段使用 Julia 符号,将大小写成一个元组,例如 (2,3,4)
。但是,在 C 代码中使用该端口时,必须考虑索引顺序的变化。也就是说,如果端口的维数是(2,3,4)
,那么在 C 代码中,变量的维数将是[4][3][2]
。这一规则类似于参数的工作方式:与 Julia 相比,索引顺序在 C 代码中是对调的。
输出
输出端口 1 -
输出端口 #1
标量 | 向量 | 矩阵
Details
填写/设置以下字段以操作输出端口:
-
Label - 输出端口的名称(文本标签)。默认情况下,名称单元格未填写(未设置名称)。
-
变量名 - C 源代码中输出端口变量的名称。默认为
output1
。/* Этот код вызывается на каждом шаге расчета модели */ output1 = input1 * param1;
其中
output1
- 输出端口变量名;input1
- 输入端口变量名;param1
- 参数变量名。 -
类型 - C 源代码中输出端口变量的数据类型。变量的数据类型必须与信号的数据类型一致。支持基本的 C 语言数据类型:
double(默认)` |
float
|int8_t
|uint8_t
|int16_t
|uint16_t
|int32_t
|uint32_t
|int64_t
|uint64_t
|uint128_t
|__uint128_t
|bool
|BusSignal
. -
Size - 输出信号维数`1(默认)`。
Size 字段使用 Julia 符号,将大小写成一个元组,例如 (2,3,4)
。但是,在 C 代码中使用该端口时,必须考虑索引顺序的变化。也就是说,如果端口的维数是(2,3,4)
,那么在 C 代码中,变量的维数将是[4][3][2]
。这一规则类似于参数的工作方式:与 Julia 相比,索引顺序在 C 代码中是对调的。
参数
参数数 -
指定参数个数
1(默认值)
Details
区块中使用的参数个数。
参数 1 -
将参数定义为变量
1(默认值)
Details
将参数定义为变量,以便在源代码中使用:
-
名称 - 参数名称,默认为
param1
。可以更改。新的参数名称称为param2
,然后按升序排列。 -
值 - 参数值,默认为
0
。可以更改。新参数的值也默认为 0。
要操作参数,请进入程序块代码编辑器 C 功能 (编辑源代码)的 "OutputCode"(输出代码)选项卡,输入所需参数的名称。默认值:
/* Этот код вызывается на каждом шаге расчета модели */
output1 = input1 * param1;
其中 input1
为输入信号变量; output1
为输出信号变量。
工作变量
工作变量数 -
操作变量数
0(默认)
Details
程序块中用于存储每个实例特定数据的工作变量数量。工作变量可通过 Work
结构访问,并可在 init
、step
和 term
函数中用于写入和读取数据。
每个变量都由 名称 和 大小(字节 参数设置,可以存储不同类型的数据。如果给变量分配了较大的大小,它就可以作为数组使用。
工作变量 1 -
定义一个工作变量
1(默认)
Details
定义在源代码中使用的工作变量:
-
名称 - 参数名,默认为
work_variable1
。可以更改。新工作变量命名为work_variable2
,然后按升序排列。 -
大小(字节 - 为变量分配的内存量,以字节为单位。此参数允许指定变量的大小,无论是标量还是数组。
要运行变量,必须进入程序块 C 功能 的代码编辑器(编辑源代码),在 "OutputCode"(输出代码)选项卡中输入变量名。
构建选项
来源文件 -
连接源代码文件
否(默认)
Details
用于连接其他源代码文件。必须包含路径和文件名以及扩展名。例如
/user/project/src/example.c
包含目录 - 定义头文件目录路径
否(默认)
Details
用于定义头文件目录的路径。例如
/user/project/include
图书馆目录 -
图书目录路径定义
否(默认)
Details
用于定义包含共享库的目录路径。例如
/user/project/third_party
页眉 -
头文件连接
stdint.h math.h (default)
Details
用于连接头文件。必须包含头文件的名称和扩展名。例如
example.h
定义 -
定义附加指令 #define
无(默认)
Details
用于定义附加 #define 指令。例如
defines LOWER=0 UPPER=300 STEP=20
图书馆 -
图书馆连接
否(默认)
Details
用于连接库。必须包含库名称和扩展名。例如
libexample.so
实际数据类型以及对可能数据类型的支持取决于块内的用户代码。 |