Генератор кода производит алгоритмический код, как определено вашей моделью. Можно включать внешний (для примера, пользовательский или устаревший) код в модель с помощью методов, описанных в разделе «Выбор внешнего кода» Интегрирования Workflow.
Генератор кода также предоставляет интерфейс, который выполняет сгенерированный код модели. Интерфейс и код модели компилируются вместе, чтобы создать исполняемую программу. Следующий рисунок показывает объектно-ориентированное представление исполняемого файла высокого уровня.
Объектно-ориентированное представление программы в реальном времени
В целом концептуальный проект драйвера выполнения модели не меняется между быстрым прототипированием и встроенным стилем сгенерированного кода. В следующих разделах описывается выполнение модели для однозадачных и многозадачных окружений как для симуляции (не в реальном времени), так и для реального времени. Для большинства кода модели окружение многозадачности обеспечивает наиболее эффективное выполнение модели (то есть самую быструю частоту дискретизации).
Следующие концепции полезны при описании выполнения кода модели.
Initialization:
инициализирует код интерфейса и код модели.model
_initialize
ModelOutputs: Вызовы блоки в вашей модели, которые имеют выборку удар в текущее время и имеют они производят свой выход.
может быть сделано в основные или незначительные временные шаги. На основных временных шагах выход является заданным временным шагом симуляции. В незначительных временных шагах интерфейс интегрирует производные для обновления непрерывных состояний.model
_output
ModelUpdate:
Вызовы блоки, которые имеют выборку попадание в текущую точку во времени и имеют их обновлять свои дискретные состояния или подобные объекты типа.model
_update
ModelDerivatives: Вызывает блоки в вашей модели, которые имеют непрерывные состояния и имеют их обновлять производные.
вызывается только незначительными временными шагами.model
_derivatives
ModelTerminate:
завершает программу, если она предназначена для выполнения в течение конечного времени. Он уничтожает структуру данных модели реального времени, удаляет память и может записывать данные в файл.model
_terminate
Программа в реальном времени не может требовать 100% времени центрального процессора. Это требование предоставляет возможность выполнения фоновых задач в свободное время.
Фоновые задачи включают в себя операции, такие как запись данных в буфер или файл, предоставление доступа к данным программы сторонними инструментами мониторинга данных или обновление параметров программы.
Важно, однако, чтобы программа могла превентировать фоновую задачу, чтобы код модели мог выполняться в реальном времени.
То, как программа управляет задачами, зависит от возможностей окружения, в которой она работает.
Программы в реальном времени требуют тщательного определения времени вызовов задач (либо с помощью прерывания, либо с помощью примитива задачи операционной системы в реальном времени), так что код модели выполняется до своего завершения, прежде чем происходит другой вызов задачи. Синхронизация включает время для чтения и записи данных на внешнее оборудование и из него.
Следующий рисунок иллюстрирует синхронизацию прерывания.
Тайминг задачи
Интервал расчета должен быть достаточно длинным, чтобы разрешить выполнение кода модели между вызовами задачи.
На рисунке выше время между двумя соседними вертикальными стрелами является интервалом расчета. Пустые поля в верхней схеме показывают пример программы, которая может выполнить один шаг в пределах интервала и все еще оставлять время для фоновой задачи. Серый ящик в нижней схеме указывает, что происходит, если интервал расчета слишком короткий. Другой вызов задачи происходит до завершения задачи. Такая синхронизация приводит к ошибке выполнения.
Если программа в реальном времени разработана, чтобы запускаться вечно (то есть последнее время 0 или бесконечно, чтобы while
цикл никогда не выходит), тогда код завершения работы не выполняется.
Для получения дополнительной информации о том, как работает механизм синхронизации, см. «Абсолютные» и «Истекшие временные расчеты».
Режим external mode позволяет общаться между Simulink® блок и автономная программа, созданная из сгенерированного кода. В этом режиме программа в реальном времени функционирует как сервер межпроцессной связи, отвечая на запросы от механизма Simulink.
Configure Model for Debugging объясняет, как можно сохранить состояния системы, выходы и время в MAT-файл по завершении выполнения модели. LogTXY
функция, которая выполняет логгирование данных, работает по-разному в однозадачных и многозадачных окружениях.
Если вы исследуете, как LogTXY
вызывается в однозадачных и многозадачных окружениях, заметьте, что для однозадачной работы LogTXY
вызывается после ModelOutputs
. Во время этого ModelOutputs
вызов, блоки, которые имеют удар в момент t выполнения, в то время как в многозадачности, LogTXY
вызывается после ModelOutputs(tid=0)
, который выполняет только блоки, которые имеют удар в момент t и которые имеют идентификатор задачи 0. Это приводит к различиям в записанных значениях между однозадачным и многозадачным логгированием. В частности, рассмотрим модель с двумя шагами расчета, более быстрым шагом расчета, имеющим период 1,0 секунды, и более медленным шагом расчета, имеющим период 10,0 секунд. В момент времени t = k * 10, k = 0,1,2... и то, и другое быстрое (tid=0
) и медленно (tid=1
) блоки выполняются. При выполнении в многозадачном режиме, при LogTXY
вызывается, медленные блоки выполняются, но предыдущее значение регистрируется, в то время как в однозадачном режиме текущее значение регистрируется.
Другое различие происходит при регистрации данных в включенной подсистеме. Рассмотрим активированную подсистему, которая имеет медленный сигнал, приводящий в действие порт включения и быстрые блоки в пределах активированной подсистемы. В этом случае оценка разрешающего сигнала происходит в медленной задаче, и быстрые блоки видят задержку на один период дискретизации; таким образом, записанные значения покажут эти различия.
Чтобы суммировать различия в записанных данных между однозадачной и многозадачной, различия будут видны, когда
Блок root outport имеет шаг расчета, которое медленнее, чем самый быстрый шаг расчета
Блок с состояниями имеет шаг расчета, которое медленнее, чем самый быстрый шаг расчета
Блок в включенной подсистеме, где сигнал, управляющий портом включения, медленнее, чем скорость блоков в включенной подсистеме
В первых двух случаях, даже если записанные значения различаются между однозадачностью и многозадачностью, результаты модели не отличаются. Единственное реальное различие заключается в том, где (в какую точку времени) выполняется логгирование. Третий случай (активированная подсистема) приводит к задержке, которую можно увидеть в окружение реального времени.
Этот псевдокод показывает выполнение модели для однозадачной системы нереального времени.
main() { Initialization While (time < final time) ModelOutputs -- Major time step. LogTXY -- Log time, states and root outports. ModelUpdate -- Major time step. Integrate -- Integration in minor time step for -- models with continuous states. ModelDerivatives Do 0 or more ModelOutputs ModelDerivatives EndDo -- Number of iterations depends upon the solver Integrate derivatives to update continuous states. EndIntegrate EndWhile Termination }
Фаза инициализации начинается первой. Это состоит из инициализации состояний модели и настройки механизма выполнения. Модель затем выполняется, по одному шагу за раз. Сначала ModelOutputs
выполняется в момент t, затем регистрируются данные ввода-вывода рабочей области, а затем ModelUpdate
обновляет дискретные состояния. Далее, если ваша модель имеет непрерывные состояния, ModelDerivatives
интегрирует производные непрерывных состояний, чтобы сгенерировать состояния для времени , где h - размер шага. Затем время переходит к и процесс повторяется.
Во время ModelOutputs
и ModelUpdate
фазы выполнения модели, выполняются только блоки, которые достигают текущей точки времени.
Этот псевдокод показывает выполнение модели для многозадачной системы без реального времени.
main() { Initialization While (time < final time) ModelOutputs(tid=0) -- Major time step. LogTXY -- Log time, states, and root -- outports. ModelUpdate(tid=0) -- Major time step. Integrate -- Integration in minor time step for -- models with continuous states. ModelDerivatives Do 0 or more ModelOutputs(tid=0) ModelDerivatives EndDo (Number of iterations depends upon the solver.) Integrate derivatives to update continuous states. EndIntegrate For i=1:NumTids ModelOutputs(tid=i) -- Major time step. ModelUpdate(tid=i) -- Major time step. EndFor EndWhile Termination }
Многозадачная операция сложнее, чем однозадачное выполнение, потому что выходные и обновленные функции подразделяются на идентификатор задачи (tid
), который передается в эти функции. Это позволяет выполнять несколько вызовов этих функций с идентификаторами различной задачи, использующими перекрывающиеся прерывания, или для нескольких задач при использовании операционной системы реального времени. В симуляции несколько задач эмулируются путем выполнения кода в том порядке, который имел бы место, если бы в системе реального времени не существовало прерывания.
Выполнение многозадачности принимает, что скорости выполнения являются кратными базовой скорости. Продукт Simulink применяет это при создании модели многозадачности с фиксированным шагом. Цикл выполнения многозадачности очень похож на цикл выполнения одной задачи, за исключением использования идентификатора задачи (tid
) аргумент в ModelOutputs
и ModelUpdate
.
Вы не можете использовать tid
значения из кода, сгенерированного целевым файлом, а не Simulink Coder™. Simulink Coder отслеживает использование tid
при генерации кода для определенной подсистемы или типа функции. Когда вы генерируете код в целевом файле, этот аргумент не может быть отслежен, потому что возможности не имеет типа подсистемы или функции. Поэтому tid
становится неопределенной переменной, и ваш целевой файл не может скомпилироваться.
Этот псевдокод показывает выполнение модели в однозадачной системе реального времени, где модель запускается на уровне прерывания.
rtOneStep() { Check for interrupt overflow Enable "rtOneStep" interrupt ModelOutputs -- Major time step. LogTXY -- Log time, states and root outports. ModelUpdate -- Major time step. Integrate -- Integration in minor time step for models -- with continuous states. ModelDerivatives Do 0 or more ModelOutputs ModelDerivatives EndDo (Number of iterations depends upon the solver.) Integrate derivatives to update continuous states. EndIntegrate } main() { Initialization (including installation of rtOneStep as an interrupt service routine, ISR, for a real-time clock). While(time < final time) Background task. EndWhile Mask interrupts (Disable rtOneStep from executing.) Complete any background tasks. Shutdown }
Однозадачное выполнение в реальном времени очень похоже на однозадачное выполнение в нереальном времени, за исключением того, что вместо свободного выполнения кода, rt_OneStep
функция управляется периодическим прерыванием таймера.
В интервале, заданном базовой частотой дискретизации программы, стандартная программа обслуживания прерывания (ISR) прерывает фоновую задачу, чтобы выполнить код модели. Базовая частота дискретизации является самой быстрой в модели. Если модель имеет непрерывные блоки, то размер шага интегрирования определяет базовую частоту дискретизации.
Например, если код модели является контроллером, работающим на частоте 100 Гц, то каждые 0,01 секунды фоновая задача прерывается. Во время этого прерывания контроллер считывает свои входы от аналого-цифрового преобразователя (АЦП), вычисляет свои выходы, записывает эти выходы в цифро-аналоговый преобразователь (ЦАП) и обновляет свои состояния. Затем управление программой возвращается к фоновой задаче. Эти шаги должны произойти до следующего прерывания.
Этот псевдокод показывает, как модель выполняется в многозадачной системе реального времени, где модель запускается на уровне прерывания.
rtOneStep() { Check for interrupt overflow Enable "rtOneStep" interrupt ModelOutputs(tid=0) -- Major time step. LogTXY -- Log time, states and root outports. ModelUpdate(tid=0) -- Major time step. Integrate -- Integration in minor time step for -- models with continuous states. ModelDerivatives Do 0 or more ModelOutputs(tid=0) ModelDerivatives EndDo (Number of iterations depends upon the solver.) Integrate derivatives and update continuous states. EndIntegrate For i=1:NumTasks If (hit in task i) ModelOutputs(tid=i) ModelUpdate(tid=i) EndIf EndFor } main() { Initialization (including installation of rtOneStep as an interrupt service routine, ISR, for a real-time clock). While(time < final time) Background task. EndWhile Mask interrupts (Disable rtOneStep from executing.) Complete any background tasks. Shutdown }
Выполнение моделей на уровне прерывания в многозадачном окружении в реальном времени очень похоже на предыдущее однозадачное окружение, за исключением того, что для параллельного выполнения задач используются перекрывающиеся прерывания.
Выполнение модели в однозадачном или многозадачном окружении при использовании примитивов задач операционной системы в реальном времени очень похоже на примеры уровня прерывания, обсужденные выше. Псевдокод ниже предназначен для однозадачной модели с использованием примитивов задачи в реальном времени.
tSingleRate() { MainLoop: If clockSem already "given", then error out due to overflow. Wait on clockSem ModelOutputs -- Major time step. LogTXY -- Log time, states and root -- outports ModelUpdate -- Major time step Integrate -- Integration in minor time step -- for models with continuous -- states. ModelDeriviatives Do 0 or more ModelOutputs ModelDerivatives EndDo (Number of iterations depends upon the solver.) Integrate derivatives to update continuous states. EndIntegrate EndMainLoop } main() { Initialization Start/spawn task "tSingleRate". Start clock that does a "semGive" on a clockSem semaphore. Wait on "model-running" semaphore. Shutdown }
В этом однозадачном окружении модель выполняется как примитивы задач операционной системы в реальном времени. В этом окружении создайте одну задачу (tSingleRate
), чтобы запустить код модели. Эта задача вызывается, когда происходит такт синхроимпульса. Тактовый такт даёт clockSem
(тактовый семафор) к задаче модели (tSingleRate
). Задача модели ожидает семафор перед выполнением. Тактовые такты происходят при основном размере шага (базовой ставке) для вашей модели.
Этот псевдокод предназначен для многозадачной модели с использованием примитивов задачи в реальном времени.
tSubRate(subTaskSem,i) { Loop: Wait on semaphore subTaskSem. ModelOutputs(tid=i) ModelUpdate(tid=i) EndLoop } tBaseRate() { MainLoop: If clockSem already "given", then error out due to overflow. Wait on clockSem For i=1:NumTasks If (hit in task i) If task i is currently executing, then error out due to overflow. Do a "semGive" on subTaskSem for task i. EndIf EndFor ModelOutputs(tid=0) -- major time step. LogTXY -- Log time, states and root outports. ModelUpdate(tid=0) -- major time step. Loop: -- Integration in minor time step for -- models with continuous states. ModelDeriviatives Do 0 or more ModelOutputs(tid=0) ModelDerivatives EndDo (number of iterations depends upon the solver). Integrate derivatives to update continuous states. EndLoop EndMainLoop } main() { Initialization Start/spawn task "tSubRate". Start/spawn task "tBaseRate". Start clock that does a "semGive" on a clockSem semaphore. Wait on "model-running" semaphore. Shutdown }
В этом многозадачном окружении модель выполняется с помощью примитивов задач операционной системы в реальном времени. Такие окружения требуют нескольких задач модели (tBaseRate
и несколько tSubRate
задачи), чтобы запустить код модели. Задача базовой скорости (tBaseRate
) имеет более высокий приоритет, чем задачи субрейта. Задача подрейса для tid=1
имеет более высокий приоритет, чем задача подрейса для tid=2
и так далее. Задача базовой скорости вызывается, когда происходит такт синхроимпульса. Тактовый такт даёт clockSem
на tBaseRate
. Первое tBaseRate
does - давать семафоры подтаскам, которые имеют попадание в текущий момент времени. Поскольку задача базовой скорости имеет более высокий приоритет, она продолжает выполняться. Далее она выполняет самую быструю задачу (tid=0
), состоящий из блоков в вашей модели, которые имеют самый быстрый шаг расчета. После этого выполнения он возобновляется в ожидании часового семафора. Тактовые такты сконфигурированы так, чтобы происходило при основном размере шага для вашей модели.
Среда программы быстрого прототипирования обеспечивает общий интерфейс прикладного программирования (API), который не меняется между определениями модели.
Embedded Coder® продукт предоставляет другую среду, называемую встраиваемой программной средой. Встроенная программная среда обеспечивает оптимизированный API, который адаптирован к вашей модели. Когда вы используете встроенный стиль сгенерированного кода, вы моделируете, как бы ваш код выполнялся в вашей встраиваемой системе. Поэтому определения, определенные в вашей модели, должны быть специфичными для ваших целевых процессоров. Такие элементы, как имя модели, параметр и класс памяти сигналов, включены в API для встроенного стиля кода.
Одно из основных различий между быстрым прототипированием и встроенным стилем сгенерированного кода заключается в том, что последний содержит меньше функций точки входа. Встроенный стиль кода может быть сконфигурирован таким образом, чтобы иметь только одну функцию,
.model
_step
Таким образом, код выполнения модели устраняет Loop...EndLoop
операторы и группы ModelOutputs
, LogTXY
, и ModelUpdate
в один оператор,
.model
_step
Для получения дополнительной информации о том, как выполняется сгенерированный встраиваемый код, смотрите Сконфигурируйте генерацию кода C для функций точки входа модели.