Выполнение кода, сгенерированного из модели

Генератор кода производит алгоритмический код, как определено вашей моделью. Можно включать внешний (для примера, пользовательский или устаревший) код в модель с помощью методов, описанных в разделе «Выбор внешнего кода» Интегрирования Workflow.

Генератор кода также предоставляет интерфейс, который выполняет сгенерированный код модели. Интерфейс и код модели компилируются вместе, чтобы создать исполняемую программу. Следующий рисунок показывает объектно-ориентированное представление исполняемого файла высокого уровня.

Объектно-ориентированное представление программы в реальном времени

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

Следующие концепции полезны при описании выполнения кода модели.

  • Initialization: model_initialize инициализирует код интерфейса и код модели.

  • ModelOutputs: Вызовы блоки в вашей модели, которые имеют выборку удар в текущее время и имеют они производят свой выход. model_output может быть сделано в основные или незначительные временные шаги. На основных временных шагах выход является заданным временным шагом симуляции. В незначительных временных шагах интерфейс интегрирует производные для обновления непрерывных состояний.

  • ModelUpdate: model_update Вызовы блоки, которые имеют выборку попадание в текущую точку во времени и имеют их обновлять свои дискретные состояния или подобные объекты типа.

  • ModelDerivatives: Вызывает блоки в вашей модели, которые имеют непрерывные состояния и имеют их обновлять производные. model_derivatives вызывается только незначительными временными шагами.

  • ModelTerminate: model_terminate завершает программу, если она предназначена для выполнения в течение конечного времени. Он уничтожает структуру данных модели реального времени, удаляет память и может записывать данные в файл.

Выполнение программы

Программа в реальном времени не может требовать 100% времени центрального процессора. Это требование предоставляет возможность выполнения фоновых задач в свободное время.

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

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

То, как программа управляет задачами, зависит от возможностей окружения, в которой она работает.

Тайминг программы

Программы в реальном времени требуют тщательного определения времени вызовов задач (либо с помощью прерывания, либо с помощью примитива задачи операционной системы в реальном времени), так что код модели выполняется до своего завершения, прежде чем происходит другой вызов задачи. Синхронизация включает время для чтения и записи данных на внешнее оборудование и из него.

Следующий рисунок иллюстрирует синхронизацию прерывания.

Тайминг задачи

Интервал расчета должен быть достаточно длинным, чтобы разрешить выполнение кода модели между вызовами задачи.

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

Если программа в реальном времени разработана, чтобы запускаться вечно (то есть последнее время 0 или бесконечно, чтобы while цикл никогда не выходит), тогда код завершения работы не выполняется.

Для получения дополнительной информации о том, как работает механизм синхронизации, см. «Абсолютные» и «Истекшие временные расчеты».

Связь во режиме external mode

Режим 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 интегрирует производные непрерывных состояний, чтобы сгенерировать состояния для времени tnew=t+h, где h - размер шага. Затем время переходит к tnew и процесс повторяется.

Во время 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 для функций точки входа модели.

Похожие темы