Engee 文档

C 功能

在模型中使用C代码。

类型: CFunction

图书馆中的路径:

/Basic/User-Defined Functions/C Function

资料描述

C 功能 允许在*Engee*模型中使用c代码和具有C API的共享库。

连接使用内部静态变量的动态库时,应确保它提供了用于初始化/去初始化这些变量的API。 必须在选项卡中调用相应的函数。 起始码终端码,终端码 源代码编辑器。 否则,静态变量将在模拟之间保留其最新值,这可能导致在再次运行模型时产生错误的结果。

使用

要将C源代码集成到*Engee*模型中,您必须:

  • 向模型添加块 C 功能 从*基本部分/自定义函数*块库;

  • 点击*编辑源代码*按钮,之后将打开源代码编辑器。

c function settings

源代码编辑器

源代码编辑器的工作区由四个选项卡组成:

  • 输出码 -包含在模型计算的每个步骤中执行的代码;

  • 起始码 -包含在模型初始化期间执行一次的代码;

  • 终端码,终端码 -包含在模型停止时运行一次的代码;

  • 共享代码 -包含允许在块的实例之间交换全局(共享)变量和函数的代码 C 功能 .

C语言的语法在每个部分中突出显示。

在该部分 输出码 有一个与模拟器和代码生成器相关的特殊注释块。

注释允许您将源代码中的变量与块的信号(输入和输出)相关联。 C 功能 ,以及指定构建代码所需的附加信息并在模型中使用它。

c function code editor

功能界面提示

以正确访问块的输入、输出、参数和操作变量。 C 功能 重要的是要知道这些函数的签名(接口)。 以前,您必须自己弄清楚它的组成,这使得编写代码变得更加困难,并可能导致错误。

现在在块源代码的所有选项卡上 C 功能 ,除了标签 共享代码 信息*区域显示在编辑器的左下角,其中自动形成并显示函数的界面(原型),对应于块的当前设置(输入,输出,参数和在选项卡上设置的工作变量*BasicParameters*和*Work Variables):

c function interfaces

这使您不仅可以看到函数的主体,还可以看到它在编写代码时的确切接口,例如:

void CFunction_step(double t, uint32_t in1, double param1, uint32_t *out1);

该提示在块配置更改时动态更新,有助于避免在访问源代码中的输入,输出,参数和工作变量时出错。

从块生成C代码的特点 C 功能

C 功能 支持C代码生成。 在生成代码时,块 C 功能 它变成了封装源代码所有四个部分内容的函数。

目前,C代码生成器没有为构建系统提供额外的信息,这些信息将基于块指令。 C 功能 . 指令在部分中指定 建造选项 块设置:

build options c function

块的重用

标签 共享代码 块的源代码 C 功能 允许您设置可用于在块实例之间交换数据和函数的通用代码。 C 功能 在参数中具有相同的名称 功能名称 .

为了使用该功能 共享代码,你需要创建一个块 C 功能 ,在参数中为其指定一个名称 功能名称 ,然后将此块保存到 用户库 user library 1. 之后,该块可以在几个地方添加到模型中,在那里它将保留对通用数据和函数的访问。 因此,仿真只创建一个共享库和一组函数,供块的所有实例使用。 C 功能 .

在为参数中具有相同名称的块生成代码时 功能名称 只创建常规函数 初始化, 步骤任期,以及标签中的代码 共享代码 它被添加到项目一次。 这简化了代码管理,并提供跨块的所有实例访问共享数据。 C 功能 .

操作变量

标签 工作变量 街区 C 功能 允许您设置静态工作变量,这些变量保持特定于块的每个实例,即使几个块具有相同的参数值。 功能名称 . 这些工作变量类似于参数,但在执行期间从块的源代码更改其值的能力不同。 这种方法允许您存储和修改仅在块的特定实例中使用的数据。

对于选项卡上的每个工作变量 工作变量 指定 名称 和 大小(字节. 在源代码中,这些变量可以通过指向结构的指针访问。 工作,这是存在于所有三个块函数的接口: 步骤, 初始化,而 任期. 例子::

work variable 1

在这里,对齐在源代码中使用,其中宏 is_对齐 检查变量是否正确对齐。 变量 工作-可变1工作_可变3 在选项卡上预定义 工作变量 并可通过结构 工作.

使用数组

当数据从Julia转移到C代码时,重要的是要考虑索引和数组结构的差异。 这对于在传输过程中可以转置(重新排列索引的顺序)的多维数组是相关的。 以下是处理数组时要考虑的要点。:

了解有关使用数组的更多信息
  • 一维数组-将一维数组从Julia传输到C时,数组保留其结构。 C中的索引从 0 因此,在访问数组元素时,必须考虑到这种偏移。 例如,如果block参数 C 功能 一维数组写成a= [1, 2, 3],那么在C语言:

    # include <stdio.h>
    
    int main() {
        int a[3] = {1, 2, 3};
        printf("%d", a[2]); // Вывeдet 3
        return 0;
    }

    在此示例中,要获取具有索引的数组元素的值 2 正在使用地址 a[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;
    }

    阵列 [1 2 3; 4 5 6] 在Julia中,它变成了一个数组 a[2][3] 在C中,其中第一个索引指向一行,第二个指向列。 在此示例中,在C中,要获取具有值的元素 2 使用索引 a[1][0]. 因此,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

V 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 功能 输入/输出端口和块参数都支持总线操作。 设置和使用轮胎的特征如下所述。:

港口的巴士

要在输入或输出端口上设置总线:

  1. 在相应端口(*Ports*选项卡)的类型参数中,选择类型 N.公共标志.

  2. 之后,参数*输入总线类型*(或*输出总线类型*)将自动采取形式:

    BusSignal((), Tuple{}, ())

    在这里你应该指定:

    • 总线的类型是显式的,例如:

      BusSignal((:s1, :s2), (Float64, Int64), ((), ()))

      哪里 :s1, :s2 -信号名称; (Float64,Int64) -他们的基本类型; ), ( -它们的尺寸。

    • 或包含在*Engee*工作区中定义的总线描述的变量的名称(在窗口中 variables)或由C/Julia代码生成。

  • 对于块 C 功能 必须显式指定端口上的总线类型。

  • 总线和字段名称不应包含空格,因为它们在C代码中使用(标识符中不允许使用空格)。

  • 类型= `N.公共标志 端口的*Size*设置被忽略-维度在*输入/输出总线类型*被设置。

如果需要,您可以使用第四个参数指定总线名称。: N.公共标志:s1,:s2),(Float64,Int64), ((),(,:MyBus).

轮胎在参数

如果总线用作参数:

  • 在价值观字段中,将总线设置为命名元组,例如:

    (s1 = 4.4, s2 = (b1 = 5, b = 6))
  • 如果参数被调用,例如, p,那么在C代码中,元素可以作为结构的字段访问:

    output1 = input1 * (p.s1 + p.s2.b1);

主页

输入端口数 — 输入端口数

+ 1(默认)

Details

定义块的输入端口数。 参数值 输入端口数 它将对应于输入端口的数量。

输出端口数 — 输出端口数

+ 1(默认)

Details

定义块的输出端口数。 参数值 输出端口数 它将对应于输出端口的数量。

功能名称 — 几个块的通用代码的ID

+ 否(默认情况下)

Details

指定字符串值以组合块代码。 C 功能 . 参数中具有相同名称的块 功能名称 他们将使用通用代码并通过源代码选项卡交换数据。 共享代码 街区 C 功能 .

如果将字段留空,则选择的块 C 功能 它将保持脱机状态(默认情况下)。

在参数中 功能名称 可以指定为绝对路径(从 /用户),以及相对—从当前工作目录(您可以使用命令找到它 残疾人士,其输出到当前文件夹的完整路径)。

您也可以只指定文件名:在这种情况下,*Engee*首先在当前目录中搜索文件,然后在 Engee路径编辑器.

取样时间 — 计算步骤之间的间隔

+ -1(默认)

Details

将计算步骤之间的间隔指定为非负数。 要继承计算步骤,请将此参数设置为 −1.

港口

入口

输入端口 1 — 1号输入端口

+ 标量,标量 | 向量资料 | 矩阵

Details

要操作输入端口,请填写/配置以下字段:

  • *Label*是输入端口的名称(文本标签)。 默认情况下,不填写名称单元格(未指定名称)。

  • *变量名*是源代码C代码中输入端口变量的名称。 默认情况下 输入1.

    /* 在模型计算的每一步调用此代码。 */
    output1 = input1 * param1;

    哪里 输入1 -输入端口变量的名称; 输出1 -输出端口变量的名称; param1 -参数变量的名称。

  • 类型是c源代码中输入端口变量的数据类型。 变量的数据类型必须与信号的数据类型匹配。 支持基本的C数据类型:

    double(默认情况下) | 浮子,浮子 | int8_t | uint8_t | int16_t | uint16_t | int32_t | uint32_t | int64_t uint64_t | int128_t | uint128_t | 布尔 | N.公共标志

  • 尺寸-输入信号的尺寸 1(默认).

    *Size*字段使用Julia表示法,其中size写成元组,例如, (2, 3, 4). 但是,在C代码中使用此端口时,有必要考虑到索引顺序的更改。 这意味着,如果端口设置与大小 (2, 3, 4),然后在C代码中,变量将具有维度 [4][3][2]. 这个规则类似于参数的工作方式:与Julia相比,c中的索引顺序被转置。

出口;出口

输出端口 1 — 1号输出端口

+ 标量,标量 | 向量资料 | 矩阵

Details

要操作输出端口,请填写/配置以下字段:

  • *Label*是输出端口的名称(文本标签)。 默认情况下,不填写名称单元格(未设置名称)。

  • *变量名*是源代码C代码中输出端口变量的名称。 默认情况下 输出1.

    /* 在模型计算的每一步调用此代码。 */
    output1 = input1 * param1;

    哪里 输出1 -输出端口变量的名称; 输入1 -输入端口变量的名称; param1 -参数变量的名称。

  • 类型是c源代码中输出端口变量的数据类型。 变量的数据类型必须与信号的数据类型匹配。 支持基本的C数据类型:

    double(默认情况下) | 浮子,浮子 | int8_t | uint8_t | int16_t | uint16_t | int32_t | uint32_t | int64_t uint64_t | int128_t | uint128_t | 布尔 | N.公共标志

  • 尺寸-输出信号的尺寸 1(默认).

    *Size*字段使用Julia表示法,其中size写成元组,例如, (2, 3, 4). 但是,在C代码中使用此端口时,有必要考虑到索引顺序的更改。 这意味着,如果端口设置与大小 (2, 3, 4),然后在C代码中,变量将具有维度 [4][3][2]. 这个规则类似于参数的工作方式:与Julia相比,c中的索引顺序被转置。

参数

参数数 — 指定参数的数量

+ 1(默认)

Details

块中使用的参数的数量。

参数 1 — 将参数定义为变量

+ 1(默认)

Details

将参数定义为要在源代码中使用的变量:

  • 名称 -默认参数名称 param1. 它是可以改变的。 新参数的名称被调用 param2 然后上升。

  • -参数的默认值 0. 它是可以改变的。 默认情况下,新参数的值也为零。

要使用参数,请转到块代码编辑器。 C 功能 (编辑源代码)在选项卡中 输出码 并输入所需参数的名称。 默认情况下:

/* 在模型计算的每一步调用此代码。 */
output1 = input1 * param1;

哪里 输入1 -输入信号变量; 输出1 -可变输出信号。

工作变量

工作变量数 — 工作变量数

+ 0(默认)

Details

块中用于存储特定于每个实例的数据的工作变量的数量。 工作变量可通过结构 工作 并且可以在函数中使用 初始化, 步骤任期 用于写入和读取数据。

每个变量都设置有参数 名称大小(字节 ,它允许您存储各种类型的数据。 如果一个变量被分配了更大的大小,那么它可以用作数组。

工作变量 1 — 定义工作变量

+ 1(默认)

Details

定义要在源代码中使用的工作变量:

  • 名称 -默认参数名称 工作-可变1. 它是可以改变的。 新工作变量的名称被调用 工作-可变2 然后上升。

  • 大小(字节 -为变量分配的内存量,以字节为单位。 此参数允许您指定变量的大小,无论是标量还是数组。

要使变量工作,您需要转到块代码编辑器。 C 功能 (编辑源代码)在选项卡 输出码 并输入变量名。

构建选项

来源文件 — 连接源代码文件

+ 否(默认情况下)

Details

它用于连接其他源代码文件。 必须包括路径和文件名以及扩展名。 例如:

/user/project/src/example.c

包含目录 -确定头文件目录的路径

+ 否(默认情况下)

Details

它用于确定包含头文件的目录的路径。 例如:

/user/project/include

图书馆目录 — 确定库目录的路径

+ 否(默认情况下)

Details

它用于确定包含共享库的目录的路径。 例如:

/user/project/third_party

页眉 — 头文件的连接

+ stdint。h数学。h(默认)

Details

它用于连接头文件。 必须包括头文件的名称以及扩展名。 例如:

example.h

定义 — 附加指令的定义#define

+ 否(默认情况下)

Details

用于定义额外的#define指令。 例如:

defines LOWER=0 UPPER=300 STEP=20

图书馆 — 连接图书馆

+ 否(默认情况下)

Details

它用于连接库。 必须包括库名称和扩展名。 例如:

libexample.so
实际的数据类型以及对可能的数据类型的支持取决于块内的用户代码。

附加选项

C 代码生成: 是