Engee documentation
Notebook

Building Lissajous curves

Modeling basic mathematical objects helps to better understand the work of the processes that generate them. In this example, we will explore two ways to build models that create Lissajous shapes, as well as configure these models and compare their operation using the program management commands described on the documentation page "Software simulation management".

The simulated process

Lissajous figures are tracks drawn by a point that performs two harmonic vibrations simultaneously. They are usually generated using a system of two trigonometric functions. Dependence of coordinates and from time to time it has the following form:

here – the amplitudes of each harmonic process (we will have equal 1)

– the frequencies of both processes,

– the shift between harmonic processes.

A model created from sinusoid generators

Our first model will consist of two blocks Sine Wave.

lissajous_curve_blocks_img.png

The model specified as a code

The second model will consist of one block Engee Function and several blocks Constant, setting the system parameters we are interested in.

lissajous_curve_function_img.png

In both cases, the output parameters are the signals x and y, and they are marked as logable signal. Thanks to this, we will be able to count them when the simulation is started programmatically.

Loading models

The first step is to get control of these models. When the model is already open (for example, it is on the canvas), one command is used for this, when it needs to be loaded, another command is needed. Getting a list of uploaded models:

In [ ]:
all_model_names = [m.name for m in engee.get_all_models()]
Out[0]:
String[]

If the model is already open, then we use the function open to get control for a few days. If not, we will use the function load.

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

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

Now we have two objects., m1 and m2 through which we can control the parameters and operation of both models we are studying.

Synchronization of model parameters

From the ratio of the parameters and the shape of the curve (the number of petals) depends. Now we will set the same parameters for both models using software control commands. We want the models to use the following parameters:

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

Let's study the structure of the block parameters Sine Wave models lissajous_curve_blocks.

In [ ]:
param = engee.get_param( "lissajous_curve_blocks/Sine Wave" )
Out[0]:
Dict{String, Any} with 11 entries:
  "Offset"     => "0"
  "SineType"   => "Time based"
  "Bias"       => "0.0"
  "SampleTime" => "0.0"
  "BlockName"  => "Sine Wave"
  "Amplitude"  => "1"
  "Frequency"  => "4"
  "BlockType"  => "Sin"
  "Samples"    => "10"
  "TimeSource" => "Use simulation time"
  "Phase"      => "0"

This is a type structure Pair, which can be changed and passed in its entirety as new block parameters lissajous_curve_blocks/Sine Wave:

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

You can also use a shorter syntax. Let's do the same for the second block and for the second model.:

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

The structure of the simulation parameters can be obtained by the command engee.get_param( "lissajous_curve_function" ).

We will set the same simulation step for both models.:

In [ ]:
param = engee.get_param( "lissajous_curve_blocks" )
Out[0]:
Dict{String, Any} with 25 entries:
  "MinStep"                  => "auto"
  "MaxConsecutiveMinStep"    => "10"
  "breakpointsConfig"        => nothing
  "ZcThreshold"              => "1e-10"
  "SolverName"               => "Euler"
  "InitialStep"              => "auto"
  "CreateCFunction"          => false
  "DefaultParameterBehavior" => "Inlined"
  "RelTol"                   => "auto"
  "debuggingInfo"            => Dict{String, Any}("SavePhysicalVariableInitiali…
  "SimulationMode"           => "rapid-accelerator"
  "TargetHardware"           => "C"
  "OutputTimes"              => "1e-2"
  "MaxStep"                  => "auto"
  "StopTime"                 => "10"
  "loggingData"              => Dict{String, Any}("chartTabs"=>Any[Dict{String,…
  "StartTime"                => "0.0"
  "SolverType"               => "fixed-step"
  "EnableMultiTasking"       => false
  "OutputOption"             => "null"
  "simulationStepSettings"   => nothing
  "GenerateComments"         => true
  "AbsTol"                   => "auto"
  "FixedStep"                => "0.01"
  "SaveSignalsAtEvents"      => true
In [ ]:
# Установим обеим моделям временной шаг 0.001
engee.set_param!( "lissajous_curve_function", "FixedStep"=>"0.001" )
engee.set_param!( "lissajous_curve_blocks", "FixedStep"=>"0.001" )

Now we can execute these models using the command run:

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

# Иногда нужно дождаться, пока модель закончит выполнение
# while( engee.get_status() != Engee.Types.READY ) end;
In [ ]:
r2 = engee.run( m2; verbose=false )
Out[0]:
SimulationResult(
    "x" => WorkspaceArray{Float64}("lissajous_curve_function/x")
,
    "y" => WorkspaceArray{Float64}("lissajous_curve_function/y")

)

At the output we get the structure Dict (dictionary), which contains a set of tables DataFrame. Each table has vector columns time and value, corresponding to the time and output value of each stored model signal.

Simulation results

The output curves can be easily compared using a graph.:

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

Conclusions

We have studied the operation of two models of one of the basic mathematical objects, which is considered in a wide variety of technical disciplines – from physics to circuit engineering. We also applied the program control mechanism, setting the same parameters for the models and analyzing the simulation results on the graph without leaving the script.