Автоматическая сборка и симуляция модели
Данный пример продолжает тему программного управления моделированием, которая до этого рассматривалась в проекте сообщества "Применение программного управления моделью".
Теперь уделим внимание публичным методам программного управления, позволяющим собирать блок-схемы (модели) из интерактивных скриптов, задавать параметры отдельных блоков, логировать выходы и запускать динамическую симуляцию в цикле с изменением параметров.
В рамках примера соберём упрощённую схему нелинейного усилителя мощности, и попробуем рассмотреть искажения входного синусоидального сигнала в зависимости от его уровня (амплитуды). В большинстве стандартных усилителей мощности будут наблюдаться два нелинейных явления:
- плавное искажение формы пиков синусоидальных сигналов (мягкий клиппинг)
- резкая обрезка пиков (насыщение, жёсткий клиппинг)
Для аудиосигнала это будет проявляться как "перегруз" или "дисторшн".
Блоки, позволяющие смоделировать эти явления находятся в составе базовой библиотеки.
Создание модели
Укажем имя создаваемой модели усилителя мощности:
mdlname = "amp_model"
Далее используем методы create и open, чтобы открыть модель на холсте:
engee.create(mdlname)
engee.open(mdlname)
Метод add_block позволит нам добавить следующие блоки базовой библиотеки:
- источник синусоидального сигнала
- блок тригонометрической функции (модель мягкого клиппинга)
- блок насыщения (модель жёсткого клиппинга)
- блок заглушки
engee.add_block("/Basic/Sources/Sine Wave", mdlname*"/")
engee.add_block("/Basic/Math Operations/Trigonometric Function", mdlname*"/")
engee.add_block("/Basic/Discontinuities/Saturation", mdlname*"/")
engee.add_block("/Basic/Sinks/Terminator", mdlname*"/")
Соединим последовательно четыре блока при помощи метода add-line:
engee.add_line("Генератор синусоиды/1", "Тригонометрическая функция/1")
engee.add_line("Тригонометрическая функция/1", "Насыщение/1")
engee.add_line("Насыщение/1", "Заглушка/1")
И автоматически упорядочим модель методом arrange_system:
engee.arrange_system(mdlname)
В результат мы получаем аккуратный и читаемый вид блок-схемы:

Сохраним модель в файл с расширением *.engee
engee.save(mdlname * ".engee")
Настройка параметров блоков
Метод set_param! позволяет указывать численные и строковые параметры блоков в модели. Зададим амплитуду и частоту генерируемой синусоиды, тип тригонометрической функции и границы уровня выходного сигнала.
(о настройках общих параметров модели и симуляции можно узнать подробнее из документации и предыдущего примера)
engee.set_param!(mdlname*"/Генератор синусоиды", "Amplitude" => 0.75)
engee.set_param!(mdlname*"/Генератор синусоиды", "Frequency" => 2.0)
engee.set_param!(mdlname*"/Тригонометрическая функция", "Operator" => "tanh")
engee.set_param!(mdlname*"/Насыщение", "UpperLimit" => 0.6)
engee.set_param!(mdlname*"/Насыщение", "LowerLimit" => -0.6)
Логирование сигналов и запуск симуляции
В первую очередь залогируем выходы Генератора синусоиды и блока Насыщения методом set_log:
engee.set_log("Генератор синусоиды/1");
engee.set_log("Насыщение/1");
Запустим модель на динамическую симуляцию со стандартными настройками при помощи метода run. Запишем общий выход результатов симуляции в переменную result. Выделим отдельные переменные для входа и выхода нелинейной части системы, построим график функцией plot:
result = engee.run(mdlname);
x = collect(result["Генератор синусоиды.1"]);
y = collect(result["Насыщение.1"]);
plot(x.time,x.value,lw=2,label="Вход")
plot!(y.time,y.value,lw=2,label="Выход")
Запуск симуляции в цикле
Будем изменять параметры блока источника сигнала в цикле и запускать симуляции программно. Варьироваться будут параметры амплитуды и частоты синусоиды. Результат будет записываться в переменную outmatrix:
ampvec = 0.25:0.25:1.25;
n = length(ampvec);
freqvec = LinRange(1,3,n)
outmatrix = zeros(length(x.time),n);
for i = 1:n
engee.set_param!(mdlname*"/Генератор синусоиды", "Amplitude" => ampvec[i])
engee.set_param!(mdlname*"/Генератор синусоиды", "Frequency" => freqvec[i])
tempresult = engee.run(mdlname);
tempout = collect(tempresult["Насыщение.1"]);
outmatrix[:,i] = tempout.value;
end
Отобразим результирующие выходные сигналы на одних осях функцией plot:
plot(x.time,outmatrix,labels=string.(collect(ampvec)'))
А также построим матрицу в 3D функцией surface:
surface(collect(freqvec), x.time, outmatrix, c = :rainbow)
Заключение
В данном интерактивном скрипте мы рассмотрели основные принципы автоматизированного создания моделей и настройки параметров блоков, а также рассмотрели возможность запуска динамических симуляций в цикле с изменением параметров.
engee.close_all()