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

Построение кривых Лиссажу

Моделирование базовых математических объектов помогает лучше понять работу порождающих их процессов. В этом примере мы изучим два способа построения модели, создающих фигуры Лиссажу, а также настроим эти модели и сравним их работу при помощи команд программного управления, описанных на странице документации "Программное управление моделированием".

Моделируемый процесс

Фигуры Лиссажу – это тректории, прочерчиваемые точкой, совершающей одновременно два гармонических колебания. Обычно их порождают при помощи системы из двух тригонометрических функций. Зависимость координат $x$ и $y$ от времени $t$ имеет следующий вид:

$$\left\{\begin{align*} x(t) &= A \, sin(\alpha t + \beta) \\ y(t) &= B \, sin(\beta t) \end{align*}\right.$$

здесь $A, B$ – амплитуды каждого гармонического процесса (у нас будут равны 1)

$\alpha, \beta$ – частоты обоих процессов,

$\delta$ – смещение между гармоническими процессами.

Модель, созданная из генераторов синусоид

Первая наша модель будет состоять из двух блоков Sine Wave.

lissajous_curve_blocks_im.png

Модель, заданная в виде кода

Вторая модель будет состоять из одного блока Engee Function и нескольких блоков Constant, задающих интересующие нас параметры системы.

lissajous_curve_function_im.png

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

Загрузка моделей

Первым делом нужно получить управления этими моделями. Когда модель уже открыта (например, находится на холсте), для этого служит одна команда, когда ее нужно загружать – нужна другая команда. Получим список загруженных моделей:

In [ ]:
all_model_names = [m.name for m in engee.get_all_models()]
Out[0]:
1-element Vector{String}:
 "engee_function_moving_average"

Если модель уже открыта, то мы используем функцию open чтобы получить на дней управление. Если нет, то мы воспользуемся функцией load.

In [ ]:
# Модель, состоящая из блоков
if "lissajous_curve_blocks" in all_model_names m1 = engee.open( "lissajous_curve_blocks" )
else m1 = engee.load( "/user/start/examples/edu/lissajous_curves/lissajous_curve_blocks.engee" )
end;

# Модель, состоящая из кода
if "lissajous_curve_function" in all_model_names m2 = engee.open( "lissajous_curve_function" )
else m2 = engee.load( "/user/start/examples/edu/lissajous_curves/lissajous_curve_function.engee" )
end;

Теперь у нас есть два объекта, m1 и m2, через которые мы можем управлять параметрами и работой обеих изучаемых нами моделей.

Синхронизация параметров моделей

От соотношения параметров $\alpha$ и $\beta$ зависит форма кривой (количество лепестков). Сейчас мы выставим обеим моделям одинаковые параметры при помощи команд программного управления. Мы хотим, чтобы модели использовали следующие параметры:

In [ ]:
alpha = 3;
beta = 4;

Изучим структуру параметров блока Sine Wave модели lissajous_curve_blocks.

In [ ]:
param = engee.get_param( "lissajous_curve_blocks/Sine Wave" )
Out[0]:
BlockParameters(
  SineType => Time based,
  Amplitude => 1,
  Bias => 0.0,
  TimeSource => Use simulation time,
  Frequency => 4,
  Phase => 0,
  SampleTime => 0.0,
)

Это структура типа Pair, которую можно изменить и передать целиком в качестве новых параметров блока lissajous_curve_blocks/Sine Wave:

In [ ]:
param.Frequency = alpha
engee.set_param!( "lissajous_curve_blocks/Sine Wave", param )

Можно использовать и более короткий синтаксис. Сделаем то же самое для второго блока и для второй модели:

In [ ]:
engee.set_param!( "lissajous_curve_blocks/Sine Wave-1", "Frequency"=>beta )
engee.set_param!( "lissajous_curve_function/Constant", "Value"=>alpha )
engee.set_param!( "lissajous_curve_function/Constant-1", "Value"=>beta )

Структуру параметров симуляции можно получить командой engee.get_param( "lissajous_curve_function" ).

Установим обеим моделям один и тот же шаг симуляции:

In [ ]:
param = engee.get_param( "lissajous_curve_blocks" )
Out[0]:
ModelParameters(
  :EnableMultiTasking => false
  :GenerateComments => true

  #Параметры интегратора:
  :StartTime => 0.0
  :StopTime => 10
  :SolverType => fixed-step
  :SolverName => Euler
  :FixedStep => 0.01
)
In [ ]:
# Установим обеим моделям временной шаг 0.001
engee.set_param!( "lissajous_curve_function", "FixedStep"=>0.001 )
engee.set_param!( "lissajous_curve_blocks", "FixedStep"=>0.001 )

Теперь мы можем выполнить эти модели при помощи команды run:

In [ ]:
r1 = engee.run( m1; verbose=false );

# Иногда нужно дождаться, пока модель закончит выполнение
# while( engee.get_status() != Engee.Types.READY ) end;
In [ ]:
r2 = engee.run( m2; verbose=false );

На выходе мы получаем структуру Dict (словарь), который содержит набор таблиц DataFrame. В каждой таблице есть столбцы вектор time и value, соответствующие времени и выходному значению каждого сохранённого сигнала модели.

Результаты моделирования

Выходные кривые легко сравнить при помощи графика:

In [ ]:
using Plots
plot( r1["x"].value, r1["y"].value, lc=:red, lw=10, label="Блоки Sine Wave" )
plot!( r2["x"].value, r2["y"].value, lc=:orange, lw=4, label="Блоки Engee Function" )
Out[0]:
No description has been provided for this image

Выводы

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

Блоки, использованные в примере