Engee documentation
Notebook

Converting MATLAB Simulink model to Engee model

Introduction

In this example, we will look at the process of automatically transferring user work from MATLAB Simulink to Engee, and compare the result of the transfer by simulating the original and the resulting models.

Obtaining a script for building the model

The first step in transferring a model from Simulink is to automatically get the script to build the Engee model using command control. Let's start by defining the variables for the files in this example:

In [ ]:
путь_примера = "$(@__DIR__)"                                # Путь к папке примера
имя_модели = "alphabetafilter"                              # Имя моделей
модельSLX = путь_примера*"/slx/"*имя_модели*".slx";         # Путь к исходной модели

mkdir(joinpath(путь_примера,"engee"));                      # Создаём папку для результирующей модели
скриптJL = путь_примера*"/engee/convert_script.jl";         # Путь к результирующему скрипту 
модельENGEE = путь_примера*"/engee/"*имя_модели*".engee";   # Путь к результирующей модели 

The MATLAB Simulink model we use in this example is alphabetafilter.slx from the integrating C code into the Engee model example.

Now let's use the programme control function engee.convert_model(). This function first defines the contents of the source model - subsystems, blocks, parameters, connections of blocks and subsystems. Then, based on the obtained data, it creates a script .jl with program control commands to build a new model .engee.

In [ ]:
engee.convert_model(модельSLX, скриптJL);           # Получение скрипта .jl для автоматического создания модели Engee
[ Info: Generated conversion script: /user/start/examples/project_management/slx_to_engee_conversion/engee/convert_script.jl

⚠️ When converting models, it is worth considering that in the current release of Engee:

In [ ]:
engee.version()
Out[0]:
"25.1.0"

conversion is supported for blocks supported by the code generator. Conversion support for all blocks in the Engee library will also be implemented in the future.

The content of the resulting script is given below. The following functions are used in the code to automatically build the .engee model:

Additionally, the programme control can be found in related example.

. Resulting code

model = engee.create("alphabetafilter")

engee.add_block("/Basic/Ports & Subsystems/In1", "alphabetafilter/processNoiseVariance") engee.set_param!("alphabetafilter/processNoiseVariance", "SignalType"=>"real")
engee.add_block("/Basic/Ports & Subsystems/In1", "alphabetafilter/measurementNoiseVariance") engee.set_param!("alphabetafilter/measurementNoiseVariance", "SignalType"=>"real")
engee.add_block("/Basic/Ports & Subsystems/In1", "alphabetafilter/y") engee.set_param!("alphabetafilter/y", "SignalType"=>"real")
engee.add_block("/Basic/Ports & Subsystems/Subsystem", "alphabetafilter/determineAlphaBeta")
engee.delete_contents("alphabetafilter/determineAlphaBeta")
engee.add_block("/Basic/Ports & Subsystems/In1", "alphabetafilter/determineAlphaBeta/processNoiseVariance") engee.set_param!("alphabetafilter/determineAlphaBeta/processNoiseVariance", "SignalType"=>"real")
engee.add_block("/Basic/Ports & Subsystems/In1", "alphabetafilter/determineAlphaBeta/measurementNoiseVariance") engee.set_param!("alphabetafilter/determineAlphaBeta/measurementNoiseVariance", "SignalType"=>"real")
engee.add_block("/Basic/Math Operations/Add", "alphabetafilter/determineAlphaBeta/Add")
engee.add_block("/Basic/Math Operations/Add", "alphabetafilter/determineAlphaBeta/Add1") engee.set_param!("alphabetafilter/determineAlphaBeta/Add1", "Inputs"=>"+-")
engee.add_block("/Basic/Math Operations/Add", "alphabetafilter/determineAlphaBeta/Add2") engee.set_param!("alphabetafilter/determineAlphaBeta/Add2", "Inputs"=>"+-")
engee.add_block("/Basic/Math Operations/Bias", "alphabetafilter/determineAlphaBeta/Bias") engee.set_param!("alphabetafilter/determineAlphaBeta/Bias", "Bias"=>"4")
engee.add_block("/Basic/Math Operations/Bias", "alphabetafilter/determineAlphaBeta/Bias1") engee.set_param!("alphabetafilter/determineAlphaBeta/Bias1", "Bias"=>"-1")
engee.add_block("/Basic/Math Operations/Bias", "alphabetafilter/determineAlphaBeta/Bias2") engee.set_param!("alphabetafilter/determineAlphaBeta/Bias2", "Bias"=>"-2")
engee.add_block("/Basic/Math Operations/Bias", "alphabetafilter/determineAlphaBeta/Bias3") engee.set_param!("alphabetafilter/determineAlphaBeta/Bias3", "Bias"=>"-1")
engee.add_block("/Basic/Sources/Constant", "alphabetafilter/determineAlphaBeta/Constant") engee.set_param!("alphabetafilter/determineAlphaBeta/Constant", "Value"=>"dt") engee.set_param!("alphabetafilter/determineAlphaBeta/Constant", "SampleTime"=>"0.0")
engee.add_block("/Basic/Math Operations/Gain", "alphabetafilter/determineAlphaBeta/Gain") engee.set_param!("alphabetafilter/determineAlphaBeta/Gain", "Gain"=>"8")
engee.add_block("/Basic/Math Operations/Gain", "alphabetafilter/determineAlphaBeta/Gain1") engee.set_param!("alphabetafilter/determineAlphaBeta/Gain1", "Gain"=>"1/4")
engee.add_block("/Basic/Math Operations/Gain", "alphabetafilter/determineAlphaBeta/Gain2") engee.set_param!("alphabetafilter/determineAlphaBeta/Gain2", "Gain"=>"-1")
engee.add_block("/Basic/Math Operations/Gain", "alphabetafilter/determineAlphaBeta/Gain3") engee.set_param!("alphabetafilter/determineAlphaBeta/Gain3", "Gain"=>"-1")
engee.add_block("/Basic/Math Operations/Gain", "alphabetafilter/determineAlphaBeta/Gain4") engee.set_param!("alphabetafilter/determineAlphaBeta/Gain4", "Gain"=>"2")
engee.add_block("/Basic/Math Operations/Gain", "alphabetafilter/determineAlphaBeta/Gain5") engee.set_param!("alphabetafilter/determineAlphaBeta/Gain5", "Gain"=>"-1")
engee.add_block("/Basic/Math Operations/Gain", "alphabetafilter/determineAlphaBeta/Gain6") engee.set_param!("alphabetafilter/determineAlphaBeta/Gain6", "Gain"=>"4")
engee.add_block("/Basic/Math Operations/Math Function", "alphabetafilter/determineAlphaBeta/Math Function") engee.set_param!("alphabetafilter/determineAlphaBeta/Math Function", "Operator"=>"square")
engee.add_block("/Basic/Math Operations/Math Function", "alphabetafilter/determineAlphaBeta/Math Function1") engee.set_param!("alphabetafilter/determineAlphaBeta/Math Function1", "Operator"=>"square")
engee.add_block("/Basic/Math Operations/Math Function", "alphabetafilter/determineAlphaBeta/Math Function2") engee.set_param!("alphabetafilter/determineAlphaBeta/Math Function2", "Operator"=>"square")
engee.add_block("/Basic/Math Operations/Math Function", "alphabetafilter/determineAlphaBeta/Math Function3") engee.set_param!("alphabetafilter/determineAlphaBeta/Math Function3", "Operator"=>"reciprocal")
engee.add_block("/Basic/Math Operations/Product", "alphabetafilter/determineAlphaBeta/Product") engee.set_param!("alphabetafilter/determineAlphaBeta/Product", "Inputs"=>"**")
engee.add_block("/Basic/Math Operations/Product", "alphabetafilter/determineAlphaBeta/Product1") engee.set_param!("alphabetafilter/determineAlphaBeta/Product1", "Inputs"=>"**")
engee.add_block("/Basic/Math Operations/Sqrt", "alphabetafilter/determineAlphaBeta/Sqrt")
engee.add_block("/Basic/Math Operations/Sqrt", "alphabetafilter/determineAlphaBeta/Sqrt1")
engee.add_block("/Basic/Ports & Subsystems/Out1", "alphabetafilter/determineAlphaBeta/alpha") engee.set_param!("alphabetafilter/determineAlphaBeta/alpha", "InitialOutput"=>"0")
engee.add_block("/Basic/Ports & Subsystems/Out1", "alphabetafilter/determineAlphaBeta/beta") engee.set_param!("alphabetafilter/determineAlphaBeta/beta", "InitialOutput"=>"0")
engee.add_line("alphabetafilter/determineAlphaBeta", "Add/1", "Sqrt/1") engee.add_line("alphabetafilter/determineAlphaBeta", "Math Function2/1", "Bias1/1") engee.add_line("alphabetafilter/determineAlphaBeta", "Gain1/1", "Math Function2/1") engee.add_line("alphabetafilter/determineAlphaBeta", "Sqrt/1", "Add1/2") engee.add_line("alphabetafilter/determineAlphaBeta", "Bias/1", "Add1/1") engee.add_line("alphabetafilter/determineAlphaBeta", "Bias1/1", "Gain2/1") engee.add_line("alphabetafilter/determineAlphaBeta", "Add2/1", "beta/1") engee.add_line("alphabetafilter/determineAlphaBeta", "Math Function/1", "Product/1") engee.add_line("alphabetafilter/determineAlphaBeta", "Gain5/1", "Sqrt1/1") engee.add_line("alphabetafilter/determineAlphaBeta", "Add1/1", "Gain1/1") engee.add_line("alphabetafilter/determineAlphaBeta", "Bias3/1", "Gain5/1") engee.add_line("alphabetafilter/determineAlphaBeta", "Product1/1", "Math Function1/1") engee.add_line("alphabetafilter/determineAlphaBeta", "Product1/1", "Gain/1") engee.add_line("alphabetafilter/determineAlphaBeta", "Product1/1", "Bias/1") engee.add_line("alphabetafilter/determineAlphaBeta", "Bias2/1", "Gain3/1") engee.add_line("alphabetafilter/determineAlphaBeta", "Product/1", "Product1/1") engee.add_line("alphabetafilter/determineAlphaBeta", "Gain/1", "Add/2") engee.add_line("alphabetafilter/determineAlphaBeta", "Sqrt1/1", "Gain6/1") engee.add_line("alphabetafilter/determineAlphaBeta", "Gain2/1", "alpha/1") engee.add_line("alphabetafilter/determineAlphaBeta", "Gain2/1", "Bias2/1") engee.add_line("alphabetafilter/determineAlphaBeta", "Gain2/1", "Bias3/1") engee.add_line("alphabetafilter/determineAlphaBeta", "Gain3/1", "Gain4/1") engee.add_line("alphabetafilter/determineAlphaBeta", "Gain6/1", "Add2/2") engee.add_line("alphabetafilter/determineAlphaBeta", "Math Function1/1", "Add/1") engee.add_line("alphabetafilter/determineAlphaBeta", "Gain4/1", "Add2/1") engee.add_line("alphabetafilter/determineAlphaBeta", "Constant/1", "Math Function/1") engee.add_line("alphabetafilter/determineAlphaBeta", "measurementNoiseVariance/1", "Math Function3/1") engee.add_line("alphabetafilter/determineAlphaBeta", "processNoiseVariance/1", "Product/2") engee.add_line("alphabetafilter/determineAlphaBeta", "Math Function3/1", "Product1/2")
engee.add_block("/Basic/Ports & Subsystems/Subsystem", "alphabetafilter/filterInputSignal")
engee.delete_contents("alphabetafilter/filterInputSignal")
engee.add_block("/Basic/Ports & Subsystems/In1", "alphabetafilter/filterInputSignal/alpha") engee.set_param!("alphabetafilter/filterInputSignal/alpha", "SignalType"=>"real")
engee.add_block("/Basic/Ports & Subsystems/In1", "alphabetafilter/filterInputSignal/beta") engee.set_param!("alphabetafilter/filterInputSignal/beta", "SignalType"=>"real")
engee.add_block("/Basic/Ports & Subsystems/In1", "alphabetafilter/filterInputSignal/y") engee.set_param!("alphabetafilter/filterInputSignal/y", "SignalType"=>"real")
engee.add_block("/Basic/Math Operations/Add", "alphabetafilter/filterInputSignal/Add")
engee.add_block("/Basic/Math Operations/Add", "alphabetafilter/filterInputSignal/Add1") engee.set_param!("alphabetafilter/filterInputSignal/Add1", "Inputs"=>"+-")
engee.add_block("/Basic/Math Operations/Add", "alphabetafilter/filterInputSignal/Add2")
engee.add_block("/Basic/Math Operations/Add", "alphabetafilter/filterInputSignal/Add3")
engee.add_block("/Basic/Math Operations/Gain", "alphabetafilter/filterInputSignal/Gain") engee.set_param!("alphabetafilter/filterInputSignal/Gain", "Gain"=>"dt")
engee.add_block("/Basic/Math Operations/Gain", "alphabetafilter/filterInputSignal/Gain1") engee.set_param!("alphabetafilter/filterInputSignal/Gain1", "Gain"=>"1/dt")
engee.add_block("/Basic/Math Operations/Product", "alphabetafilter/filterInputSignal/Product") engee.set_param!("alphabetafilter/filterInputSignal/Product", "Inputs"=>"**")
engee.add_block("/Basic/Math Operations/Product", "alphabetafilter/filterInputSignal/Product1") engee.set_param!("alphabetafilter/filterInputSignal/Product1", "Inputs"=>"**")
engee.add_block("/Basic/Discrete/Unit Delay", "alphabetafilter/filterInputSignal/Unit Delay") engee.set_param!("alphabetafilter/filterInputSignal/Unit Delay", "InitialCondition"=>"0") engee.set_param!("alphabetafilter/filterInputSignal/Unit Delay", "SampleTime"=>"-1")
engee.add_block("/Basic/Discrete/Unit Delay", "alphabetafilter/filterInputSignal/Unit Delay1") engee.set_param!("alphabetafilter/filterInputSignal/Unit Delay1", "InitialCondition"=>"0") engee.set_param!("alphabetafilter/filterInputSignal/Unit Delay1", "SampleTime"=>"-1")
engee.add_block("/Basic/Ports & Subsystems/Out1", "alphabetafilter/filterInputSignal/x") engee.set_param!("alphabetafilter/filterInputSignal/x", "InitialOutput"=>"0")
engee.add_line("alphabetafilter/filterInputSignal", "Add1/1", "Product/2") engee.add_line("alphabetafilter/filterInputSignal", "Add1/1", "Product1/1") engee.add_line("alphabetafilter/filterInputSignal", "Unit Delay/1", "Add/1") engee.add_line("alphabetafilter/filterInputSignal", "Add3/1", "Unit Delay1/1") engee.add_line("alphabetafilter/filterInputSignal", "Unit Delay1/1", "Add3/2") engee.add_line("alphabetafilter/filterInputSignal", "Unit Delay1/1", "Gain/1") engee.add_line("alphabetafilter/filterInputSignal", "y/1", "Add1/1") engee.add_line("alphabetafilter/filterInputSignal", "Product/1", "Add2/2") engee.add_line("alphabetafilter/filterInputSignal", "Add2/1", "Unit Delay/1") engee.add_line("alphabetafilter/filterInputSignal", "Add2/1", "x/1") engee.add_line("alphabetafilter/filterInputSignal", "Gain1/1", "Add3/1") engee.add_line("alphabetafilter/filterInputSignal", "Product1/1", "Gain1/1") engee.add_line("alphabetafilter/filterInputSignal", "alpha/1", "Product/1") engee.add_line("alphabetafilter/filterInputSignal", "Gain/1", "Add/2") engee.add_line("alphabetafilter/filterInputSignal", "Add/1", "Add2/1") engee.add_line("alphabetafilter/filterInputSignal", "Add/1", "Add1/2") engee.add_line("alphabetafilter/filterInputSignal", "beta/1", "Product1/2")
engee.add_block("/Basic/Ports & Subsystems/Out1", "alphabetafilter/x") engee.set_param!("alphabetafilter/x", "InitialOutput"=>"0")
engee.add_line("alphabetafilter", "measurementNoiseVariance/1", "determineAlphaBeta/2") engee.add_line("alphabetafilter", "processNoiseVariance/1", "determineAlphaBeta/1") engee.add_line("alphabetafilter", "determineAlphaBeta/1", "filterInputSignal/1") engee.add_line("alphabetafilter", "determineAlphaBeta/2", "filterInputSignal/2") engee.add_line("alphabetafilter", "y/1", "filterInputSignal/3") engee.add_line("alphabetafilter", "filterInputSignal/1", "x/1")
engee.save(model, "alphabetafilter.engee") engee.close() end

Building the Engee model

The second and final step of transferring the Simulink model to the Engee model is to reproduce the resulting script:

In [ ]:
cd(joinpath(путь_примера,"engee"))        # Переходим в папку примера – в ней будет располагаться модель .engee
include(скриптJL)                         # Запускаем выполнение скрипта .jl для автоматического создания модели .engee

As a result of the previous cell, the required model file will appear in the folder of the current example .engee. The obtained model is ready for use.

Using the engee.load() and engee.open() functions of the programme control we can make sure that the built model with subsystems are opened and therefore they are created correctly.

In [ ]:
# Функция для проверки модели и подсистем на открытие
function model_check(name::String, path::String, subsystem::String, delay::Int)     # Функция получает имя и путь модели, имя подсистемы, время ожидания
    model = engee.load(path; sync_gui=true)                                         # Загружаем модель
    sleep(delay)                                                                        # Ожидаем завершения синхронизации GUI
    engee.open(joinpath(name,subsystem); sync_gui=true)                             # Открываем подсистему 
    sleep(delay)                                                                        # Ожидаем завершения синхронизации GUI
    engee.save(model, name*".engee"; force=true, sync_gui=true)                     # Обновляем модель
    sleep(delay)                                                                        # Ожидаем завершения синхронизации GUI
                                                                                    # Закрываем модель
    try
        engee.close(model;sync_gui=true)
    catch e
        engee.close_all(;sync_gui=true)
    end
    sleep(delay)                                                                        # Ожидаем завершения синхронизации GUI
    return nothing                                                                  # Функция ничего не возвращает
end;

Let's check if the model and subsystems are created - let's open the subsystems one by one. It takes some time for the cell execution to synchronise the graphical user interface (GUI).

In [ ]:
подсистемы = ["filterInputSignal", "determineAlphaBeta"]        # Вектор с именами открываемых подсистем

for i in подсистемы                                             # Цикл по вектору
    model_check(имя_модели, модельENGEE, i, 5)                  # Циклический вызов функции проверки модели и подсистем
                                                                # время ожидания = 3 [сек]. При медленной синхронизации GUI
                                                                # рекомендуется увеличить время ожидания
end

During cell execution, the model and subsystem tabs are opened and closed in the Engee modelling environment. You must wait for all model and GUI control commands to complete.

Next, let's proceed to verification of the automatically built model .engee.

Verification of the obtained model

Let's use the method described in the example C code integration.

The initial data for verification are the results of the Simulink model. To obtain the results, let's generate code from it using Simulink Embedded Coder.

In [ ]:
# Загружаем и устанавливаем библиотеку MATLAB, если она ещё не установлена
import Pkg; Pkg.add("MATLAB")
   Resolving package versions...
  No Changes to `~/.project/Project.toml`
  No Changes to `~/.project/Manifest.toml`
In [ ]:
cgModel = модельSLX                                     # Путь модели Simulink
cgPath = mkdir(joinpath(путь_примера,"slx","cg"));      # Создаём директорию для результатов генерации кода из модели Simulink

using MATLAB                                            # Подключаем библиотеку MATLAB

mat"""                                                  % Вставка кода на языке MATLAB
model = load_system($cgModel);                              % Загружаем модель Simulink в память 
path = $cgPath;                                             % Сохраняем путь к папке генерации кода

set_param(0, 'CacheFolder', path)                           % Определяем путь к папке кэша моделирования
set_param(0, 'CodeGenFolder', path)                         % Определяем путь к папке генерации кода

slbuild(model)                                              % Генерируем код из исходной модели Simulink

set_param(0, 'CacheFolder', '')                             % Сбрасываем путь к папке кэша моделирования
set_param(0, 'CodeGenFolder', '')                           % Сбрасываем путь к папке генерации кода
"""                                                     # Конец вставки кода
>> >> >> >> Model 'alphabetafilter' was exported from R2024b to R2023a. To find blocks that were removed during the export operation, <a href="matlab:slexportprevious.utils.displayReplacedBlocks('alphabetafilter')">click here</a>. Save the model to remove this notification.
>> >> >> >> >> >> ### Starting build procedure for: alphabetafilter
### Generating code and artifacts to 'Model specific' folder structure
### Generating code into build folder: /user/start/examples/project_management/slx_to_engee_conversion/slx/cg/alphabetafilter_ert_rtw
### Invoking Target Language Compiler on alphabetafilter.rtw
### Using System Target File: /matlab/rtw/c/ert/ert.tlc
### Loading TLC function libraries
.......
### Generating TLC interface API for custom data
.
### Initial pass through model to cache user defined code
### Caching model source code
....................................
### Writing header file alphabetafilter_types.h
### Writing header file alphabetafilter.h
### Writing header file rtwtypes.h
### Writing source file alphabetafilter.c
### Writing header file alphabetafilter_private.h
.
### Writing source file alphabetafilter_data.c
### Writing source file ert_main.c
### TLC code generation complete (took 13.524s).
[Warning: P-code file /matlab/toolbox/coder/simulinkcoder_core/addStandardInfo.p
is older than source code file
/matlab/toolbox/coder/simulinkcoder_core/addStandardInfo.m.
/matlab/toolbox/coder/simulinkcoder_core/addStandardInfo.p may be obsolete and
may need to be regenerated.
Type "help pcode" for information about generating P-code.] 
### Saving binary information cache.
### Using toolchain: GNU gcc/g++ | gmake (64-bit Linux)
### Creating '/user/start/examples/project_management/slx_to_engee_conversion/slx/cg/alphabetafilter_ert_rtw/alphabetafilter.mk' ...
### Building 'alphabetafilter': "/matlab/bin/glnxa64/gmake"  -f alphabetafilter.mk all
gcc -c -fwrapv -fPIC -O0 -msse2 -DCLASSIC_INTERFACE=0 -DALLOCATIONFCN=0 -DTERMFCN=1 -DONESTEPFCN=1 -DMAT_FILE=0 -DMULTI_INSTANCE_CODE=0 -DINTEGER_CODE=0 -DMT=0  -DTID01EQ=0 -DMODEL=alphabetafilter -DNUMST=1 -DNCSTATES=0 -DHAVESTDIO -DMODEL_HAS_DYNAMICALLY_LOADED_SFCNS=0 -I/user/start/examples/project_management/slx_to_engee_conversion/slx/cg -I/user/start/examples/project_management/slx_to_engee_conversion/slx/cg/alphabetafilter_ert_rtw -I/matlab/extern/include -I/matlab/simulink/include -I/matlab/rtw/c/src -I/matlab/rtw/c/src/ext_mode/common -I/matlab/rtw/c/ert -o "alphabetafilter.o" "/user/start/examples/project_management/slx_to_engee_conversion/slx/cg/alphabetafilter_ert_rtw/alphabetafilter.c"
gcc -c -fwrapv -fPIC -O0 -msse2 -DCLASSIC_INTERFACE=0 -DALLOCATIONFCN=0 -DTERMFCN=1 -DONESTEPFCN=1 -DMAT_FILE=0 -DMULTI_INSTANCE_CODE=0 -DINTEGER_CODE=0 -DMT=0  -DTID01EQ=0 -DMODEL=alphabetafilter -DNUMST=1 -DNCSTATES=0 -DHAVESTDIO -DMODEL_HAS_DYNAMICALLY_LOADED_SFCNS=0 -I/user/start/examples/project_management/slx_to_engee_conversion/slx/cg -I/user/start/examples/project_management/slx_to_engee_conversion/slx/cg/alphabetafilter_ert_rtw -I/matlab/extern/include -I/matlab/simulink/include -I/matlab/rtw/c/src -I/matlab/rtw/c/src/ext_mode/common -I/matlab/rtw/c/ert -o "alphabetafilter_data.o" "/user/start/examples/project_management/slx_to_engee_conversion/slx/cg/alphabetafilter_ert_rtw/alphabetafilter_data.c"
gcc -c -fwrapv -fPIC -O0 -msse2 -DCLASSIC_INTERFACE=0 -DALLOCATIONFCN=0 -DTERMFCN=1 -DONESTEPFCN=1 -DMAT_FILE=0 -DMULTI_INSTANCE_CODE=0 -DINTEGER_CODE=0 -DMT=0  -DTID01EQ=0 -DMODEL=alphabetafilter -DNUMST=1 -DNCSTATES=0 -DHAVESTDIO -DMODEL_HAS_DYNAMICALLY_LOADED_SFCNS=0 -I/user/start/examples/project_management/slx_to_engee_conversion/slx/cg -I/user/start/examples/project_management/slx_to_engee_conversion/slx/cg/alphabetafilter_ert_rtw -I/matlab/extern/include -I/matlab/simulink/include -I/matlab/rtw/c/src -I/matlab/rtw/c/src/ext_mode/common -I/matlab/rtw/c/ert -o "ert_main.o" "/user/start/examples/project_management/slx_to_engee_conversion/slx/cg/alphabetafilter_ert_rtw/ert_main.c"
### Creating standalone executable ../alphabetafilter ...
g++  -o ../alphabetafilter alphabetafilter.o alphabetafilter_data.o ert_main.o  
### Created: ../alphabetafilter
### Successfully generated all binary outputs.
gmake: Nothing to be done for `all'.
### Successful completion of build procedure for: alphabetafilter
### Simulink cache artifacts for 'alphabetafilter' were created in '/user/start/examples/project_management/slx_to_engee_conversion/slx/cg/alphabetafilter.slxc'.

Build Summary

Top model targets built:

Model            Action                        Rebuild Reason                                    
=================================================================================================
alphabetafilter  Code generated and compiled.  Code generation information file does not exist.  

1 of 1 models built (0 models already up to date)
Build duration: 0h 0m 39.355s

The model in which the generated code from the Simulink model is embedded using the C Function block is test_cg_simulink.engee. The necessary paths to the C files are already specified in the block C Function.
Let's load, execute and close this model.

In [ ]:
тест_моделиSLX = engee.load(joinpath(путь_примера, "test_cg_simulink.engee"), force = true);    # Загружаем модель для сбора исходных данных верификации
результаты_моделиSLX = engee.run(тест_моделиSLX);                                               # Выполняем модель и сохраняем исходные данные
In [ ]:
engee.close(тест_моделиSLX, force = true);    

For clarity, let's plot the signals obtained as a result of modelling:

In [ ]:
# Передадим результаты моделирования в отдельные переменные:
noisy_t_slx = результаты_моделиSLX["noisy"].time;
noisy_v_slx = результаты_моделиSLX["noisy"].value;
filtered_t_slx = результаты_моделиSLX["filtered"].time;
filtered_v_slx = результаты_моделиSLX["filtered"].value;

plot(noisy_t_slx, noisy_v_slx, label = "Исходный сигнал")                   # Строим график зашумленного сигнала
plot!(filtered_t_slx, filtered_v_slx, label = "Отфильтрованный сигнал")     # Строим график отфильтрованного сигнала (при помощи кода, сгенерированного из модели Simulink)
plot!(legend = :bottomright)                                                # Расположение легенды

title!("Результаты работы исходной модели Simulink")                        # Заголовок
xlabel!("Время, [с]")                                                       # Подпись оси X
ylabel!("Амплитуда")                                                        # Подпись оси Y
Out[0]:

Modelling of the obtained Engee model

Now let's move on to modelling and getting results from the Engee model built using the automatically generated script.
Define the adjustable parameters of the model (the same values as in the Simulink model):

In [ ]:
# Настраиваемые параметры модели:
dt = 0.01;
Gain = 1/dt;

Generate C code from the automatically built Engee model:

In [ ]:
engee.generate_code(модельENGEE, путь_примера*"/engee/code")        # Автоматическая генерация кода Си из модели Engee
[ Info: Generated code and artifacts: /user/start/examples/project_management/slx_to_engee_conversion/engee/code

Identical to the previous model, which also uses a block to C Function the generated code from the Engee model is embedded - test_cg_engee.engee. The necessary paths to the C files are already specified in the block C Function.
Let's load, execute and close this model.

In [ ]:
тест_моделиENGEE = engee.load(joinpath(путь_примера, "test_cg_engee.engee"), force = true);     # Загружаем модель для сбора данных верификации модели Engee
результаты_моделиENGEE = engee.run(тест_моделиENGEE);                                           # Выполняем модель и сохраняем исходные данные
In [ ]:
engee.close(тест_моделиENGEE, force = true);   

For clarity, let's plot the signals obtained as a result of modelling:

In [ ]:
# Передадим результаты моделирования в отдельные переменные:
noisy_t_engee = результаты_моделиENGEE["noisy"].time;
noisy_v_engee = результаты_моделиENGEE["noisy"].value;
filtered_t_engee = результаты_моделиENGEE["filtered"].time;
filtered_v_engee = результаты_моделиENGEE["filtered"].value;

plot(noisy_t_engee, noisy_v_engee, label = "Исходный сигнал")                   # Строим график зашумленного сигнала
plot!(filtered_t_engee, filtered_v_engee, label = "Отфильтрованный сигнал")     # Строим график отфильтрованного сигнала (при помощи кода, сгенерированного из модели Engee)
plot!(legend = :bottomright)                                                    # Расположение легенды

title!("Результаты работы построенной модели Engee")                            # Заголовок
xlabel!("Время, [с]")                                                           # Подпись оси X
ylabel!("Амплитуда")                                                            # Подпись оси Y
Out[0]:

Comparison of modelling results

The graphs allow us to confidently conclude that the results of model building in the two modelling environments under consideration are similar. Let us calculate the minimum and maximum values of absolute deviations of the simulation results for the Simulink model and the Engee model converted from it:

In [ ]:
# Вычисляем абсолютные отклонения величин смоделированных сигналов
Δ_noisy_v = noisy_v_slx .- noisy_v_engee;
Δ_filtered_v = filtered_v_slx .- filtered_v_engee;

println("""Абсолютные отклонения величин сигналов для построенной модели Engee от исходной модели Simulink:
 - зашумленный сигнал       минимум: $(minimum(Δ_noisy_v))    максимум: $(maximum(Δ_noisy_v))
 - отфильтрованный сигнал   минимум: $(minimum(Δ_filtered_v))    максимум: $(maximum(Δ_filtered_v))""")
Абсолютные отклонения величин сигналов для построенной модели Engee от исходной модели Simulink:
- зашумленный сигнал       минимум: 0.0    максимум: 0.0
- отфильтрованный сигнал   минимум: 0.0    максимум: 0.0

As can be seen from the graphical and analytical comparison, there are no deviations in the performance of the automatically generated Engee model compared to the performance of the original Simulink model.

Conclusions

In this example, we have examined the process of converting Simulink models to Engee models, verified the built model using automatic code generation. We also examined in detail the application of many of Engee's software control features. At the end of this experiment, we found that the converted Engee model is not different from the original Simulink model. The original model can be deleted as unnecessary and to avoid confusion:

In [ ]:
# rm(модельSLX; force=true); # При необходимости раскомментируйте строку

Blocks used in example