Engee documentation
Notebook

Automatic model assembly and simulation

This example continues the theme of software modeling management, which was previously considered in the community project "Application of software management моделью".

Now let's pay attention to public methods of program management, which allows you to assemble flowcharts (models) from interactive scripts, set the parameters of individual blocks, log outputs, and run a dynamic simulation in a loop with parameter changes.

As an example, we will assemble a simplified circuit of a nonlinear power amplifier, and try to consider the distortions of the input sinusoidal signal depending on its level (amplitude). Two nonlinear phenomena will be observed in most standard power amplifiers:

  • smooth distortion of the peaks of sinusoidal signals (soft clipping)
  • sharp trimming of peaks (saturation, hard clipping)

For the audio signal, this will manifest as "overload" or "distortion".

CLPPNG.png

The blocks that allow you to simulate these phenomena are included in the basic library.

Creating a model

Specify the name of the power amplifier model to be created:

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

Next, we use the methods create and open to open the model on the canvas:

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

Method add_block this will allow us to add the following blocks of the base library:

  • Sinusoidal signal source
  • trigonometric function block (soft clipping model)
  • Saturation block (hard clipping model)
  • plug 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/Заглушка"

Let's connect four blocks in series using the method add-line:

In [ ]:
engee.add_line("Sinusoid generator/1", "Trigonometric function/1") 
engee.add_line("Trigonometric function/1", "Saturation/1")
engee.add_line("Saturation/1", "Plug/1")

And we will automatically arrange the model using the method arrange_system:

In [ ]:
engee.arrange_system(mdlname)

As a result, we get a neat and readable flowchart.:

amp_model.png

Saving the model to a file with the *.engee extension

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

Configuring Block parameters

Method set_param! allows you to specify numerical and string parameters of blocks in the model. We will set the amplitude and frequency of the generated sinusoid, the type of trigonometric function, and the boundaries of the output signal level.

(you can learn more about the settings of the general parameters of the model and simulation from the documentation and the previous example)

In [ ]:
engee.set_param!(mdlname*"/Sinusoid Generator", "Amplitude" => 0.75)
engee.set_param!(mdlname*"/Sinusoid Generator", "Frequency" => 2.0)
engee.set_param!(mdlname*"/The trigonometric function", "Operator" => "tanh")
engee.set_param!(mdlname*"/Saturation", "UpperLimit" => 0.6)
engee.set_param!(mdlname*"/Saturation", "LowerLimit" => -0.6)

Signal logging and simulation start

First of all, we analyze the outputs of the Sine Wave Generator and the Saturation block using the method set_log:

In [ ]:
engee.set_log("Sinusoid generator/1");
engee.set_log("Saturation/1");

Let's run the model for dynamic simulation with standard settings using the method run. Let's write the total output of the simulation results to the variable result. Let's select separate variables for the input and output of the nonlinear part of the system, and plot the graph using the function plot:

In [ ]:
result = engee.run(mdlname);
x = collect(result["The sine wave generator.1"]);
y = collect(result["Saturation.1"]);
plot(x.time,x.value,lw=2,label="Entrance")
plot!(y.time,y.value,lw=2,label="Exit")
Out[0]:

Running the simulation in a loop

We will change the parameters of the signal source block in the loop and run simulations programmatically. The parameters of the amplitude and frequency of the sine wave will vary. The result will be written to the outmatrix variable.:

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*"/Sinusoid Generator", "Amplitude" => ampvec[i])
    engee.set_param!(mdlname*"/Sinusoid Generator", "Frequency" => freqvec[i])
    tempresult = engee.run(mdlname);
    tempout = collect(tempresult["Saturation.1"]);
    outmatrix[:,i] = tempout.value;
end

We will display the resulting output signals on one axis with the function plot:

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

And also we will construct the matrix in 3D by the function surface:

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

Conclusion

In this interactive script, we have reviewed the basic principles of automated model creation and block parameter settings, as well as the possibility of running dynamic simulations in a loop with parameter changes.

In [ ]:
engee.close_all()