Engee 文档
Notebook

将 MATLAB Simulink 模型转换为 Engee 模型

简介

在本示例中,我们将了解将用户工作从 MATLAB Simulink 自动转移到 Engee 的过程,并通过仿真原始模型和生成的模型来比较转移结果。

获取建立模型的脚本

Simulink传输模型的第一步是使用命令控制自动获取脚本以构建Engee模型。让我们先为本例中的文件定义变量:

In [ ]:
путь_примера = "$(@__DIR__)"                                # Путь к папке примера
имя_модели = "alphabetafilter"                              # Имя моделей
модельSLX = путь_примера*"/slx/"*имя_модели*".slx";         # Путь к исходной модели

mkdir(joinpath(путь_примера,"engee"));                      # Создаём папку для результирующей модели
скриптJL = путь_примера*"/engee/convert_script.jl";         # Путь к результирующему скрипту 
модельENGEE = путь_примера*"/engee/"*имя_модели*".engee";   # Путь к результирующей модели 

本例中使用的 MATLAB Simulink 模型是alphabetafilter.slx ,来自 将 C 代码集成到 Engee 模型中 示例。

现在让我们使用程序控制函数 engee.convert_model()。 该函数首先定义了源模型的内容,包括 子系统、模块、参数、模块和子系统的连接。 然后,根据获得的数据,用程序控制 命令创建脚本.jl ,以建立新的模型.engee

In [ ]:
engee.convert_model(модельSLX, скриптJL);           # Получение скрипта .jl для автоматического создания модели Engee
[ Info: Generated conversion script: /user/start/examples/project_management/slx_to_engee_conversion/engee/convert_script.jl

⚠️ 在转换模型时,值得考虑的是当前版本的Engee

In [ ]:
engee.version()
Out[0]:
"25.1.0"

代码生成器支持]1。 未来还将实现对Engee库中所有块的转换支持。

生成的脚本内容如下。代码中使用了以下函数来自动构建.engee 模型:

此外,程序控制可参见 相关示例

. <摘要>结果代码"real")
"real")
"real")
"real")
"real")
"+-")
"+-")
"4")
"-1")
"-2")
"-1")
"dt") engee.set_param!("alphabetafilter/determineAlphaBeta/Constant", "SampleTime"=>"0.0")
"8")
"1/4")
"-1")
"-1")
"2")
"-1")
"4")
"square")
"square")
"square")
"reciprocal")
"**")
"**")
"0")
"0")
"real")
"real")
"real")
"+-")
"dt")
"1/dt")
"**")
"**")
"0") engee.set_param!("alphabetafilter/filterInputSignal/Unit Delay", "SampleTime"=>"-1")
"0") engee.set_param!("alphabetafilter/filterInputSignal/Unit Delay1", "SampleTime"=>"-1")
"0")
"0")

建立 Engee 模型

Simulink模型转移到Engee模型的第二步,也是最后一步,是重现生成的脚本:

In [ ]:
cd(joinpath(путь_примера,"engee"))        # Переходим в папку примера – в ней будет располагаться модель .engee
include(скриптJL)                         # Запускаем выполнение скрипта .jl для автоматического создания модели .engee

作为前一个单元的结果,所需的模型文件将出现在当前示例的文件夹中.engee 。获得的模型即可使用。

使用程序控制的 engee.load()engee.open() 功能,我们可以确保已建模型的子系统被打开,从而正确创建子系统。

In [ ]:
# Функция для проверки модели и подсистем на открытие
function model_check(name::String, path::String, subsystem::String, delay::Int)     # Функция получает имя и путь модели, имя подсистемы, время ожидания
    model = engee.load(path; sync_gui=true)                                         # Загружаем модель
    sleep(delay)                                                                        # Ожидаем завершения синхронизации GUI
    engee.open(joinpath(name,subsystem); sync_gui=true)                             # Открываем подсистему 
    sleep(delay)                                                                        # Ожидаем завершения синхронизации GUI
    engee.save(model, name*".engee"; force=true, sync_gui=true)                     # Обновляем модель
    sleep(delay)                                                                        # Ожидаем завершения синхронизации GUI
                                                                                    # Закрываем модель
    try
        engee.close(model;sync_gui=true)
    catch e
        engee.close_all(;sync_gui=true)
    end
    sleep(delay)                                                                        # Ожидаем завершения синхронизации GUI
    return nothing                                                                  # Функция ничего не возвращает
end;

让我们检查一下模型和子系统是否已创建--让我们逐个打开子系统。单元格执行需要一些时间来同步图形用户界面 (GUI)。

In [ ]:
подсистемы = ["filterInputSignal", "determineAlphaBeta"]        # Вектор с именами открываемых подсистем

for i in подсистемы                                             # Цикл по вектору
    model_check(имя_модели, модельENGEE, i, 5)                  # Циклический вызов функции проверки модели и подсистем
                                                                # время ожидания = 3 [сек]. При медленной синхронизации GUI
                                                                # рекомендуется увеличить время ожидания
end

在单元执行过程中,模型和子系统选项卡会在 Engee 建模环境中打开和关闭。您必须等待所有模型和图形用户界面控制指令完成。

接下来,让我们对自动构建的模型.engee 进行验证。

验证获得的模型

让我们使用C 代码集成示例中描述的方法。

验证的初始数据是Simulink模型的结果。为了获得结果,让我们使用Simulink 嵌入式编码器从中生成代码。

In [ ]:
# Загружаем и устанавливаем библиотеку MATLAB, если она ещё не установлена
import Pkg; Pkg.add("MATLAB")
   Resolving package versions...
  No Changes to `~/.project/Project.toml`
  No Changes to `~/.project/Manifest.toml`
In [ ]:
cgModel = модельSLX                                     # Путь модели Simulink
cgPath = mkdir(joinpath(путь_примера,"slx","cg"));      # Создаём директорию для результатов генерации кода из модели Simulink

using MATLAB                                            # Подключаем библиотеку MATLAB

mat"""                                                  % Вставка кода на языке MATLAB
model = load_system($cgModel);                              % Загружаем модель Simulink в память 
path = $cgPath;                                             % Сохраняем путь к папке генерации кода

set_param(0, 'CacheFolder', path)                           % Определяем путь к папке кэша моделирования
set_param(0, 'CodeGenFolder', path)                         % Определяем путь к папке генерации кода

slbuild(model)                                              % Генерируем код из исходной модели Simulink

set_param(0, 'CacheFolder', '')                             % Сбрасываем путь к папке кэша моделирования
set_param(0, 'CodeGenFolder', '')                           % Сбрасываем путь к папке генерации кода
"""                                                     # Конец вставки кода
>> >> >> >> Model 'alphabetafilter' was exported from R2024b to R2023a. To find blocks that were removed during the export operation, <a href="matlab:slexportprevious.utils.displayReplacedBlocks('alphabetafilter')">click here</a>. Save the model to remove this notification.
>> >> >> >> >> >> ### Starting build procedure for: alphabetafilter
### Generating code and artifacts to 'Model specific' folder structure
### Generating code into build folder: /user/start/examples/project_management/slx_to_engee_conversion/slx/cg/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 13.524s).
[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/start/examples/project_management/slx_to_engee_conversion/slx/cg/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/start/examples/project_management/slx_to_engee_conversion/slx/cg -I/user/start/examples/project_management/slx_to_engee_conversion/slx/cg/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/start/examples/project_management/slx_to_engee_conversion/slx/cg/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/start/examples/project_management/slx_to_engee_conversion/slx/cg -I/user/start/examples/project_management/slx_to_engee_conversion/slx/cg/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/start/examples/project_management/slx_to_engee_conversion/slx/cg/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/start/examples/project_management/slx_to_engee_conversion/slx/cg -I/user/start/examples/project_management/slx_to_engee_conversion/slx/cg/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/start/examples/project_management/slx_to_engee_conversion/slx/cg/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/start/examples/project_management/slx_to_engee_conversion/slx/cg/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 39.355s

使用C Function块嵌入Simulink模型生成代码的模型是test_cg_simulink.engee 。C 文件的必要路径已在块C Function 中指定。
让我们加载、执行并关闭该模型。

In [ ]:
тест_моделиSLX = engee.load(joinpath(путь_примера, "test_cg_simulink.engee"), force = true);    # Загружаем модель для сбора исходных данных верификации
результаты_моделиSLX = engee.run(тест_моделиSLX);                                               # Выполняем модель и сохраняем исходные данные
In [ ]:
engee.close(тест_моделиSLX, force = true);    

为了清楚起见,让我们绘制建模后得到的信号:

In [ ]:
# Передадим результаты моделирования в отдельные переменные:
noisy_t_slx = результаты_моделиSLX["noisy"].time;
noisy_v_slx = результаты_моделиSLX["noisy"].value;
filtered_t_slx = результаты_моделиSLX["filtered"].time;
filtered_v_slx = результаты_моделиSLX["filtered"].value;

plot(noisy_t_slx, noisy_v_slx, label = "Исходный сигнал")                   # Строим график зашумленного сигнала
plot!(filtered_t_slx, filtered_v_slx, label = "Отфильтрованный сигнал")     # Строим график отфильтрованного сигнала (при помощи кода, сгенерированного из модели Simulink)
plot!(legend = :bottomright)                                                # Расположение легенды

title!("Результаты работы исходной модели Simulink")                        # Заголовок
xlabel!("Время, [с]")                                                       # Подпись оси X
ylabel!("Амплитуда")                                                        # Подпись оси Y
Out[0]:

Engee 模型的建模结果

现在,让我们利用自动生成的脚本建立恩吉模型,并从中获取结果。
定义模型的可调参数(与Simulink模型中的参数值相同):

In [ ]:
# Настраиваемые параметры модели:
dt = 0.01;
Gain = 1/dt;

从自动构建的 Engee 模型中 生成 C 代码

In [ ]:
engee.generate_code(модельENGEE, путь_примера*"/engee/code")        # Автоматическая генерация кода Си из модели Engee
[ Info: Generated code and artifacts: /user/start/examples/project_management/slx_to_engee_conversion/engee/code

与上一个模型相同,也使用了一个块来嵌入Engee模型生成的代码。 C Function 嵌入从 Engee 模型生成的代码 -test_cg_engee.engee 。C 文件的必要路径已在块C Function 中指定。
让我们加载、执行并关闭这个模型。

In [ ]:
тест_моделиENGEE = engee.load(joinpath(путь_примера, "test_cg_engee.engee"), force = true);     # Загружаем модель для сбора данных верификации модели Engee
результаты_моделиENGEE = engee.run(тест_моделиENGEE);                                           # Выполняем модель и сохраняем исходные данные
In [ ]:
engee.close(тест_моделиENGEE, force = true);   

为了清楚起见,让我们绘制建模后得到的信号:

In [ ]:
# Передадим результаты моделирования в отдельные переменные:
noisy_t_engee = результаты_моделиENGEE["noisy"].time;
noisy_v_engee = результаты_моделиENGEE["noisy"].value;
filtered_t_engee = результаты_моделиENGEE["filtered"].time;
filtered_v_engee = результаты_моделиENGEE["filtered"].value;

plot(noisy_t_engee, noisy_v_engee, label = "Исходный сигнал")                   # Строим график зашумленного сигнала
plot!(filtered_t_engee, filtered_v_engee, label = "Отфильтрованный сигнал")     # Строим график отфильтрованного сигнала (при помощи кода, сгенерированного из модели Engee)
plot!(legend = :bottomright)                                                    # Расположение легенды

title!("Результаты работы построенной модели Engee")                            # Заголовок
xlabel!("Время, [с]")                                                           # Подпись оси X
ylabel!("Амплитуда")                                                            # Подпись оси Y
Out[0]:

模拟结果比较

通过这些图表,我们可以肯定地得出结论:在两种建模环境中建立模型的结果是相似的。让我们计算一下Simulink模型和由其转换而来的Engee模型模拟结果绝对偏差的最小值和最大值:

In [ ]:
# Вычисляем абсолютные отклонения величин смоделированных сигналов
Δ_noisy_v = noisy_v_slx .- noisy_v_engee;
Δ_filtered_v = filtered_v_slx .- filtered_v_engee;

println("""Абсолютные отклонения величин сигналов для построенной модели Engee от исходной модели Simulink:
 - зашумленный сигнал       минимум: $(minimum(Δ_noisy_v))    максимум: $(maximum(Δ_noisy_v))
 - отфильтрованный сигнал   минимум: $(minimum(Δ_filtered_v))    максимум: $(maximum(Δ_filtered_v))""")
Абсолютные отклонения величин сигналов для построенной модели Engee от исходной модели Simulink:
- зашумленный сигнал       минимум: 0.0    максимум: 0.0
- отфильтрованный сигнал   минимум: 0.0    максимум: 0.0

从图形和分析比较中可以看出,自动生成的Engee模型的性能与原始Simulink模型的性能相比没有偏差。

结论

在本例中,我们考察了将Simulink模型转换为Engee模型的过程,并使用自动代码生成验证了所建模型。我们还详细研究了 Engee 软件控制功能的应用。实验结束后,我们发现转换后的Engee模型与原始的Simulink模型并无不同。为避免混淆,可删除不必要的原始模型:

In [ ]:
# rm(модельSLX; force=true); # При необходимости раскомментируйте строку