Документация Engee
Notebook

Автоматическая сборка и симуляция модели

Данный пример продолжает тему программного управления моделированием, которая до этого рассматривалась в проекте сообщества "Применение программного управления моделью".

Теперь уделим внимание публичным методам программного управления, позволяющим собирать блок-схемы (модели) из интерактивных скриптов, задавать параметры отдельных блоков, логировать выходы и запускать динамическую симуляцию в цикле с изменением параметров.

В рамках примера соберём упрощённую схему нелинейного усилителя мощности, и попробуем рассмотреть искажения входного синусоидального сигнала в зависимости от его уровня (амплитуды). В большинстве стандартных усилителей мощности будут наблюдаться два нелинейных явления:

  • плавное искажение формы пиков синусоидальных сигналов (мягкий клиппинг)
  • резкая обрезка пиков (насыщение, жёсткий клиппинг)

Для аудиосигнала это будет проявляться как "перегруз" или "дисторшн".

CLPPNG.png

Блоки, позволяющие смоделировать эти явления находятся в составе базовой библиотеки.

Создание модели

Укажем имя создаваемой модели усилителя мощности:

In [ ]:
mdlname = "amp_model"
Out[0]:
"amp_model"

Далее используем методы create и open, чтобы открыть модель на холсте:

In [ ]:
engee.create(mdlname)
engee.open(mdlname)
Out[0]:
System(
    name: root,
    id: eff890cd-7e30-4ac5-b5c1-8e9d84390539,
    path: amp_model
)

Метод add_block позволит нам добавить следующие блоки базовой библиотеки:

  • источник синусоидального сигнала
  • блок тригонометрической функции (модель мягкого клиппинга)
  • блок насыщения (модель жёсткого клиппинга)
  • блок заглушки
In [ ]:
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*"/")
Out[0]:
"amp_model/Заглушка"

Соединим последовательно четыре блока при помощи метода add-line:

In [ ]:
engee.add_line("Генератор синусоиды/1", "Тригонометрическая функция/1") 
engee.add_line("Тригонометрическая функция/1", "Насыщение/1")
engee.add_line("Насыщение/1", "Заглушка/1")

И автоматически упорядочим модель методом arrange_system:

In [ ]:
engee.arrange_system(mdlname)

В результат мы получаем аккуратный и читаемый вид блок-схемы:

amp_model.png

Сохраним модель в файл с расширением *.engee

In [ ]:
engee.save(mdlname * ".engee")

Настройка параметров блоков

Метод set_param! позволяет указывать численные и строковые параметры блоков в модели. Зададим амплитуду и частоту генерируемой синусоиды, тип тригонометрической функции и границы уровня выходного сигнала.

(о настройках общих параметров модели и симуляции можно узнать подробнее из документации и предыдущего примера)

In [ ]:
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:

In [ ]:
engee.set_log("Генератор синусоиды/1");
engee.set_log("Насыщение/1");

Запустим модель на динамическую симуляцию со стандартными настройками при помощи метода run. Запишем общий выход результатов симуляции в переменную result. Выделим отдельные переменные для входа и выхода нелинейной части системы, построим график функцией plot:

In [ ]:
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="Выход")
Out[0]:

Запуск симуляции в цикле

Будем изменять параметры блока источника сигнала в цикле и запускать симуляции программно. Варьироваться будут параметры амплитуды и частоты синусоиды. Результат будет записываться в переменную outmatrix:

In [ ]:
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:

In [ ]:
plot(x.time,outmatrix,labels=string.(collect(ampvec)'))
Out[0]:

А также построим матрицу в 3D функцией surface:

In [ ]:
surface(collect(freqvec), x.time, outmatrix, c = :rainbow)
Out[0]:

Заключение

В данном интерактивном скрипте мы рассмотрели основные принципы автоматизированного создания моделей и настройки параметров блоков, а также рассмотрели возможность запуска динамических симуляций в цикле с изменением параметров.

In [ ]:
engee.close_all()