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

Трёхфазный генератор синусоидальных сигналов

В этом демонстрационном примере мы рассмотрим способы встраивания кода, сгенерированного из подсистемы модели Engee.

Введение

Цель этого примера - разработать модель трёхфазного генератора синусоидальных сигналов. Входные сигналы генератора - амплитуда [В] и частота [Гц] выходных сигналов: мгновенных фазных напряжений. Разность фаз синусоидальных сигналов равна $- \frac{2 \cdot \pi}{3}$.

По ходу примера мы проведем моделирование алгоритма, генерацию кода, встраивание и проверку в модели Engee, встравивание и тестирование на целевом устройстве - Arduino-совместимой платформе.

Описание модели

Разработанная модель sine_generator.engee представляет из себя алгоритм трёхфазного генератора синусоидальных сигналов, содержащегося внутри подсистемы SinGen. На входы подсистемы подаются значения амплитуды Amp = 1.0 и частоты Freq = 25.0. Выходные синусоидальные сигналы Sin_A, Sin_B и Sin_C логгируются. Шаг расчета модели - 0.001 сек.

image.png

Содержимое подсистемы SinGen приведено на рисунке ниже.

image.png

Эта подсистема воспроизводит стандартные вычисления по следующим уравнениям:

$$ 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}). $$

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

Загрузим и выполним описанную модель:

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);

Из полученных данных модели построим графики выходных переменных - мгновенных напряжений фаз 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]:

Полученные в результате моделирования графики выходных сигналов - трёхфазные синосоидальные напряжения V_a, V_b, V_c с частотой 25 Гц, амплитудой 1 В и фазовым сдвигом $- \frac{2 \cdot \pi}{3}$.

Генерация кода

Для встраивания разработанного алгоритма необходимо сгенерировать код из подсистемы 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

В результате выполнения команды генерации кода в указанной директории были созданы файлы main.c, sine_generator_SinGen.h и sine_generator_SinGen.c.

image.png

Теперь рассмотрим и протестируем способы встраивания сгенерированного из модели кода.

Встраивание кода в модель Engee

Для проверки работы сгенерированного кода встроим его в модель Engee sine_generator_test.engee. Входные и выходные параметры алгоритма идентичны параметрам в первоначальной модели sine_generator.engee. Однако сам алгоритм здесь реализуется на базе сгенерированных файлов Си, встроенных в блок C Function.

image.png

Встраивание кода заключается в следующем. В блоке C Function указываются расположения сгенерированных файлов, инициализируются входные и выходные переменные, вызываются функции расчёта, сгенерированные из модели.

Содержимое вкладки </> OutputCode блока 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_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
//

//передача в структуру значений частоты и амплитуды
sine_generator_SinGen_U.Frequency = F;
sine_generator_SinGen_U.Amplitude = A;

sine_generator_SinGen_step();

// передача из структуры величин мгновенных напряжений по фазам
Va = sine_generator_SinGen_Y.Sin_A;
Vb = sine_generator_SinGen_Y.Sin_B;
Vc = sine_generator_SinGen_Y.Sin_C;

Содержимое вкладки </> StartCode блока C Function:

// вызов функции инициализации
sine_generator_SinGen_init();

Содержимое вкладки </> TerminateCode блока C Function:

// вызов функции терминации
sine_generator_SinGen_term();

Моделирование встроенного кода

Загрузим и выполним модель sine_generator_test.engee для тестирования сгенерированного кода:

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);

Из полученных данных модели построим графики выходных переменных - мгновенных напряжений фаз 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]:

Как видно из полученных графиков, результирующие сигналы напряжения в модели для тестирования также имеют синусоидальный вид с заданными частотой, амплитудой и сдвигом фаз.

Также сравним результаты моделирования синусоидальных сигналов фазы А для первоначальной и тестовой моделей:

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

Как видно из приведенных графиков, результаты моделирования первоначальной модели и модели для проверки результатов генерации кода полностью совпадают.

Встраивание кода в скетч Arduino

Для тестирования разработанного алгоритма на целевом устройстве необходимо подключить сгенерированные файлы sine_generator_SinGen.c и sine_generator_SinGen.h в проект пользовательской программы.

Для демонстрации в этом примере используется контроллер Iskra Neo от Amperka. Выполнение алгоритма на целевом устройстве заключается в передаче контроллером в последовательный порт значений сгенерированных сигналов. Отображение переданных значений будет осуществляться инструментами Arduino IDE.

Для встравивания кода алгоритма предварительно был разработан скетч для Arduino IDE sine_generator.ino, который также приложен в папку этого демонстрационного примера. Содержимое скетча функционально идентично содержимому блока C Function тестовой модели Engee, за исключением функций работы с периферией и цикла поддержания шага расчета. Подробное описание работы скетча дано в комментариях к коду.

Выполнение кода на Arduino

После успешной компиляции и загрузки скетча в целевое устройство откроем "Плоттер по последовательному соединению" из инструментария Arduino IDE. Скриншот плоттера с выведенными сигналами представлен на рисунке ниже.

image_2.png

По графикам плоттера видно, что результирующие сигналы также имеют заданные амплитуду, частоту и фазовые сдвиги.

Вывод

В этом демонстрационном примере была разработана модель трёхфазного генератора синусоидальных сигналов с заданными параметрами - амплитудой, частотой и фазовым сдвигом. Работа алгоритма генератора была отлажена в модели Engee, затем результирующие файлы генерации кода были протестированы путём встраивания в модель Engee, и в завершение сгенерированные файлы на языке Си были загружены в пользовательский скетч и протестированы на целевом устройстве.

Таким образом, на простом примере генератора синусоидальных сигналов мы рассмотрели возможности генерации кода из модели Engee.

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