Пример программного управления в моделировании
Введение
В данном примере мы создадим модель с помощью методов программного управления. Наша цель – показать, как можно реализовать модель программно с помощью инструментов рабочего пространства — командной строки и редактора скриптов .
Для создания модели с помощью методов программного управления откроем командную строку или редактор скриптов Engee. Выбор инструмента не является принципиальным и в случае создания примера не будет отличаться по синтаксису. Однако, редактор скриптов позволит рефакторить уже инициализированные строки кода, что может быть полезным для создания собственных моделей. В дальнейшем будем использовать редактор скриптов.
Создание/загрузка модели
По умолчанию при запуске Engee создается модель newmodel_1, с которой мы и будем работать в дальнейшем. Однако, вы можете создать или загрузить другую модель, выбрав нужный вам метод из предложенных ниже:
Создание/загрузка/открытие модели
Используйте метод create для создания модели:
model = "newmodel_2" # создает переменную model со значением "model_name"
engee.create(model) # создает модель из переменной
или создайте модель напрямую без инициализации переменной:
engee.create("newmodel_2")
Вы можете загрузить уже существующую модель с помощью метода load:
engee.load("/user/newmodel_2.engee")
# или
engee.load("/user/newmodel_2.engee"; force = true) # force = true обязательно указывается в случае, если модель уже была загружена ранее
Добавление блока
Для начала добавим блоки из библиотеки в нашу модель newmodel_1 с помощью метода add_block:
engee.add_block("/Basic/Sources/Sine Wave", "newmodel_1/") # добавляет блок Sin Wave из библиотеки Basic/Sources и присваивает имя автоматически
и аналогично для блока Terminator:
engee.add_block("/Basic/Sinks/Terminator", "newmodel_1/") # аналогично добавляет блок Terminator, но уже из другой библиотеки
В данном случае имена присваиваются автоматически, например Terminator сменит имя на Terminator-1, если блок с таким именем уже существует в модели. |
При необходимости вы можете сами задавать имена блокам, добавив их название после слэша / имени модели:
engee.add_block("/Basic/Sources/Sine Wave", "newmodel_1/Sine Wave-x") #добавит блок Sine Wave с именем Sin Wave-x
Удалить ненужный блок можно через метод delete_block:
engee.delete_block("newmodel_1/Sine Wave-x") # удалит блок Sine Wave-x и все связанные с ним линии и блоки из системы
Добавление линий
Добавим соединительную сигнальную линию между добавленными блоками с помощью метода add_line:
engee.add_line("Sine Wave/1", "Terminator/1") # устанавливает сигнал между выходным портом №1 у блока Sin Wave и входным портом №1 блока Terminator
Включите запись сигналов для созданной сигнальной линии между блоками Sin Wave и Terminator, нажав левой кнопкой мыши по сигналу и выбрав Запись:
Это необходимо для получения данных с блока после завершения симуляции модели. |
Настройка параметров модели
Получим параметры модели с помощью метода get_param:
engee.get_param("newmodel_1") - # получение параметров моделирования
Вывод get_param с постоянным шагом
ModelParameters( :EnableMultiTasking => false :GenerateComments => true #Параметры интегратора: :StartTime => 0.0 :StopTime => 10 :SolverType => fixed-step :SolverName => Euler :FixedStep => 0.01 )
Перечень настраиваемых параметров моделей отличается в зависимости от выбранного шага (постоянного или переменного). Например, get_param для упомянутой выше модели с переменным шагом будет показывать следующие параметры:
Вывод get_param с переменным шагом
ModelParameters(
:EnableMultiTasking => false
:GenerateComments => true
#Параметры интегратора:
:StartTime => 0.0
:StopTime => 10
:SolverName => Tsit5
:SolverType => variable-step
:MaxStep => auto #максимальный размер шага
:MinStep => auto #минимальный размер шага
:InitialStep => auto #начальный размер шага
:RelTol => auto #относительная точность
:AbsTol => auto #абсолютная точность
:OutputOption => true #плотная выдача
:OutputTimes => 1e-2 #интервал
)
Изменим несколько параметров модели с помощью метода set_param!:
engee.set_param!("newmodel_1", "FixedStep" => 0.05, "StopTime" => 40) # меняем фиксированный размер шага и время окончания симуляции
Далее повторно используем get_param для отслеживания изменения параметров:
Вывод get_param с измененными параметрами
ModelParameters( :EnableMultiTasking => false :GenerateComments => true #Параметры интегратора: :StartTime => 0.0 :StopTime => 40.0 :SolverType => fixed-step :SolverName => Euler :FixedStep => 0.05 )
Симуляция
Запустим симуляцию нашей модели с помощью метода run:
engee.run("newmodel_1")
Благодаря включенной ранее записи сигналов, переменная simout, хранящая результаты симуляции, получила значение SimulationResult("newmodel_1/Sine Wave.1" ⇒ WorkspaceArray("newmodel_1/Sine Wave.1"))
, представленное в виде таблицы DataFrame:
Вывод
Dict{String, DataFrames.DataFrame} with 1 entry:
"Sine Wave.1" => 801×2 DataFrame…
Сохраним результаты симуляции в оперативную память Engee с помощью функции collect
в виде переменной result
:
result = collect(simout["newmodel_1/Sine Wave.1"])
Дополнительно получим результаты симуляции с помощью метода get_results не прибегая к переменной simout:
Обе переменных с результатами симуляции ( |
Для удобства продолжим работу с переменной result
. DataFrame переменной result
состоит из двух столбцов — time (время) и value (значение). Визуализируем DataFrame с помощью библиотеки Plots:
using Plots
plot(result.time, result.value)
Дополнительно можно сохранить результаты симуляции в формате CSV:
|
Кодогенерация
Сгенерируем код модели с помощью метода generate_code:
engee.generate_code("/user/newmodel_1.engee", "/user/codegen_dir") # сгенерировали код из модели newmodel_1.engee, код будет храниться в папке codegen_dir
Сгенерированный код будет находиться в папке codegen_dir в файлах newmodel_1.h, newmodel_1.c и main.c.
В конце сохраним нашу модель с помощью метода save:
engee.save("/user/newmodel_1.engee"; force=true)