Трёхфазный генератор синусоидальных сигналов
В этом демонстрационном примере мы рассмотрим способы встраивания кода, сгенерированного из подсистемы модели Engee.
Введение
Цель этого примера - разработать модель трёхфазного генератора синусоидальных сигналов. Входные сигналы генератора - амплитуда [В] и частота [Гц] выходных сигналов: мгновенных фазных напряжений. Разность фаз синусоидальных сигналов равна .
По ходу примера мы проведем моделирование алгоритма, генерацию кода, встраивание и проверку в модели Engee, встравивание и тестирование на целевом устройстве - Arduino-совместимой платформе.
Описание модели
Разработанная модель sine_generator.engee
представляет из себя алгоритм трёхфазного генератора синусоидальных сигналов, содержащегося внутри подсистемы SinGen
. На входы подсистемы подаются значения амплитуды Amp = 1.0
и частоты Freq = 25.0
. Выходные синусоидальные сигналы Sin_A
, Sin_B
и Sin_C
логгируются.
Шаг расчета модели - 0.001 сек.

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

Эта подсистема воспроизводит стандартные вычисления по следующим уравнениям:
Результаты моделирования
Загрузим и выполним описанную модель:
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
.
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!("Напряжение, В")
Полученные в результате моделирования графики выходных сигналов - трёхфазные синосоидальные напряжения V_a
, V_b
, V_c
с частотой 25 Гц, амплитудой 1 В и фазовым сдвигом .
Генерация кода
Для встраивания разработанного алгоритма необходимо сгенерировать код из подсистемы SinGen
:
engee.generate_code( "$(@__DIR__)/sine_generator.engee",
"$(@__DIR__)/sine_generator_SinGen_code";
subsystem_name="SinGen" )
В результате выполнения команды генерации кода в указанной директории были созданы файлы main.c
, sine_generator_SinGen.h
и sine_generator_SinGen.c
.

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

Встраивание кода заключается в следующем. В блоке 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
для тестирования сгенерированного кода:
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
.
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!("Напряжение, В")
Как видно из полученных графиков, результирующие сигналы напряжения в модели для тестирования также имеют синусоидальный вид с заданными частотой, амплитудой и сдвигом фаз.
Также сравним результаты моделирования синусоидальных сигналов фазы А для первоначальной и тестовой моделей:
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!("Напряжение, В")
Как видно из приведенных графиков, результаты моделирования первоначальной модели и модели для проверки результатов генерации кода полностью совпадают.
Встраивание кода в скетч 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. Скриншот плоттера с выведенными сигналами представлен на рисунке ниже.

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