Генерация кода в Engee
Верификация кода
Под верификацией понимается генерация проверочной модели с блоком C Function, чьи результаты симуляции должны совпадать с результатами симуляции исходной модели при одинаковых входных данных.
Блок C Function можно создать автоматически для верификации сгенерированного кода. Для этого поставьте галочку Генерировать блок C Function в окне настроек модели:
При следующей генерации кода (через контекстное меню или команду engee.generate_code) в директории output_dir появится файл modelname_verification.jl (если директории не существует — она будет создана автоматически). Этот файл будет содержать скрипт с командами программного управления Engee, который можно выполнить в редакторе скриптов или в командной строке :
include("path/to/verification.jl")
Скрипт создаст модель Engee с именем modelname_verification.engee и блоком C Function, который использует сгенерированный код:
Практическая часть
Пример
Сгенерируем Си-код для подсистемы SubSystem модели sinewave.engee, которую вы построили в Разделе 1 этого курса. Модель выглядит следующим образом:
Подсистема SubSystem содержит блок Генератор синусоиды:
-
В окне настроек модели во вкладке Генерация кода поставим галочку Генерировать блок C Function.
-
После этого сгенерируем Си-код для подсистемы. Нажмем правой кнопкой мыши по подсистеме и в появившемся контекстном меню выберем пункт Сгенерировать код.
В результате в текущей папке появится папка sinewave_SubSystem_code, в которой будут находиться знакомые вам файлы main.c, sinewave_SubSystem.c, sinewave_SubSystem.h, а также файл sinewave_SubSystem_verification.jl, содержащий следующий скрипт на языке Julia:
# This is a verification script for the sinewave_SubSystem generated code.
# Run this code in order to create a verification model with a CFunction block inside that behaves like the original model.
# CFunction variables
start_code = """
sinewave_SubSystem_init();"""
output_code = """
sinewave_SubSystem_step();
Out1 = sinewave_SubSystem_Y.Out1;
"""
terminate_code = """
sinewave_SubSystem_term();"""
# Close
try engee.close("sinewave_SubSystem_verification";force=true) catch end
# Create
engee.create("sinewave_SubSystem_verification")
# Add Blocks
engee.add_block("/Basic/User-Defined Functions/C Function", "sinewave_SubSystem_verification/")
engee.add_block("/Basic/Ports & Subsystems/Out1", "sinewave_SubSystem_verification/Out1")
# Edit block parameters
engee.set_param!("sinewave_SubSystem_verification/C Function", "OutputCode" => output_code, "StartCode" => start_code, "TerminateCode" => terminate_code)
engee.set_param!("sinewave_SubSystem_verification/C Function", "Inputs" => 0)
engee.set_param!("sinewave_SubSystem_verification/C Function", "Outputs" => 1)
engee.set_param!("sinewave_SubSystem_verification/C Function", "SampleTime" => "0.01")
engee.set_param!("sinewave_SubSystem_verification/C Function", "Parameters" => 0)
engee.set_param!("sinewave_SubSystem_verification/C Function", "OutputPort1Label" => "Out1")
engee.set_param!("sinewave_SubSystem_verification/C Function", "OutputPort1VarName" => "Out1")
engee.set_param!("sinewave_SubSystem_verification/C Function", "OutputPort1Size" => "()")
engee.set_param!("sinewave_SubSystem_verification/C Function", "OutputPort1Type" => "double")
engee.set_param!("sinewave_SubSystem_verification/C Function", "SourceFiles" => "\"/user/start/Курсы/Генерация кода в Engee/sinewave_SubSystem_code/sinewave_SubSystem.c\"")
engee.set_param!("sinewave_SubSystem_verification/C Function", "IncludeDirectories" => "\"/user/start/Курсы/Генерация кода в Engee/sinewave_SubSystem_code/\"")
engee.set_param!("sinewave_SubSystem_verification/C Function", "Headers" => "\"stdint.h\" \"math.h\" \"sinewave_SubSystem.h\"")
# Edit model parameters
engee.set_param!("sinewave_SubSystem_verification", "FixedStep" => 0.01)
engee.set_param!("sinewave_SubSystem_verification", "StartTime" => 0.0)
engee.set_param!("sinewave_SubSystem_verification", "StopTime" => 10)
engee.set_param!("sinewave_SubSystem_verification", "EnableMultiTasking" => false)
# Add lines
engee.add_line("sinewave_SubSystem_verification", "C Function/1", "Out1/1")
# Save
engee.save("sinewave_SubSystem_verification.engee"; force=true)
-
Откроем скрипт
sinewave_SubSystem_verification.jlв редакторе скриптов и запустим его, нажав кнопку Выполнить
. В результате выполнения скрипта в той же папке появится файл со сгенерированной моделью sinewave_SubSystem_verification.engee. -
Откроем эту модель:
Залогируем выходной сигнал блока C Function, запустим симуляцию модели и построим график выходного сигнала:
Можно убедиться в том, что результаты симуляции этой модели полностью идентичны результатам симуляции исходной модели sinewave.engee. Следовательно, сгенерированный Си-код успешно прошел верификацию.
✏️Задание 1
Выполните верификацию кода, сгенерированного для подсистемы SubSystem модели two_sinewaves.engee, которую вы построили в Разделе 1 этого курса. Напомним, что подсистема SubSystem выполняет сложение двух синусоидальных сигналов с разными частотами:
-
Откройте модель
two_sinewaves.engee, залогируйте выходной сигнал подсистемы, запустите модель и постройте график выходного сигнала. -
В окне настроек модели во вкладке Генерация кода поставьте галочку Генерировать блок C Function.
-
Сгенерируйте Си-код для подсистемы SubSystem. В результате в текущей папке появится папка
two_sinewaves_SubSystem_code, в которой будут находиться файлыmain.c,two_sinewaves_SubSystem.c,two_sinewaves_SubSystem.h, а также файлtwo_sinewaves_SubSystem_verification.jl -
Откройте скрипт
two_sinewaves_SubSystem_verification.jlв редакторе скриптов и запустите его. В результате в той же папке появится файл со сгенерированной модельюtwo_sinewaves_SubSystem_verification.engee. -
Откройте эту модель, залогируйте выходной сигнал блока C Function, запустите модель и постройте график выходного сигнала. Убедитесь в том, что результаты симуляции обеих моделей идентичны.
Решение
Скрипт two_sinewaves_SubSystem_verification.jl:
# This is a verification script for the two_sinewaves_SubSystem generated code.
# Run this code in order to create a verification model with a CFunction block inside that behaves like the original model.
# CFunction variables
start_code = """
two_sinewaves_SubSystem_init();"""
output_code = """
two_sinewaves_SubSystem_step();
Out1 = two_sinewaves_SubSystem_Y.Out1;
"""
terminate_code = """
two_sinewaves_SubSystem_term();"""
# Close
try engee.close("two_sinewaves_SubSystem_verification";force=true) catch end
# Create
engee.create("two_sinewaves_SubSystem_verification")
# Add Blocks
engee.add_block("/Basic/User-Defined Functions/C Function", "two_sinewaves_SubSystem_verification/")
engee.add_block("/Basic/Ports & Subsystems/Out1", "two_sinewaves_SubSystem_verification/Out1")
# Edit block parameters
engee.set_param!("two_sinewaves_SubSystem_verification/C Function", "OutputCode" => output_code, "StartCode" => start_code, "TerminateCode" => terminate_code)
engee.set_param!("two_sinewaves_SubSystem_verification/C Function", "Inputs" => 0)
engee.set_param!("two_sinewaves_SubSystem_verification/C Function", "Outputs" => 1)
engee.set_param!("two_sinewaves_SubSystem_verification/C Function", "SampleTime" => "0.01")
engee.set_param!("two_sinewaves_SubSystem_verification/C Function", "Parameters" => 0)
engee.set_param!("two_sinewaves_SubSystem_verification/C Function", "OutputPort1Label" => "Out1")
engee.set_param!("two_sinewaves_SubSystem_verification/C Function", "OutputPort1VarName" => "Out1")
engee.set_param!("two_sinewaves_SubSystem_verification/C Function", "OutputPort1Size" => "()")
engee.set_param!("two_sinewaves_SubSystem_verification/C Function", "OutputPort1Type" => "double")
engee.set_param!("two_sinewaves_SubSystem_verification/C Function", "SourceFiles" => "\"/user/start/Курсы/Генерация кода в Engee/two_sinewaves_SubSystem_code/two_sinewaves_SubSystem.c\"")
engee.set_param!("two_sinewaves_SubSystem_verification/C Function", "IncludeDirectories" => "\"/user/start/Курсы/Генерация кода в Engee/two_sinewaves_SubSystem_code/\"")
engee.set_param!("two_sinewaves_SubSystem_verification/C Function", "Headers" => "\"stdint.h\" \"math.h\" \"two_sinewaves_SubSystem.h\"")
# Edit model parameters
engee.set_param!("two_sinewaves_SubSystem_verification", "FixedStep" => 0.01)
engee.set_param!("two_sinewaves_SubSystem_verification", "StartTime" => 0.0)
engee.set_param!("two_sinewaves_SubSystem_verification", "StopTime" => 10)
engee.set_param!("two_sinewaves_SubSystem_verification", "EnableMultiTasking" => false)
# Add lines
engee.add_line("two_sinewaves_SubSystem_verification", "C Function/1", "Out1/1")
# Save
engee.save("two_sinewaves_SubSystem_verification.engee"; force=true)
Сгенерированная модель two_sinewaves_SubSystem_verification.engee:
График выходного сигнала:
✏️Задание 2
Выполните верификацию кода, сгенерированного для модели lowpass_filter.engee (вы уже генерировали код для этой модели в Разделе 2):
-
Откройте модель
lowpass_filter.engee, находящуюся в папке данного курса, запустите модель и постройте на одной координатной плоскости графики зашумленного и сглаженного сигналов. -
В окне настроек модели во вкладке Генерация кода поставьте галочку Генерировать блок C Function.
-
Сгенерируйте Си-код для подсистемы SubSystem. В результате в текущей папке появится папка
lowpass_filter_SubSystem_code, в которой будут находиться файлыmain.c,lowpass_filter_SubSystem.c,lowpass_filter_SubSystem.h, а также файлlowpass_filter_SubSystem_verification.jl -
Откройте скрипт
lowpass_filter_SubSystem_verification.jlв редакторе скриптов и запустите его. В результате в той же папке появится файл со сгенерированной модельюlowpass_filter_SubSystem_verification.engee. -
Откройте эту модель и скопируйте в буфер обмена блок C Function.
-
Сохраните модель
lowpass_filter.engeeпод другим именем, например,lowpass_filter 2.engee. Удалите из этой модели подсистему SubSystem и вставьте на ее место из буфера обмена блок C Function. -
Залогируйте выходной сигнал блока C Function, запустите симуляцию модели и постройте на одной координатной плоскости графики зашумленного и сглаженного сигналов. Убедитесь в том, что результаты симуляции обеих моделей идентичны.
Решение
Скрипт lowpass_filter_SubSystem_verification.jl:
# This is a verification script for the lowpass_filter_SubSystem generated code.
# Run this code in order to create a verification model with a CFunction block inside that behaves like the original model.
# CFunction variables
start_code = """
lowpass_filter_SubSystem_init();"""
output_code = """
lowpass_filter_SubSystem_U.In1 = In1;
lowpass_filter_SubSystem_step();
Out1 = lowpass_filter_SubSystem_Y.Out1;
"""
terminate_code = """
lowpass_filter_SubSystem_term();"""
# Close
try engee.close("lowpass_filter_SubSystem_verification";force=true) catch end
# Create
engee.create("lowpass_filter_SubSystem_verification")
# Add Blocks
engee.add_block("/Basic/Ports & Subsystems/In1", "lowpass_filter_SubSystem_verification/In1")
engee.add_block("/Basic/User-Defined Functions/C Function", "lowpass_filter_SubSystem_verification/")
engee.add_block("/Basic/Ports & Subsystems/Out1", "lowpass_filter_SubSystem_verification/Out1")
# Edit block parameters
engee.set_param!("lowpass_filter_SubSystem_verification/In1", "PortDimensions" => "()")
engee.set_param!("lowpass_filter_SubSystem_verification/In1", "SignalType" => "real")
engee.set_param!("lowpass_filter_SubSystem_verification/In1", "OutDataTypeStr" => "Float64")
engee.set_param!("lowpass_filter_SubSystem_verification/C Function", "OutputCode" => output_code, "StartCode" => start_code, "TerminateCode" => terminate_code)
engee.set_param!("lowpass_filter_SubSystem_verification/C Function", "Inputs" => 1)
engee.set_param!("lowpass_filter_SubSystem_verification/C Function", "Outputs" => 1)
engee.set_param!("lowpass_filter_SubSystem_verification/C Function", "InputPort1Label" => "In1")
engee.set_param!("lowpass_filter_SubSystem_verification/C Function", "InputPort1VarName" => "In1")
engee.set_param!("lowpass_filter_SubSystem_verification/C Function", "InputPort1Size" => "()")
engee.set_param!("lowpass_filter_SubSystem_verification/C Function", "InputPort1Type" => "double")
engee.set_param!("lowpass_filter_SubSystem_verification/C Function", "SampleTime" => "0.01")
engee.set_param!("lowpass_filter_SubSystem_verification/C Function", "Parameters" => 0)
engee.set_param!("lowpass_filter_SubSystem_verification/C Function", "OutputPort1Label" => "Out1")
engee.set_param!("lowpass_filter_SubSystem_verification/C Function", "OutputPort1VarName" => "Out1")
engee.set_param!("lowpass_filter_SubSystem_verification/C Function", "OutputPort1Size" => "()")
engee.set_param!("lowpass_filter_SubSystem_verification/C Function", "OutputPort1Type" => "double")
engee.set_param!("lowpass_filter_SubSystem_verification/C Function", "SourceFiles" => "\"/user/start/Курсы/Генерация кода в Engee/lowpass_filter_SubSystem_code/lowpass_filter_SubSystem.c\"")
engee.set_param!("lowpass_filter_SubSystem_verification/C Function", "IncludeDirectories" => "\"/user/start/Курсы/Генерация кода в Engee/lowpass_filter_SubSystem_code/\"")
engee.set_param!("lowpass_filter_SubSystem_verification/C Function", "Headers" => "\"stdint.h\" \"math.h\" \"lowpass_filter_SubSystem.h\"")
# Edit model parameters
engee.set_param!("lowpass_filter_SubSystem_verification", "FixedStep" => 0.01)
engee.set_param!("lowpass_filter_SubSystem_verification", "StartTime" => 0.0)
engee.set_param!("lowpass_filter_SubSystem_verification", "StopTime" => 20)
engee.set_param!("lowpass_filter_SubSystem_verification", "EnableMultiTasking" => false)
# Add lines
engee.add_line("lowpass_filter_SubSystem_verification", "In1/1", "C Function/1")
engee.add_line("lowpass_filter_SubSystem_verification", "C Function/1", "Out1/1")
# Save
engee.save("lowpass_filter_SubSystem_verification.engee"; force=true)
Сгенерированная модель lowpass_filter_SubSystem_verification.engee:
Верификационная модель lowpass_filter 2.engee:
Графики результатов симуляции: