Engee documentation
Notebook

Three-phase sine wave generator

In this demo, we will look at ways to embed code generated from the Engee model subsystem.

Introduction

The purpose of this example is to develop a model of a three-phase sine wave generator. The input signals of the generator are the amplitude [V] and frequency [Hz] of the output signals: instantaneous phase voltages. The phase difference of the sinusoidal signals is equal to $- \frac{2 \cdot \pi}{3}$.

In the course of the example we will perform modelling of the algorithm, code generation, embedding and testing in Engee models, embedding and testing on the target device - Arduino-compatible platform.

Model description

The developed model sine_generator.engee represents the algorithm of a three-phase sine wave generator contained within the subsystem SinGen. The inputs of the subsystem are supplied with amplitude values Amp = 1.0 and frequency values Freq = 25.0. The output sinusoidal signals Sin_A, Sin_B and Sin_C are logged. Step of the model calculation is 0.001 sec.

image.png

The content of the subsystem SinGen is shown in the figure below.

image.png

This subsystem reproduces standard calculations using the following equations:

$$ Sin_A = Amplitude \cdot sin(2 \cdot \pi \cdot Frequency \cdot t + \varphi_A) = 1 \cdot sin(2 \cdot \pi \cdot 25 \cdot t), $$ $$ Sin_B = Amplitude \cdot sin(2 \cdot \pi \cdot Frequency \cdot t + \varphi_B) = 1 \cdot sin(2 \cdot \pi \cdot 25 \cdot t - \frac{2 \cdot \pi}{3}), $$ $$ Sin_C = Amplitude \cdot sin(2 \cdot \pi \cdot Frequency \cdot t + \varphi_C) = 1 \cdot sin(2 \cdot \pi \cdot 25 \cdot t - \frac{4 \cdot \pi}{3}). $$

Modelling results

Let's load and execute the described model:

In [ ]:
if "sine_generator" in [m.name for m in engee.get_all_models()]
    m = engee.open( "sine_generator" );
else
    m = engee.load( "$(@__DIR__)/sine_generator.engee" );
end

data = engee.run(m);

From the obtained model data we plot the output variables - instantaneous phase voltages SinGen.Sin_A, SinGen.Sin_B, SinGen.Sin_C.

In [ ]:
using Plots
plotlyjs()
plot(data["SinGen.Sin_A"].time, data["SinGen.Sin_A"].value,
    label="V_a", size=(900,300), lw=2, st=:step)
plot!(data["SinGen.Sin_B"].time, data["SinGen.Sin_B"].value,
    label="V_b", size=(900,300), lw=2, st=:step)
plot!(data["SinGen.Sin_C"].time, data["SinGen.Sin_C"].value,
    label="V_c", size=(900,300), lw=2, st=:step,
    legend=:topleft)
xlabel!("Время, сек")
ylabel!("Напряжение, В")
Out[0]:

The plots of output signals obtained as a result of modelling are three-phase sinusoidal voltages V_a, V_b, V_c with frequency 25 Hz, amplitude 1 V and phase shift $- \frac{2 \cdot \pi}{3}$.

Code generation

To embed the developed algorithm it is necessary to generate the code from the subsystem SinGen:

In [ ]:
engee.generate_code( "$(@__DIR__)/sine_generator.engee",
                     "$(@__DIR__)/sine_generator_SinGen_code";
                     subsystem_name="SinGen" )
[ Info: Generated code and artifacts: /user/start/examples/codegen/sine_generator/sine_generator_SinGen_code

As a result of executing the code generation command, the files main.c, sine_generator_SinGen.h and sine_generator_SinGen.c were created in the specified directory.

image.png

Now let's look at and test ways to embed the code generated from the model.

Embedding code into the Engee model

To test the generated code, we embed it into the Engee model sine_generator_test.engee. The input and output parameters of the algorithm are identical to those in the original model sine_generator.engee. However, the algorithm itself is implemented here on the basis of generated C files embedded in the block C Function.

image.png

Code embedding consists of the following. In the block C Function the locations of the generated files are specified, input and output variables are initialised, and the calculation functions generated from the model are called.

Contents of the tab </> OutputCode of the block C Function:

// engee-cfunction-start
//
// build source_files /user/start/examples/codegen/sine_generator/sine_generator_SinGen_code/sine_generator_SinGen.c
// build include_directories /user/start/examples/codegen/sine_generator/sine_generator/sine_generator_SinGen_code
// build library_directories
// build headers sine_generator_SinGen.h
// build defines
// build libraries
//
// Name Scope Label Type Size Port
// symbol A Input 'A' double 1 1
// symbol F Input 'F' double 1 2
// symbol Va Output 'Va' double 1 1
// symbol Vb Output 'Vb' double 1 2
// symbol Vc Output 'Vc' double 1 3
//
// engee-cfunction-end
//

// transfer frequency and amplitude values to the structure
sine_generator_SinGen_U.Frequency = F;
sine_generator_SinGen_U.Amplitude = A;

sine_generator_SinGen_step();

// transfer from the structure the values of instantaneous voltages by phases
Va = sine_generator_SinGen_Y.Sin_A;
Vb = sine_generator_SinGen_Y.Sin_B;
Vc = sine_generator_SinGen_Y.Sin_C;

Contents of tab </> StartCode of block C Function:

// call the initialisation function
sine_generator_SinGen_init();

Contents of the </> TerminateCode tab of the C Function block :

// call the termination function
sine_generator_SinGen_term();

Modelling embedded code

Let's load and execute the sine_generator_test.engee model to test the generated code:

In [ ]:
if "sine_generator_test" in [n.name for n in engee.get_all_models()]
    n = engee.open( "sine_generator_test" );
else
    n = engee.load( "$(@__DIR__)/sine_generator_test.engee" );
end

test = engee.run(m);

From the obtained model data, plot the output variables - instantaneous phase voltages SinGen.Sin_A, SinGen.Sin_B, SinGen.Sin_C.

In [ ]:
plot(test["SinGen.Sin_A"].time, test["SinGen.Sin_A"].value,
    label="V_a", size=(900,300), lw=2, st=:step)
plot!(test["SinGen.Sin_B"].time, test["SinGen.Sin_B"].value,
    label="V_b", size=(900,300), lw=2, st=:step)
plot!(test["SinGen.Sin_C"].time, test["SinGen.Sin_C"].value,
    label="V_c", size=(900,300), lw=2, st=:step,
    legend=:topleft)
xlabel!("Время, сек")
ylabel!("Напряжение, В")
Out[0]:

As can be seen from the obtained graphs, the resulting voltage signals in the model for testing also have a sinusoidal form with the specified frequency, amplitude and phase shift.

Let us also compare the results of modelling of sinusoidal signals of phase A for the original and test models:

In [ ]:
plot(data["SinGen.Sin_A"].time, data["SinGen.Sin_A"].value,
    label="V_a", size=(900,300), lw=4, st=:step)
plot!(test["SinGen.Sin_A"].time, test["SinGen.Sin_A"].value,
    label="V_a_test", size=(900,300), lw=2, st=:step,
    legend=:topleft)
xlabel!("Время, сек")
ylabel!("Напряжение, В")
Out[0]:

As can be seen from the above graphs, the simulation results of the initial model and the model for testing the code generation results completely coincide.

Embedding the code into the Arduino sketch

In order to test the developed algorithm on the target device, it is necessary to plug the generated files sine_generator_SinGen.c and sine_generator_SinGen.h into the user programme project.

For demonstration in this example the Iskra Neo controller from Amperka is used. Execution of the algorithm on the target device consists in the controller transmitting the values of the generated signals to the serial port. Displaying of the transmitted values will be done by Arduino IDE tools.

To embed the algorithm code, a sketch for the Arduino IDE sine_generator.ino has been previously developed, which is also attached to the folder of this demo. The contents of the sketch are functionally identical to the contents of the C Function block of the Engee test model, except for the functions of working with peripherals and the cycle of maintaining the calculation step. A detailed description of the sketch operation is given in the comments to the code.

Executing the code on Arduino

After successfully compiling and loading the sketch into the target device, let's open the "Serial Plotter" from the Arduino IDE toolbox. A screenshot of the plotter with the output signals is shown in the figure below.

image_2.png

It can be seen from the plotter plots that the resulting signals also have specified amplitude, frequency and phase shifts.

Conclusion

In this demo, a model of a three-phase sine wave generator with specified parameters such as amplitude, frequency, and phase shift was developed. The generator algorithm was debugged in the Engee model, then the resulting code generation files were tested by embedding them in the Engee model, and finally the generated C files were loaded into a custom sketch and tested on the target device.

Thus, using a simple example of a sine wave generator, we have looked at the possibilities of generating code from the Engee model.