Engee 文档
Notebook

使用C功能块将C代码集成到Engee模型中

此示例显示了使用C函数块将C代码集成到Engee模型中的各种方法。

在开始工作之前,我们将连接库以与MATLAB进行比较。:

In [ ]:
using MATLAB

使用宏 @__DIR__ 为了找出交互脚本所在的文件夹:

In [ ]:
demoroot = @__DIR__
Out[0]:
"/user/demo_renew/ccodeintegration"

使用C功能块的基础知识

让我们来看看使用C函数块的简单示例,说明将C代码集成到Engee模型中的基础知识。

1. 处理多维信号,传递参数并使用#define指令

进入模型 cCodeIntegration_basics.engee 添加了C函数块,它在其输入端接收正弦信号。 in:

basics_1.PNG

假设我们要增加正弦波的振幅 ingain 一次,并将其移动一个量 bias. 也就是说,输出信号应由公式确定 out = gain * in + bias.

让我们转到C函数块的设置,在选项卡中的位置 Ports 我们将熟悉块的输入和输出的定义。 这是源代码变量与C功能块的端口相关联的地方。:

  1. 标量变量 xdouble 与第一输入端口通信 in;
  2. 向量(3个元素)变量 ydouble 与所述第一输出端口连通 out.
image_2.png

阵列 gain 它也在C函数块(选项卡)的设置中定义 Parameters):

image.png

值得注意的是,将变量作为参数传递后,它变成:

  1. 全球至 gain 您可以从源代码编辑器的任何选项卡访问它。;
  2. 用限定符 const -尝试更改值时 gain 将收到错误。

位移量 bias 由标识符确定 #define bias,这是在选项卡中设置 Build options:

image.png

在此示例中,偏移量为 5.

我们去弗拉卡吧 Main 设置C函数块并单击"编辑源代码"按钮。 在打开的源代码编辑器中,在选项卡上 OutputCode 给出了在模型计算的每一步执行的代码。:

image.png

在循环中 for (对于三个输出信号中的每一个)在模型计算的每个步骤中,变量的值被确定 y.

让我们为系统建模:

In [ ]:
cCodeIntegration_basics = engee.load("$demoroot/models/cCodeIntegration_basics.engee", force = true)
simulationResults_basics = engee.run(cCodeIntegration_basics)
Out[0]:
SimulationResult(
    "out" => WorkspaceArray{Vector{Float64}}("cCodeIntegration_basics/out")

)

关闭模型:

In [ ]:
engee.close(cCodeIntegration_basics, force = true);

导入模拟结果:

In [ ]:
cCodeIntegration_basics_t = simulationResults_basics["out"].time;

cCodeIntegration_basics_y1 = [y[1] for y in simulationResults_basics["out"].value];
cCodeIntegration_basics_y2 = [y[2] for y in simulationResults_basics["out"].value];
cCodeIntegration_basics_y3 = [y[3] for y in simulationResults_basics["out"].value];

让我们建立一个图表:

In [ ]:
plot(cCodeIntegration_basics_t, cCodeIntegration_basics_y1)
plot!(cCodeIntegration_basics_t, cCodeIntegration_basics_y2)
plot!(cCodeIntegration_basics_t, cCodeIntegration_basics_y3)

title!("Выходной сигнал блока C Function <br> (Многомерные сигналы, параметры и #define)")
xlabel!("Время, [с]")
ylabel!("Амплитуда")
Out[0]:

2. 使用整数数据类型和静态变量

在模型中 cCodeIntegration_integers.engee 使用C函数块,我们实现一个简单的计数器,其输出将是一个正整数,指示当前迭代的数量。:

cCodeIntegration_integers_1.PNG

让我们分析一下选项卡的内容 PortsBuild OptionsC功能块设置:

image.png
image.png

C函数块中整数数据类型的名称根据[头文件]设置(https://ru.wikipedia.org/wiki/Stdint.h<stdint.h> C语言的标准库。 此文件附加在该行中 Headers 标签 Build options.

在标签中 Ports 一个无符号的64位变量绑定。 out (类型设置为 uint64_t 而不是 long,见上一段关于 <stdint.h>)的源代码与C函数块的第一个输出端口。

在标签中 Output code C函数块的源代码的编辑器显示了在模拟的每个步骤中执行的代码。:

image.png

静态变量 counter 在仿真的第一步,它被初始化为0,之后,在每次迭代中,它的值增加 1 并被赋值给一个变量 out.

让我们为系统建模:

In [ ]:
cCodeIntegration_integers = engee.load("$demoroot/models/cCodeIntegration_integers.engee", force = true)
simulationResults_integers = engee.run(cCodeIntegration_integers)
Out[0]:
SimulationResult(
    "counter" => WorkspaceArray{UInt64}("cCodeIntegration_integers/counter")

)

关闭模型:

In [ ]:
engee.close(cCodeIntegration_integers, force = true);

导入模拟结果:

In [ ]:
cCodeIntegration_integers_t = simulationResults_integers["counter"].time;
cCodeIntegration_integers_y = simulationResults_integers["counter"].value;

让我们建立一个图表:

In [ ]:
plot(cCodeIntegration_integers_t, cCodeIntegration_integers_y, legend = false)

title!("Выходной сигнал блока C Function <br> (Целочисленные типы и статические переменные)")
xlabel!("Время, [с]")
ylabel!("Номер итерации")
Out[0]:

有关源代码编辑器选项卡的用途、构建功能和可用数据类型的更多详细信息,请参阅[文档](https://engee.com/helpcenter/stable/base-lib-user-defined-function/c-function.htmlEngee

集成外部源代码

设置任务

让我们考虑一个更有趣的工程问题。

假设考虑到测量噪声,我们需要控制二阶的稳定对象,该对象受外部扰动的影响。 因此,我们将需要解决过滤控制对象的输出信号的问题,幸运的是,Engee有一个非常适合这个的工具!

在档案中 alphabetafilter.calphabetafilter.h 提出了[alpha-beta过滤器]的实现(https://en.wikipedia.org/wiki/Alpha_beta_filter )在C语言中。

文件内容 alphabetafilter.c:

``'C
#包括"alphabetafilter。h"
#include<math.h>

双倍dt=0.01;
静态双xk_1,vk_1;

Parameters determineAlphaBeta(double processNoiseVariance,双测量值)
{
双lambda,r;
参数p;

lambda=(processNoiseVariance*pow(dt,2))/measurementNoiseVariance;
r=(4+lambda-sqrt(8*lambda+pow(lambda,2)))/4;

p.alpha=1-pow(r,2);
p.beta=2*(2-p.alpha)-4*sqrt(1-p.alpha);

返回p;

}

双字母过滤器(双值,参数p)
{
双xk,vk,rk;

xk=xk_1+(vk_1*dt);
vk=vk_1;

rk=值-xk;

xk+=p.alpha*rk;
vk+=(p.beta*rk)/dt;

xk_1=xk;
vk_1=vk;

返回xk;

}

void initializeStaticVariables()
{
xk_1=0;
vk_1=0;
}



文件内容 alphabetafilter.h:

``'C
typedef结构{
双阿尔法;
双贝塔;
}参数;

参数determineAlphaBeta(双,双);
双字母过滤器(双,参数);
void initializeStaticVariables();



我们将此源代码集成到我们的Engee模型中。

模型分析

模型 cCodeIntegration_source.engee:

source_1.PNG

该模型由:

  1. 管理对象 Plant
  2. 实现二阶PID控制器的子系统 Controller;
  3. 带限白噪声 ProcessNoiseMeasurementNoise 模拟外部冲击和测量噪声;
  4. C功能块 Filter,其中实现了alpha-beta过滤器。

参数 Sample Time 街区 Filter 等于模型求解器的步骤 Ts:

image.png

让我们分析一下选项卡的内容 Build options 块设置 Filter:

image.png

在此选项卡的行中:

  • Source files -源代码文件已连接 alphabetafilter.c;
  • Iinclude directories -包含头文件的文件夹的路径设置;
  • Headers -头文件已连接 alphabetafilter.h.

在标签中 Ports 源代码变量与块的输入和输出端口相关联。 Filter.

块的源代码中 Filter 在标签上 OutputCode 给出了循环执行的代码:

image.png

在模型计算的每个步骤中,函数按顺序调用 determineAlphaBeta()alphabetafilter(),之后将过滤后的值保存到变量中 out 对应的输出端口 x 街区 Filter.

运行模拟

让我们为系统建模:

In [ ]:
cCodeIntegration_source = engee.load("$demoroot/models/cCodeIntegration_source.engee", force = true)
simulationResults_source = engee.run(cCodeIntegration_source)
Out[0]:
SimulationResult(
    "filtered" => WorkspaceArray{Float64}("cCodeIntegration_source/filtered")
,
    "noisy" => WorkspaceArray{Float64}("cCodeIntegration_source/noisy")

)

关闭模型:

In [ ]:
engee.close(cCodeIntegration_source, force = true);

模拟结果

导入模拟结果:

In [ ]:
cCodeIntegration_source_noisy_t = simulationResults_source["noisy"].time;
cCodeIntegration_source_noisy_y = simulationResults_source["noisy"].value;
In [ ]:
cCodeIntegration_source_filtered_t = simulationResults_source["filtered"].time;
cCodeIntegration_source_filtered_y = simulationResults_source["filtered"].value;

让我们建立一个图表:

In [ ]:
plot(cCodeIntegration_source_noisy_t, cCodeIntegration_source_noisy_y, label = "Исходный сигнал")
plot!(cCodeIntegration_source_filtered_t, cCodeIntegration_source_filtered_y, label = "Отфильтрованный сигнал")
plot!(legend = :bottomright)

title!("Альфа-бета фильтр <br> (Интеграция внешнего исходного кода)")
xlabel!("Время, [с]")
ylabel!("Амплитуда")
Out[0]:

静态和动态库的集成

设置任务

源代码通常不是显式提供的,而是作为静态或动态库的一部分提供的。 具有C API接口的库与外部源代码一样容易地集成到Engee模型中!

编译一个静态(alphabetafilter.a)和动态(alphabetafilter.so)文件库 alphabetafilter.calphabetafilter.h 使用 MakeFile.

文件内容 Makefile:

所有:alphabetafilter.一个alphabetafilter.so

字母过滤器。o:alphabetafilter。c
	$(CC) -c -fPIC $^-o $@

alphabetafilter.a: alphabetafilter.o
	ar rcs $@ $^

alphabetafilter.so: alphabetafilter.o
	$(CC)-\text{共享} $^ -o $@
    
清洁:
	rm-f*。o*。a*.所以

让我们开始编译库:

In [ ]:
run(`make -C $demoroot/source`)
make: Entering directory '/user/demo_renew/ccodeintegration/source'
cc -c -fPIC alphabetafilter.c -o alphabetafilter.o
ar rcs alphabetafilter.a alphabetafilter.o
cc -shared alphabetafilter.o -o alphabetafilter.so
make: Leaving directory '/user/demo_renew/ccodeintegration/source'
Out[0]:
Process(`make -C /user/demo_renew/ccodeintegration/source`, ProcessExited(0))

将静态和动态库集成到我们的Engee模型中。

静态库:模型分析

通过它的结构,模型 cCodeIntegration_library_static.engee 它与前面讨论的没有区别 cCodeIntegration_source.engee;只有选项卡上的指令不同 Build options 块设置 Filter. 让我们分析一下它的内容:

image.png

此处定义了以下构造选项:

  • Include directories -设置包含头文件的文件夹的路径。;
  • Library directories -设置包含静态库的文件夹的路径。;
  • Headers -头文件已连接 alphabetafilter.h;
  • Libraries -静态库已连接 alphabetafilter.a.

静态库:运行模拟

让我们为系统建模:

In [ ]:
cCodeIntegration_library_static = engee.load("$demoroot/models/cCodeIntegration_library_static.engee", force = true)
simulationResults_library_static = engee.run(cCodeIntegration_library_static)
Out[0]:
SimulationResult(
    "filtered" => WorkspaceArray{Float64}("cCodeIntegration_library_static/filtered")
,
    "noisy" => WorkspaceArray{Float64}("cCodeIntegration_library_static/noisy")

)

关闭模型:

In [ ]:
engee.close(cCodeIntegration_library_static, force = true);

静态库:仿真结果

导入模拟结果:

In [ ]:
cCodeIntegration_library_static_noisy_t = simulationResults_library_static["noisy"].time;
cCodeIntegration_library_static_noisy_y = simulationResults_library_static["noisy"].value;
In [ ]:
cCodeIntegration_library_static_filtered_t = simulationResults_library_static["filtered"].time;
cCodeIntegration_library_static_filtered_y = simulationResults_library_static["filtered"].value;

让我们建立一个图表:

In [ ]:
plot(cCodeIntegration_library_static_noisy_t, cCodeIntegration_library_static_noisy_y, label = "Исходный сигнал")
plot!(cCodeIntegration_library_static_filtered_t, cCodeIntegration_library_static_filtered_y, label = "Отфильтрованный сигнал")
plot!(legend = :bottomright)

title!("Альфа-бета фильтр <br> (Интеграция статической библиотеки)")
xlabel!("Время, [с]")
ylabel!("Амплитуда")
Out[0]:

动态库:模型分析

通过它的结构,模型 cCodeIntegration_library_dynamic.engee 它与前面讨论的没有区别 cCodeIntegration_source.engee;只有选项卡上的指令不同 Build options 块设置 Filter. 让我们分析一下它的内容:

image.png

此处定义了以下构造选项:

  • Include directories -包含头文件的文件夹的路径设置;
  • Library directories -设置包含动态库的文件夹的路径。;
  • Headers -头文件已连接 alphabetafilter.h;
  • Libraries -启用了动态库 alphabetafilter.so.

在块源代码编辑器的开始代码选项卡中 Filter 函数正在被调用 initializeStaticVariables():

dynamic_2.PNG

功能 initializeStaticVariables() 在文件中声明 alphabetafilter.h 它用于初始化静态变量。 xk_1vk_1,在动态库中使用。 这是必要的,以便在重新启动模拟时,变量不会保留其最后计算的值,而是重置为其原始值(在这种情况下,在 0).

动态库:运行模拟

让我们为系统建模:

In [ ]:
cCodeIntegration_library_dynamic = engee.load("$demoroot/models/cCodeIntegration_library_dynamic.engee", force = true)
simulationResults_library_dynamic = engee.run(cCodeIntegration_library_dynamic)
Out[0]:
SimulationResult(
    "filtered" => WorkspaceArray{Float64}("cCodeIntegration_library_dynamic/filtered")
,
    "noisy" => WorkspaceArray{Float64}("cCodeIntegration_library_dynamic/noisy")

)

关闭模型:

In [ ]:
engee.close(cCodeIntegration_library_dynamic, force = true);

动态库:仿真结果

导入模拟结果:

In [ ]:
cCodeIntegration_library_dynamic_noisy_t = simulationResults_library_dynamic["noisy"].time;
cCodeIntegration_library_dynamic_noisy_y = simulationResults_library_dynamic["noisy"].value;
In [ ]:
cCodeIntegration_library_dynamic_filtered_t = simulationResults_library_dynamic["filtered"].time;
cCodeIntegration_library_dynamic_filtered_y = simulationResults_library_dynamic["filtered"].value;

让我们建立一个图表:

In [ ]:
plot(cCodeIntegration_library_dynamic_noisy_t, cCodeIntegration_library_dynamic_noisy_y, label = "Исходный сигнал")
plot!(cCodeIntegration_library_dynamic_filtered_t, cCodeIntegration_library_dynamic_filtered_y, label = "Отфильтрованный сигнал")
plot!(legend = :bottomright)

title!("Альфа-бета фильтр <br> (Интеграция динамической библиотеки)")
xlabel!("Время, [с]")
ylabel!("Амплитуда")
Out[0]:

集成从Simulink模型生成的代码

设置任务

Simulink模型生成C代码 alphabetafilter.slx 并将其集成到我们的Engee模型中。 cCodeIntegration_cg_simulink.engee.

模型 alphabetafilter.slx,实现了alpha-beta滤波器,从简单的块组装在Simulink中,由子系统组成 determineAlphaBetafilterInputSignal.

模型的上层:

codegen_simulink_2.png

子系统 determineAlphaBeta:

codegen_simulink_3.png

子系统 filterInputSignal:

codegen_simulink_4.png

使用Simulink嵌入式编码器生成代码:

In [ ]:
cgPath = joinpath(demoroot,"cg/simulink")
cgModel = joinpath(demoroot,"cg/simulink/alphabetafilter")

mat"""
model = load_system($cgModel);
path = $cgPath;

set_param(0, 'CacheFolder', path)
set_param(0, 'CodeGenFolder', path)

slbuild(model)

set_param(0, 'CacheFolder', '')
set_param(0, 'CodeGenFolder', '')
"""
>> >> >> >> >> >> >> >> >> ### Starting build procedure for: alphabetafilter
### Generating code and artifacts to 'Model specific' folder structure
### Generating code into build folder: /user/demo_renew/ccodeintegration/cg/simulink/alphabetafilter_ert_rtw
### Invoking Target Language Compiler on alphabetafilter.rtw
### Using System Target File: /matlab/rtw/c/ert/ert.tlc
### Loading TLC function libraries
.......
### Generating TLC interface API for custom data
.
### Initial pass through model to cache user defined code
### Caching model source code
...................................
### Writing header file alphabetafilter_types.h
.
### Writing header file alphabetafilter.h
### Writing header file rtwtypes.h
### Writing source file alphabetafilter.c
### Writing header file alphabetafilter_private.h
### Writing source file alphabetafilter_data.c
.
### Writing source file ert_main.c
### TLC code generation complete (took 10.433s).
[Warning: P-code file /matlab/toolbox/coder/simulinkcoder_core/addStandardInfo.p
is older than source code file
/matlab/toolbox/coder/simulinkcoder_core/addStandardInfo.m.
/matlab/toolbox/coder/simulinkcoder_core/addStandardInfo.p may be obsolete and
may need to be regenerated.
Type "help pcode" for information about generating P-code.] 
### Saving binary information cache.
### Using toolchain: GNU gcc/g++ | gmake (64-bit Linux)
### Creating '/user/demo_renew/ccodeintegration/cg/simulink/alphabetafilter_ert_rtw/alphabetafilter.mk' ...
### Building 'alphabetafilter': "/matlab/bin/glnxa64/gmake"  -f alphabetafilter.mk all
gcc -c -fwrapv -fPIC -O0 -msse2 -DCLASSIC_INTERFACE=0 -DALLOCATIONFCN=0 -DTERMFCN=1 -DONESTEPFCN=1 -DMAT_FILE=0 -DMULTI_INSTANCE_CODE=0 -DINTEGER_CODE=0 -DMT=0  -DTID01EQ=0 -DMODEL=alphabetafilter -DNUMST=1 -DNCSTATES=0 -DHAVESTDIO -DMODEL_HAS_DYNAMICALLY_LOADED_SFCNS=0 -I/user/demo_renew/ccodeintegration/cg/simulink -I/user/demo_renew/ccodeintegration/cg/simulink/alphabetafilter_ert_rtw -I/matlab/extern/include -I/matlab/simulink/include -I/matlab/rtw/c/src -I/matlab/rtw/c/src/ext_mode/common -I/matlab/rtw/c/ert -o "alphabetafilter.o" "/user/demo_renew/ccodeintegration/cg/simulink/alphabetafilter_ert_rtw/alphabetafilter.c"
gcc -c -fwrapv -fPIC -O0 -msse2 -DCLASSIC_INTERFACE=0 -DALLOCATIONFCN=0 -DTERMFCN=1 -DONESTEPFCN=1 -DMAT_FILE=0 -DMULTI_INSTANCE_CODE=0 -DINTEGER_CODE=0 -DMT=0  -DTID01EQ=0 -DMODEL=alphabetafilter -DNUMST=1 -DNCSTATES=0 -DHAVESTDIO -DMODEL_HAS_DYNAMICALLY_LOADED_SFCNS=0 -I/user/demo_renew/ccodeintegration/cg/simulink -I/user/demo_renew/ccodeintegration/cg/simulink/alphabetafilter_ert_rtw -I/matlab/extern/include -I/matlab/simulink/include -I/matlab/rtw/c/src -I/matlab/rtw/c/src/ext_mode/common -I/matlab/rtw/c/ert -o "alphabetafilter_data.o" "/user/demo_renew/ccodeintegration/cg/simulink/alphabetafilter_ert_rtw/alphabetafilter_data.c"
gcc -c -fwrapv -fPIC -O0 -msse2 -DCLASSIC_INTERFACE=0 -DALLOCATIONFCN=0 -DTERMFCN=1 -DONESTEPFCN=1 -DMAT_FILE=0 -DMULTI_INSTANCE_CODE=0 -DINTEGER_CODE=0 -DMT=0  -DTID01EQ=0 -DMODEL=alphabetafilter -DNUMST=1 -DNCSTATES=0 -DHAVESTDIO -DMODEL_HAS_DYNAMICALLY_LOADED_SFCNS=0 -I/user/demo_renew/ccodeintegration/cg/simulink -I/user/demo_renew/ccodeintegration/cg/simulink/alphabetafilter_ert_rtw -I/matlab/extern/include -I/matlab/simulink/include -I/matlab/rtw/c/src -I/matlab/rtw/c/src/ext_mode/common -I/matlab/rtw/c/ert -o "ert_main.o" "/user/demo_renew/ccodeintegration/cg/simulink/alphabetafilter_ert_rtw/ert_main.c"
### Creating standalone executable ../alphabetafilter ...
g++  -o ../alphabetafilter alphabetafilter.o alphabetafilter_data.o ert_main.o  
### Created: ../alphabetafilter
### Successfully generated all binary outputs.
gmake: Nothing to be done for `all'.
### Successful completion of build procedure for: alphabetafilter
### Simulink cache artifacts for 'alphabetafilter' were created in '/user/demo_renew/ccodeintegration/cg/simulink/alphabetafilter.slxc'.

Build Summary

Top model targets built:

Model            Action                        Rebuild Reason                                    
=================================================================================================
alphabetafilter  Code generated and compiled.  Code generation information file does not exist.  

1 of 1 models built (0 models already up to date)
Build duration: 0h 0m 25.148s

模型分析

通过它的结构,模型 cCodeIntegration_cg_simulink.engee 它与前面讨论的没有区别 cCodeIntegration_source.engee;只有选项卡上的指令不同 Build options 块设置 Filter. 我们来分析一下它的内容:

image.png

此处定义了以下构造选项:

  • Source files -源代码文件已连接 alphabetafilter.calphabetafilter_data.c;
  • Include directories -包含头文件的文件夹的路径已设置;
  • Headers -头文件已连接 alphabetafilter.h, alphabetafilter_types.hrtwtypes.h.

循环执行的代码显示在选项卡上 Output code 块源代码编辑器 Filter:

image.png

在模型计算的每个步骤中,执行以下操作:

*结构的初始化 alphabetafilter_U 变量 in, processNoiseVariancemeasurementNoiseVariance (输入信号);

*函数调用 alphabetafilter_step();

*分配变量 out (输出信号)的结果 x,保存在结构中 alphabetafilter_Y.

在块源代码编辑器的开始代码选项卡中 Filter 函数正在被调用 alphabetafilter_initialize():

codegen_simulink_6.png

在块源代码编辑器的终止代码选项卡中 Filter 函数正在被调用 alphabetafilter_terminate():

codegen_simulink_7.png

运行模拟

让我们为系统建模:

In [ ]:
cCodeIntegration_cg_simulink = engee.load("$demoroot/models/cCodeIntegration_cg_simulink.engee", force = true)
simulationResults_cg_simulink = engee.run(cCodeIntegration_cg_simulink)
Out[0]:
SimulationResult(
    "filtered" => WorkspaceArray{Float64}("cCodeIntegration_cg_simulink/filtered")
,
    "noisy" => WorkspaceArray{Float64}("cCodeIntegration_cg_simulink/noisy")

)

关闭模型:

In [ ]:
engee.close(cCodeIntegration_cg_simulink, force = true);

模拟结果

导入模拟结果:

In [ ]:
cCodeIntegration_cg_simulink_noisy_t = simulationResults_cg_simulink["noisy"].time;
cCodeIntegration_cg_simulink_noisy_y = simulationResults_cg_simulink["noisy"].value;
In [ ]:
cCodeIntegration_cg_simulink_filtered_t = simulationResults_cg_simulink["filtered"].time;
cCodeIntegration_cg_simulink_filtered_y = simulationResults_cg_simulink["filtered"].value;

让我们建立一个图表:

In [ ]:
plot(cCodeIntegration_cg_simulink_noisy_t, cCodeIntegration_cg_simulink_noisy_y, label = "Исходный сигнал")
plot!(cCodeIntegration_cg_simulink_filtered_t, cCodeIntegration_cg_simulink_filtered_y, label = "Отфильтрованный сигнал")
plot!(legend = :bottomright)

title!("Альфа-бета фильтр <br> (Интеграция кода, сгенерированного из модели Simulink)")
xlabel!("Время, [с]")
ylabel!("Амплитуда")
Out[0]:

集成从Engee模型生成的代码

设置任务

Engee模型生成C代码 alphabetafilter.engee,由简单的块组装并实现alpha-beta过滤器,并将其集成到我们的Engee模型中 cCodeIntegration_cg_engee.engee.

模型的上层:

codegen_engee_2.PNG

子系统 determineAlphaBeta:

codegen_engee_3.PNG

子系统 filterInputSignal:

codegen_engee_4.PNG

让我们使用Engee代码生成器生成代码:

In [ ]:
engee.generate_code("$demoroot/cg/engee/alphabetafilter.engee", "$demoroot/cg/engee/alphabetafilter_cg")

模型分析

通过它的结构,模型 cCodeIntegration_cg_engee.engee 它与前面讨论的没有区别 cCodeIntegration_source.engee;只有选项卡上的指令不同 Build options 块设置 Filter. 让我们分析一下它的内容:

image.png

此处定义了以下构造选项:

  • Source files -源代码文件已连接 alphabetafilter.c;
  • Include directories -包含头文件的文件夹的路径已设置;
  • Headers -头文件已连接 alphabetafilter.h.

循环执行的代码显示在选项卡上 Output code 块源代码编辑器 Filter:

image.png

在模型计算的每个步骤中,执行以下操作:

*结构的初始化 alphabetafilter_U 变量 in, processNoiseVariancemeasurementNoiseVariance (输入信号);

*函数调用 alphabetafilter_step();

*分配变量 out (输出信号)的结果 x,保存在结构 alphabetafilter_Y.

在块源代码编辑器的开始代码选项卡中 Filter 函数正在被调用 alphabetafilter_init():

codegen_engee_6.PNG

在块源代码编辑器的终止代码选项卡中 Filter 函数正在被调用 alphabetafilter_term():

codegen_engee_7.PNG

运行模拟

让我们为系统建模:

In [ ]:
cCodeIntegration_cg_engee = engee.load("$demoroot/models/cCodeIntegration_cg_engee.engee", force = true)
simulationResults_cg_engee = engee.run(cCodeIntegration_cg_engee)
Out[0]:
SimulationResult(
    "filtered" => WorkspaceArray{Float64}("cCodeIntegration_cg_engee/filtered")
,
    "noisy" => WorkspaceArray{Float64}("cCodeIntegration_cg_engee/noisy")

)

关闭模型:

In [ ]:
engee.close(cCodeIntegration_cg_engee, force = true);

模拟结果

导入模拟结果:

In [ ]:
cCodeIntegration_cg_engee_noisy_t = simulationResults_cg_engee["noisy"].time;
cCodeIntegration_cg_engee_noisy_y = simulationResults_cg_engee["noisy"].value;
In [ ]:
cCodeIntegration_cg_engee_filtered_t = simulationResults_cg_engee["filtered"].time;
cCodeIntegration_cg_engee_filtered_y = simulationResults_cg_engee["filtered"].value;

让我们建立一个图表:

In [ ]:
plot(cCodeIntegration_cg_engee_noisy_t, cCodeIntegration_cg_engee_noisy_y, label = "Исходный сигнал")
plot!(cCodeIntegration_cg_engee_filtered_t, cCodeIntegration_cg_engee_filtered_y, label = "Отфильтрованный сигнал")
plot!(legend = :bottomright)

title!("Альфа-бета фильтр <br> (Интеграция кода, сгенерированного из модели Engee)")
xlabel!("Время, [с]")
ylabel!("Амплитуда")
Out[0]:

结论

这个例子演示了使用C函数块的特性以及将C代码集成到Engee模型中的各种方法。:

  1. 集成外部源代码;
  2. 静态和动态库的集成;
  3. 集成从Simulink模型生成的代码;
  4. Engee模型生成的代码的集成。