将 MATLAB Simulink 模型转换为 Engee 模型
简介
在本示例中,我们将了解将用户工作从 MATLAB Simulink 自动转移到 Engee 的过程,并通过仿真原始模型和生成的模型来比较转移结果。
获取建立模型的脚本
从Simulink传输模型的第一步是使用命令控制自动获取脚本以构建Engee模型。让我们先为本例中的文件定义变量:
путь_примера = "$(@__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
。
engee.convert_model(модельSLX, скриптJL); # Получение скрипта .jl для автоматического создания модели Engee
⚠️ 在转换模型时,值得考虑的是当前版本的Engee:
engee.version()
代码生成器支持]1。
未来还将实现对Engee库中所有块的转换支持。
生成的脚本内容如下。代码中使用了以下函数来自动构建.engee
模型:
engee.create()
- 创建一个新模型;engee.add_block()
- 从 Engee 库中添加一个块;engee.set_param!()
- 更新模型/块参数;engee.delete_contents()
- 删除系统内容;engee.add_line()
- 添加块之间的通信/链接;engee.save()
- 保存模型;engee.close()
- 关闭模型。
此外,程序控制可参见 相关示例。
"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模型的第二步,也是最后一步,是重现生成的脚本:
cd(joinpath(путь_примера,"engee")) # Переходим в папку примера – в ней будет располагаться модель .engee
include(скриптJL) # Запускаем выполнение скрипта .jl для автоматического создания модели .engee
作为前一个单元的结果,所需的模型文件将出现在当前示例的文件夹中.engee
。获得的模型即可使用。
使用程序控制的 engee.load()
和 engee.open()
功能,我们可以确保已建模型的子系统被打开,从而正确创建子系统。
# Функция для проверки модели и подсистем на открытие
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)。
подсистемы = ["filterInputSignal", "determineAlphaBeta"] # Вектор с именами открываемых подсистем
for i in подсистемы # Цикл по вектору
model_check(имя_модели, модельENGEE, i, 5) # Циклический вызов функции проверки модели и подсистем
# время ожидания = 3 [сек]. При медленной синхронизации GUI
# рекомендуется увеличить время ожидания
end
在单元执行过程中,模型和子系统选项卡会在 Engee 建模环境中打开和关闭。您必须等待所有模型和图形用户界面控制指令完成。
接下来,让我们对自动构建的模型.engee
进行验证。
验证获得的模型
让我们使用C 代码集成示例中描述的方法。
模拟原始 Simulink 模型
验证的初始数据是Simulink模型的结果。为了获得结果,让我们使用Simulink 嵌入式编码器从中生成代码。
# Загружаем и устанавливаем библиотеку MATLAB, если она ещё не установлена
import Pkg; Pkg.add("MATLAB")
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', '') % Сбрасываем путь к папке генерации кода
""" # Конец вставки кода
使用C Function
块嵌入Simulink模型生成代码的模型是test_cg_simulink.engee
。C 文件的必要路径已在块C Function
中指定。
让我们加载、执行并关闭该模型。
тест_моделиSLX = engee.load(joinpath(путь_примера, "test_cg_simulink.engee"), force = true); # Загружаем модель для сбора исходных данных верификации
результаты_моделиSLX = engee.run(тест_моделиSLX); # Выполняем модель и сохраняем исходные данные
engee.close(тест_моделиSLX, force = true);
为了清楚起见,让我们绘制建模后得到的信号:
# Передадим результаты моделирования в отдельные переменные:
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
Engee 模型的建模结果
现在,让我们利用自动生成的脚本建立恩吉模型,并从中获取结果。
定义模型的可调参数(与Simulink模型中的参数值相同):
# Настраиваемые параметры модели:
dt = 0.01;
Gain = 1/dt;
从自动构建的 Engee 模型中 生成 C 代码:
engee.generate_code(модельENGEE, путь_примера*"/engee/code") # Автоматическая генерация кода Си из модели Engee
与上一个模型相同,也使用了一个块来嵌入Engee模型生成的代码。
C Function
嵌入从 Engee 模型生成的代码 -test_cg_engee.engee
。C 文件的必要路径已在块C Function
中指定。
让我们加载、执行并关闭这个模型。
тест_моделиENGEE = engee.load(joinpath(путь_примера, "test_cg_engee.engee"), force = true); # Загружаем модель для сбора данных верификации модели Engee
результаты_моделиENGEE = engee.run(тест_моделиENGEE); # Выполняем модель и сохраняем исходные данные
engee.close(тест_моделиENGEE, force = true);
为了清楚起见,让我们绘制建模后得到的信号:
# Передадим результаты моделирования в отдельные переменные:
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
模拟结果比较
通过这些图表,我们可以肯定地得出结论:在两种建模环境中建立模型的结果是相似的。让我们计算一下Simulink模型和由其转换而来的Engee模型模拟结果绝对偏差的最小值和最大值:
# Вычисляем абсолютные отклонения величин смоделированных сигналов
Δ_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模型的性能相比没有偏差。
结论
在本例中,我们考察了将Simulink模型转换为Engee模型的过程,并使用自动代码生成验证了所建模型。我们还详细研究了 Engee 软件控制功能的应用。实验结束后,我们发现转换后的Engee模型与原始的Simulink模型并无不同。为避免混淆,可删除不必要的原始模型:
# rm(модельSLX; force=true); # При необходимости раскомментируйте строку