Сгенерируйте модульный код функции для невиртуальных подсистем

Сведения о невиртуальной Генерации кода подсистемы

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

Чтобы сгенерировать код модульной функции для невиртуальных подсистем, включая атомарные подсистемы и условно выполненные подсистемы, используйте параметры блоков подсистемы Function with separate data. Эти параметры блоков предписывают генератору кода создать структуру ввода-вывода блоков и данных DWork для функции невиртуальной подсистемы, которая независима от структур родительской модели данных. В результате сгенерированный код для подсистемы:

  • Легче отследить.

  • Легче протестировать.

  • Уменьшает размер глобальных структур данных модели.

Чтобы использовать параметр Function with separate data,

  • Сконфигурируйте модель с системным целевым файлом на основе ERT.

  • Сконфигурируйте подсистему как атомарную или условно выполненную.

  • Установите параметры блоков подсистемы Function packaging равным Nonreusable function.

Чтобы сконфигурировать подсистему для генерации кода модульной функции, вызовите диалоговое окно Subsystem Parameters и сделайте ряд выбора, чтобы отобразить и включить опцию Function with separate data. Для получения дополнительной информации смотрите Configure Subsystem для генерации кода модульной функции и кода модульной функции для невиртуальных подсистем. Для ограничений, которые применяются, смотрите Ограничения модульного кода невиртуальной подсистемы.

Для получения дополнительной информации о генерации кода для атомарных подсистем смотрите разделы «Управление генерацией функций для подсистем» и «Генерация кода и исполняемых файлов для отдельных подсистем».

Сконфигурируйте подсистему для генерации кода модульной функции

  1. Проверьте, что модель, содержащая подсистему, использует системный целевой файл на основе ERT.

  2. Выберите подсистему, для которой вы хотите сгенерировать код модульной функции и откройте диалоговое окно Subsystem Parameters. Диалоговое окно для атомарной подсистемы показано ниже. (В диалоговом окне для условно выполняемой подсистемы опция диалогового окна Treat as atomic unit выделена серым цветом, и можно пропустить Шаг 3.)

  3. Если Treat as atomic unit параметров блоков доступен для выбора, но не выбран, подсистема не является атомарной и не выполняется по условию. Выберите Treat as atomic unit параметра, который включает параметр Function packaging на вкладке Code Generation. Выберите вкладку Code Generation.

  4. Для параметра Function packaging выберите Nonreusable function. После выбора этого параметра отображается параметр Function with separate data.

    Прежде чем вы сгенерируете код для невиртуальной подсистемы с выбранным параметром Function with separate data, рассмотрите генерацию кода функции с очищенным параметром и сохраните сгенерированную функцию .c и .h файлы в отдельной директории для последующего сравнения.

  5. Выберите параметр Function with separate data. Появляются дополнительные параметры.

    Чтобы управлять именованием сгенерированной функции подсистемы и файлов подсистемы, измените параметры подсистемы Function name options и File name options.

  6. Сохраните изменения параметров подсистемы и выйдите из диалогового окна нажав OK.

  7. Сгенерируйте код для подсистемы и исследуйте сгенерированные файлы, включая функцию .c и .h файлы с именем в соответствии со спецификациями параметров подсистемы.

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

Модульный код функции для невиртуальных подсистем

Этот пример показывает, как сгенерировать невиртуальный код функции подсистемы с Function with separate data параметром, очищенным и выбранным, и сравнивает результаты.

  1. Откройте пример модели rtwdemo_atomic. Затем откройте Embedded Coder приложения. Измените системный целевой файл на ert.tlc.

    Эта модель показывает, как сохранить контур виртуальной подсистемы. Когда вы выбираете подсистему параметров блоков Treat as atomic unit, код, который генератор кода производит для подсистемы, выполняется как атомарный модуль. Когда настроен как атомарный, можно задать, как генератор кода представляет подсистему, установив параметр Function Packaging на вкладке Code Generation. Можно указать, что подсистема переведена в один из следующих типов реализации:

    • Inline: Встроенный код подсистемы в узлах вызова.

    • Function: void/void функция с вводом-выводом и внутренними данными в структуре глобальных данных модели.

    • Reusable Function: Входящая функция с данными, переданными в качестве аргументов функции.

    • Auto: Генератор кода оптимизирует реализацию на основе контекста.

  2. Дважды кликните подсистему SS1 и исследуйте содержимое.

    Затем закройте окно подсистемы.

  3. Щелкните правой кнопкой мыши подсистему SS1, выберите в контекстном меню Параметров блоков (Подсистема) и исследуйте настройки. Simulink® и генератор кода может избежать «искусственных» алгебраических циклов, когда вы делаете подсистему атомарной с параметром подсистемы Minimize algebraic loop occurrences.

  4. Создайте вариант rtwdemo_atomic который показывает код функции без разделения данных.

    1. В диалоговом окне «Параметры подсистемы»

      • На вкладке Main выберите Treat as atomic unit.

      • На вкладке Code Generation:

        • Установите Function packaging значение Nonreusable function.

        • Установите Function name options значение User specified.

        • Установите Function name значение myfun.

        • Установите File name options значение Use function name. Эта настройка является необязательной, но упрощает последующую задачу сравнения кода, заставляя код функции атомарной подсистемы генерироваться в файлы myfun.c и myfun.h.

      Не выбирайте параметр Function with separate data.

    2. Нажмите кнопку Apply, чтобы применить изменения, и нажмите кнопку OK, чтобы выйти из диалогового окна.

    3. Сохраните вариант модели с уникальным именем файла (для примера, rtwdemo_atomic1) в место с возможностью записи.

  5. Создайте вариант rtwdemo_atomic который показывает код функции с разделением данных.

    1. Откройте rtwdemo_atomic модели.

    2. Откройте Embedded Coder приложение. Измените системный целевой файл на ert.tlc.

    3. В холсте модели щелкните правой кнопкой мыши подсистему SS1 и выберите Block Parameters (Subsystem). В диалоговом окне «Параметры подсистемы»

      • На вкладке Main выберите Treat as atomic unit.

      • На вкладке Code Generation:

        • Установите Function packaging значение Nonreusable function.

        • Установите Function name options значение User specified.

        • Установите Function name значение myfun.

        • Установите File name options значение Use function name.

        • Выберите Function with separate data.

    4. Нажмите кнопку Apply, чтобы применить изменение, и нажмите кнопку OK, чтобы выйти из диалогового окна.

    5. Сохраните вариант модели с уникальным именем файла (для примера, rtwdemo_atomic2) в место с возможностью записи.

  6. Сгенерируйте код для каждой модели (для примера, rtwdemo_atomic1 и rtwdemo_atomic2).

  7. Сравните model.c/ .h и myfun.c/ .h файлы, сгенерированные для этих двух моделей. Для сравнения кода смотрите H File Differences for Nonvirtual Subsystem Function Data Separation и C File Differences for Nonvirtual Subsystem Function Data Separation.

    В этом примере нет существенных различий в сгенерированных вариантах ert_main.c, model_private.h, model_types.h, или rtwtypes.h.

H- Различий файла для разделения данных о невиртуальной подсистеме

  • Выбор Function with separate data заставляет генератор кода помещать определения типов для данных подсистемы в myfun.h файл для rtwdemo_atomic2:

    /* Block states (default storage) for system '<Root>/SS1' */
    typedef struct {
      real_T Integrator_DSTATE;            /* '<S1>/Integrator' */
    } DW_myfun_T;

    Для rtwdemo_atomic1, определения типов для данных подсистемы относятся к модели и появляются в rtwdemo_atomic1.h:

    /* Block signals (default storage) */
    typedef struct {
      real_T Sum;                          /* '<Root>/Sum' */
    } B_rtwdemo_atomic_1_T;
    
    /* Block states (default storage) for system '<Root>' */
    typedef struct {
      real_T Integrator_DSTATE;            /* '<S1>/Integrator' */
    } DW_rtwdemo_atomic_1_T;
  • Выбор Function with separate data генерирует следующие внешние объявления в myfun.h файл для rtwdemo_atomic2:

    /* Extern declarations of internal data for system '<Root>/SS1' */
    extern DW_myfun_T myfun_DW;
    extern void myfun_Update(void);
    extern void myfun(void);

    Напротив, сгенерированный код для rtwdemo_atomic1 содержит внешние объявления уровня модели для подсистемы BlockIO и D_Work данные, в rtwdemo_atomic1.h:

    /* Block signals (default storage) */
    extern B_rtwdemo_atomic_1_T rtwdemo_atomic_1_B;
    
    /* Block states (default storage) */
    extern DW_rtwdemo_atomic_1_T rtwdemo_atomic_1_DW;

Различия файлов C для разделения данных о невиртуальной подсистеме

  • Выбор Function with separate data вызывает отдельную функцию инициализации подсистемы, myfun_initialize, будет сгенерирован в myfun.c файл для rtwdemo_atomic2:

    void myfun_initialize(void) {
      {
        ((real_T*)&rtwdemo_atomic2_myfunB.Integrator)[0] = 0.0;
      }
      rtwdemo_atomic2_myfunDW.Integrator_DSTATE = 0.0;
    }

    Функция инициализации подсистемы в myfun.c вызывается функцией инициализации модели в rtwdemo_atomic2.c:

    /* Model initialize function */
    
    void rtwdemo_atomic2_initialize(void)
    {
    ...
    
      /* Initialize subsystem data */
      myfun_initialize();
    }

    Напротив, для rtwdemo_atomic1данные подсистемы инициализируются функцией инициализации модели в rtwdemo_atomic1.c:

    /* Model initialize function */
    
    void rtwdemo_atomic1_initialize(void)
    {
    ...
      /* block I/O */
      {
     ...
        ((real_T*)&rtwdemo_atomic1_B.Integrator)[0] = 0.0;
      }
    
      /* states (dwork) */
    
      rtwdemo_atomic1_DWork.Integrator_DSTATE = 0.0;
    ...
    }
  • Выбор Function with separate data генерирует следующие объявления в myfun.c файл для rtwdemo_atomic2:

    /* Declare variables for internal data of system '<Root>/SS1' */
    DW_myfun_T myfun_DW;

    Напротив, сгенерированный код для rtwdemo_atomic1 содержит объявления уровня модели для подсистем BlockIO и D_Work данные, в rtwdemo_atomic1.c:

    /* Block signals (default storage) */
    B_rtwdemo_atomic_1_T rtwdemo_atomic_1_B;
    
    /* Block states (default storage) */
    DW_rtwdemo_atomic_1_T rtwdemo_atomic_1_DW;
  • Выбор Function with separate data генерирует именование идентификаторов, которое отражает ориентацию подсистемы элементов данных. Ссылки на данные подсистемы в функциях подсистемы, таких как myfun и myfun_update, находятся в модели model_step функция. Например, сравните этот код с myfun для rtwdemo_atomic2

    /*  DiscreteIntegrator: '<S1>/Integrator' */
      rtwdemo_atomic_2_Y.Out1 = myfun_DW.Integrator_DSTATE;

    к соответствующему коду из myfun для rtwdemo_atomic1.

    /* DiscreteIntegrator: '<S1>/Integrator' */
    rtwdemo_atomic_1_Y.Out1 = rtwdemo_atomic_1_DW.Integrator_DSTATE;

Функции разбиения в сгенерированном коде

В этом примере показано, как связать подсистемы в модели с именами функции и файлами.

Узнать, как:

  • Задайте функцию и имена файла в сгенерированном коде.

  • Идентифицируйте части сгенерированного кода, необходимые для интегрирования.

  • Сгенерируйте код для атомарных подсистем.

  • Идентифицируйте данные, которые требуются для выполнения сгенерированной функции.

Для получения информации о модели примера и других примерах в этой серии, смотрите Подготовьте модель алгоритма управления для генерации кода C.

Атомарные и виртуальные подсистемы

Модели в примере Prepare a Алгоритм Управления Model for Генерация Кода C и Configure Data Interface в Сгенерированном коде используют виртуальные подсистемы. Виртуальные подсистемы визуально организуют блоки, но не влияют на функциональность модели. Атомарные подсистемы оценивают блоки, включенные в модель, как модуль. С помощью атомарных подсистем можно задать дополнительную информацию о разбиении функций. В модели атомарные подсистемы появляются с жирной границей.

Просмотр изменений в архитектуре модели

Откройте пример модели rtwdemo_PCG_Eval_P3.

Сохраните копию модели в папку с возможностью записи.

В этом примере показано, как заменить виртуальные подсистемы подсистемами вызова функций. Подсистемы вызова функций:

  • Являются атомарными подсистемами

  • Позволяет вам управлять порядком выполнения подсистемы

  • Выполняется, когда запускается сигнал вызова функции

Путем управления порядком выполнения подсистем можно сопоставить модель с существующей системой, которая имеет определенный порядок выполнения.

Рисунок идентифицирует подсистемы вызова функции (1) PI_ctrl_1, PI_ctrl_2, и Pos_Command_Arbitration.

Эта версия модели содержит новую подсистему Execution_Order_Control (2), которая содержит график Stateflow ®, которая моделирует вызывающую функциональность планировщика. Подсистема управляет порядком выполнения подсистем вызова функции через сигналы вызова функции (3). Позже в этом примере вы исследуете, как изменение порядка выполнения может изменить результаты симуляции.

Эта версия модели содержит новые блоки Преобразования Сигналов (4) на выходах ПИ-контроллеров. С помощью этих дополнительных блоков генератор кода может сгенерировать одну входящую функцию для ПИ-контроллеров.

Расположение функции управления и размещение файлов в сгенерированном коде

В Подготовке Модели Алгоритма Управления для Генерации Кода C и Конфигурировании Интерфейса Данных в Сгенерированном Коде генератор кода создает одну model_step функция, которая содержит код алгоритма управления. Однако многие приложения требуют большего уровня контроля за размещением функций в файлах. Изменяя параметры атомарных подсистем, можно задать несколько функций в одной модели.

Рисунок показывает параметры подсистемы для PI_ctrl_1.

Обработайте как атомарный модуль

  • Включает другое подменю. Для атомарных подсистем этот параметр автоматически выбирается и отключается.

Шаг расчета

  • Задает шаг расчета для выполнения. Недоступно для подсистем вызова функций.

Опции упаковки функций

  • Auto -- Определяет, как подсистема появится в сгенерированном коде. Это значение является значением по умолчанию.

  • Inline - Помещает код подсистемы в строку с остальной частью кода модели.

  • Function -- Генерирует код для подсистемы как функции.

  • Reusable function -- Генерирует переиспользуемую (повторно входящую) функцию из подсистемы. Функция передает все входные и выходные данные через формальные параметры. Функция не имеет прямого доступа к глобальным переменным.

Опции имени функции

  • Выбор Function или Reusable function для Function packaging включает опции имени функции.

  • Auto -- Определяет функцию.

  • Use subsystem name -- Основывает функцию на имени подсистемы.

  • User specified - Применяет указанное имя файла.

Опции имени файла

  • Выбор Function или Reusable function для Function packaging включает опции имени файла.

  • Auto -- Помещает определение функции в модуль, сгенерированный для родительской системы, или, если корень модели является родительским элементом, в model.c.

  • Use subsystem name - Генерирует отдельный файл. Имя файла - это имя подсистемы или библиотечного блока.

  • Use function name - Генерирует отдельный файл. Имя файла задается с помощью Имени функции опций.

  • User specified -- Применяет указанное уникальное имя файла.

Функция с отдельными данными

  • Включено, когда для Function packaging задано значение Function. При выборе генератор кода отделяет внутренние данные подсистемы (для примера, сигналы) от данных родительской модели. Подсистема владеет этими отдельными данными.

Сгенерируйте входящий код

Embedded Coder ® поддерживает входящий код. Повторный код является переиспользуемой стандартной программой программирования, которую одновременно могут использовать несколько программ. Повторный код используется в операционных системах и другом системном программном обеспечении, которое использует многопоточность для обработки параллельных событий. Повторный код не поддерживает данные о состоянии, поэтому в функции нет постоянных переменных. Вызывающие программы поддерживают переменные состояния и должны передать данные о состоянии в функцию. Многие пользователи или процессов могут совместно использовать одну копию входящей функции.

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

В некоторых случаях строение модели препятствует переиспользуемому коду. В таблице перечислены общие вопросы.

Cause                                     Solution
Subsystem output feeds global signal      Add a Signal Conversion block between the 
data                                      subsystem and the global signal.
Generated function receives data          Select Configuration Parameters >
(formal parameters) through pointers      Model Referencing > Pass fixed-size scalar root
                                          inputs by value for code generation.           
Subsystem uses global signal data         Use a port to pass the global data in and out 
in internal algorithm                     of the subsystem.

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

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

В этой версии модели подсистемы PI_ctrl_1 и PI_ctrl_2 маскированы. В каждой маске значения P и I коэффициент усиления задается такими объектами данных, как I_Gain_2 и P_Gain_2.

Сгенерируйте код для атомарной подсистемы

В разделе «Подготовка модели алгоритма управления для генерации кода C и конфигурирование интерфейса данных в Сгенерированном коде» вы генерируете код на корневом уровне модели. Также можно создать определенную подсистему.

Чтобы инициировать сборку подсистемы, используйте контекстное меню. Вы можете выбрать из следующих опций:

  1. Сборка Эта Подсистема: Обрабатывает подсистему как отдельный режим и создает полный набор исходных файлов C и заголовочных файлов. Эта опция не поддерживает подсистем вызова функций.

  2. Сгенерируйте S-функцию: Генерирует код C для подсистемы и создает оболочку S-функции. Затем можно симулировать код в исходной модели. Эта опция не поддерживает подсистем вызова функций.

  3. Экспорты функций: Генерирует Код С без кода планирования, который поставляется с опцией Build This Subsystem. Используйте эту опцию для создания подсистем, которые используют триггеры, такие как подсистемы вызова функций.

Также откройте приложение Embedded Coder, выберите подсистему и на вкладке Код С нажмите Build.

Исследуйте сгенерированный код

Этот пример сравнивает файлы, которые генерируются для полной системной сборки, с файлами, которые генерируются для экспортированных функций. Вы также исследуете, как маскированные данные появляются в коде.

Запустите скрипт сборки для трёх опций. Затем исследуйте сгенерированные файлы, щелкнув гиперссылки.

rtwdemo_PCG_Eval_P3.c

  • Полная сборка: Да, функция шага

  • PI_ctrl_1: Нет

  • Pos_Command_Arbitration: Нет

PI_ctrl_1.c

  • Полная сборка: Нет

  • PI_ctrl_1: Да, функция триггера

  • Pos_Command_Arbitration: Нет

Pos_Command_Arbitration.c

  • Полная сборка: Нет

  • PI_ctrl_1: Нет

  • Pos_Command_Arbitration: Да, Init и функция

PI_Ctrl_Reusable.c

  • Полная сборка: Да

  • PI_ctrl_1: Да

  • Pos_Command_Arbitration: Нет

ert_main.c

  • Полная сборка: Да

  • PI_ctrl_1: Да

  • Pos_Command_Arbitration: Да

eval_data.c

  • Полная сборка: Да (1)

  • PI_ctrl_1: Да (1)

  • Pos_Command_Arbitration: Нет, данные Eval, не используемые в схеме

(1) eval_data.c имеет разное содержимое в полных и экспортных сборках функций. Полная сборка включает все параметры, которые использует модель. Экспорт функций содержит только те переменные, которые использует подсистема.

Маскированные данные в сгенерированном коде

В файл rtwdemo_PCG_Eval_P3.cсайты вызовов входящей функции используют объекты данных P_Gain, I_Gain, P_Gain_2, и I_Gain_2 как аргументы.

Эффект порядка выполнения на результаты симуляции

По умолчанию Simulink ® выполняет подсистемы в следующем порядке:

  1. PI_ctrl_1

  2. PI_ctrl_2

  3. Pos_Command_Arbitration

В данном примере можно задать один из двух альтернативных порядков выполнения. Затем можно использовать тестовую обвязку, чтобы наблюдать эффект порядка выполнения на результаты симуляции. Подсистема Execution_Order_Control имеет два строений, которые управляют порядком выполнения. Чтобы выбрать строение, используйте контекстное меню подсистемы.

Измените порядок выполнения и наблюдайте за результатами.

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

Для следующего примера в этой серии смотрите Вызов внешнего кода С из модели и Сгенерированный код.

Невиртуальные ограничения кода модульной функции подсистемы

Невиртуальные параметры блоков подсистемы Function with separate data имеют следующие ограничения:

  • Параметр доступен для моделей, сконфигурированных с системным целевым файлом на основе ERT.

  • Невиртуальная подсистема, к которой применяется параметр, не может иметь нескольких шагов расчета или непрерывных шагов расчета; то есть подсистема должна быть односкоростной с дискретным шагом расчета.

  • Невиртуальная подсистема не может содержать непрерывные состояния.

  • Невиртуальная подсистема не может выходная функция сигналы вызова.

  • Невиртуальная подсистема не может содержать нелинейные S-функции.

  • Сгенерированные файлы для невиртуальной подсистемы будут ссылаться на заголовочные файлы всей модели, такие как model.h и model_private.h.

  • Параметр несовместим с параметром Classic call interface. Выбор обоих параметров генерирует ошибку.

  • Параметр несовместим со Reusable function настройка для параметра конфигурации <reservedrangesplaceholder0> модели. Выбор обоих параметров генерирует ошибку.

  • Когда вы выбираете параметр для подсистемы, модель, которая содержит подсистему, не может содержать блок Data Store Memory с Share across model instances выбранными. См. Data Store Memory.

Похожие темы