exponenta event banner

Создание кода повторного ввода из функциональных блоков Simulink

Если используется Embedded Coder ®, можно создать повторно используемый код, представив алгоритм как функциональный блок Simulink. Примеры того, когда нужно генерировать повторный ввод кода из блоков Simulink Function, являются случаями, когда функция совместно использует состояние между вызывающими функциями в модели или для приложений клиент/сервер. Можно создать код с высокой степенью модульности с помощью нескольких экземпляров общего блока функции Simulink в модели export-function. Генератор кода создает код функции и связывает каждое использование или вызов функции с данными для конкретного экземпляра. Область действия функции зависит от размещения функции на корневом уровне модели или в подсистеме .

Генератор кода создает повторный код функции при конфигурировании:

Вызовите функцию, представленную блоком Simulink Function в области, с одного уровня выше, на том же уровне или с уровня ниже уровня определения функции. Можно задать область действия функции в атомной или невиртуальной подсистеме, но доступность вызова функции ограничена одним и тем же уровнем или ниже иерархии. Имя функции не обязательно должно быть уникальным.

Определение требований

До и во время конструирования модели учтите следующее:

  • Сколько экземпляров каждой функции требуется?

  • Нужно ли ограничивать сайты вызовов для функции моделью, содержащей определение функции?

  • Нужна ли вам функция для взаимодействия с сигналами в локальной среде, но скрывать эти сигналы от вызывающих абонентов?

  • Должны ли функции напрямую взаимодействовать друг с другом?

  • Должны ли функции подключаться к внешним вводам-выводам?

  • Нужно ли регистрировать выходные данные функции?

Создать модель

Использование компонента модели примера rtwdemo_comp чтобы увидеть, как использовать функциональные блоки Simulink для создания исходного кода C. Использовать пример модели rtwdemo_comp_cpp если вы предпочитаете генерировать код C++. Откройте модель и проверьте иерархию модели.

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

Ссылочная модель, rtwdemo_func_dinteg, состоит из блока Simulink Function, который определяет функцию multiinstfunc и подсистема subsys_calc.

Подсистема состоит из блока Simulink Function. Использование блока Simulink Function показывает, как можно ограничить область функции, определяемую блоком, моделью, содержащей подсистему. Генератор кода создает код функции для func_calc и связывает каждый вызов функции с данными, специфичными для экземпляра. Данные включают в себя состояния, такие как данные, хранящиеся в памяти.

Блок функции Simulink, определяющий функцию multiinstfunc использует блок вызывающего абонента функции для вызова функции func_calc. Этот функциональный блок Simulink также показывает, что он может взаимодействовать с сигналами в локальной среде блока через блоки Inport и Outport.

На верхнем уровне модели rtwdemo_comp, подсистема вызова функции использует блоки вызова функции для вызова двух экземпляров функции multiinstfunc. Генератор кода создает код функции и связывает каждый вызов с данными для конкретного экземпляра.

Настройка модели и элементов модели

Настройка функциональных блоков Simulink

Сконфигурируйте функциональные блоки Simulink, установив параметры для блока триггерного порта функции. Чтобы генератор кода создавал повторный код из функциональных блоков Simulink:

  • Настройте экземпляры блоков с тем же именем функции.

  • Задать для параметра блока Видимость функции значение scoped.

В примере имя функции для блоков Simulink Function в двух экземплярах ссылочной модели rtwdemo_func_dinteg указывается как multiinstfunc.

Конфигурирование блоков вызывающего абонента функции

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

В этом примере прототипы конфигурируются следующим образом:

  • В подсистеме вызова функций прототипы для вызывающих функций конфигурируются как y = Instance1.multiinstfunc(u) и y = Instance2.multiinstfunc(u). Instancen префикс однозначно идентифицирует каждый вызов функции и связывает вызов с собственным набором данных.

  • Вызывающая функция в функции multiinstfunc сконфигурирован с прототипом y = subsys_calc.func_calc(u). Префикс subsys_calc определяет подсистему, содержащую определение функции.

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

Конфигурация подсистемы

Изменения конфигурации не требуются для подсистемы в примерной модели. При включении блока функции Simulink в подсистему генератор кода

  • Определяет область действия функции для модели, включающей подсистему.

  • Рассматривает подсистему как атомную единицу.

Настройка ссылочной модели

Настройте ссылочную модель, включающую блок функции Simulink:

  • В диалоговом окне «Параметры блока» задайте для параметра «Имя модели» имя файла ссылочной модели. В этом примере имя модели: rtwdemo_func_dinteg.slx.

  • Задать параметр конфигурации модели Общее число экземпляров, разрешенных для модели верхнего уровня, равным Multiple.

  • Чтобы создать интерфейс класса C++ для ссылочной модели, задайте для параметра конфигурации модели Language значение C++ и параметр Code interface packaging to C++ class.

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

Настройка модели верхнего уровня

Настройте верхнюю модель для компонента модели. Если требуется повторно использовать компонент модели (то есть верхнюю модель), установите для параметра конфигурации модели Code interface packaging значение Reusable function. При создании кода C++ можно установить для этого параметра значение C++ class. В любом случае также:

  • Задайте для параметра конфигурации модели Диагностику ошибок кода нескольких экземпляров значение Error.

  • Установка параметра конфигурации модели Pass root-level I/O для Part of model data structure.

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

Создание и проверка кода C

Создайте код C для модели.

  • Код функции для многоэкземплярного функционального блока Simulink

    При размещении блока функции Simulink в области в ссылочной модели, которая используется несколько раз в другой модели, генератор кода помещает код функции в model.c для ссылочной модели. В этом примере генератор кода размещает код функции для multiinstfunc в slprj/ert/rtwdemo_func_dinteg/rtwdemo_func_dinteg.c.

    real_T rtwdemo_func_dinteg_multiinstfunc(RT_MODEL_rtwdemo_func_dinteg_T * const
      rtwdemo_func_dinteg_M, const real_T rtu_u)
    {
      real_T rtb_TmpLatchAtInOutport1;
      real_T rtb_TmpLatchAtIn2Outport1;
      real_T rty_y_0;
    
      rtb_TmpLatchAtInOutport1 =
        *rtwdemo_func_dinteg_M->rtwdemo_func_dintegrtextInport.rtu_In1;
    
      rtb_TmpLatchAtIn2Outport1 =
        *rtwdemo_func_dinteg_M->rtwdemo_func_dintegrtextInport.rtu_In2;
    
      *rtwdemo_func_dinteg_M->rtwdemo_func_dintegrtextOutport.rty_Out2 = 2.0 *
        rtb_TmpLatchAtInOutport1;
      
      rtwdemo_func_dinteg_func_calc(rtwdemo_func_dinteg_M, rtb_TmpLatchAtIn2Outport1,
        rtwdemo_func_dinteg_M->rtwdemo_func_dintegrtextOutport.rty_Out1);
    
      rty_y_0 = rtwdemo_func_dinteg_M->dwork.DiscreteIntegrator_DSTATE;
    
      rtwdemo_func_dinteg_M->dwork.DiscreteIntegrator_DSTATE += 0.1 * rtu_u;
      return rty_y_0;
    }
    
  • Код функции для блока функции Simulink, определенного в подсистеме

    Генератор кода помещает код функции для блока Simulink Function, который определяется в подсистеме в model.c для модели, содержащей подсистему. В этом примере генератор кода размещает код функции для func_calc в slprj/ert/rtwdemo_func_dinteg/rtwdemo_func_dinteg.c.

    void rtwdemo_func_dinteg_func_calc(RT_MODEL_rtwdemo_func_dinteg_T * const
      rtwdemo_func_dinteg_M, real_T rtu_u, real_T *rty_y)
    {
      rtwdemo_func_dinteg_M->dwork.calcMem =
        rtwdemo_func_dinteg_M->dwork.UnitDelay_DSTATE;
    
      *rty_y = rtwdemo_func_dinteg_M->dwork.UnitDelay_DSTATE;
    
      rtwdemo_func_dinteg_M->dwork.UnitDelay_DSTATE = rtu_u * 0.07;
    }
    
  • Структура, в которой хранятся данные нескольких экземпляров для многократно используемых функций

    Генератор кода использует структуру, аналогичную модели реального времени (RT_MODEL) структура данных для хранения многоэкземплярных данных, связанных с повторно используемой функцией. Генератор кода определяет структуру в slprj/ert/rtwdemo_func_dinteg/rtwdemo_func_dinteg.h.

    typedef struct rtwdemo_func_dinteg_tag_RTM RT_MODEL_rtwdemo_func_dinteg_T;
    
  • Код инициализации для многоэкземплярной ссылочной модели

    Для каждого экземпляра ссылочной модели, который включает в себя один и тот же блок Simulink Function, генератор кода создает код инициализации и функции запуска. Одна копия кода инициализации определена в slprj/ert/rtwdemo_func_dinteg/rtwdemo_func_dinteg.c.

    void rtwdemo_func_dinteg_Start(RT_MODEL_rtwdemo_func_dinteg_T *const
      rtwdemo_func_dinteg_M, const real_T *rtu_In1, const real_T *rtu_In2, real_T
      *rty_Out2, real_T *rty_Out1)
    {
      rtwdemo_func_dinteg_M->rtwdemo_func_dintegrtextInport.rtu_In1 = rtu_In1;
      rtwdemo_func_dinteg_M->rtwdemo_func_dintegrtextInport.rtu_In2 = rtu_In2;
      rtwdemo_func_dinteg_M->rtwdemo_func_dintegrtextOutport.rty_Out2 = rty_Out2;
      rtwdemo_func_dinteg_M->rtwdemo_func_dintegrtextOutport.rty_Out1 = rty_Out1;
    }
    
    void rtwdemo_func_dinteg_initialize(const char_T **rt_errorStatus,
      RT_MODEL_rtwdemo_func_dinteg_T *const rtwdemo_func_dinteg_M)
    {
      {
        rtmSetErrorStatusPointer(rtwdemo_func_dinteg_M, rt_errorStatus);
      }
    }
    

    Код инициализации вызывается для каждого экземпляра ссылочной модели, который содержит один и тот же блок функции Simulink. Этот код находится в файле rtwdemo_comp.c в папке построения.

    .
    .
    .
    rtwdemo_func_dinteg_initialize(rtmGetErrorStatusPointer(rtwdemo_comp_M),
      (&(rtwdemo_comp_M->Instance1)));
      
    rtwdemo_func_dinteg_initialize(rtmGetErrorStatusPointer(rtwdemo_comp_M),
      (&(rtwdemo_comp_M->Instance2)));
    
    rtwdemo_func_dinteg_Start((&(rtwdemo_comp_M->Instance1)), &rtU->In2, &rtU->In3,
      &rtY->Out2, &rtY->Out3);
      
    rtwdemo_func_dinteg_Start((&(rtwdemo_comp_M->Instance2)), &rtU->In4, &rtU->In5,
      &rtY->Out4, &rtY->Out5);
    }
    
  • Объявления основных функций точки входа модели

    Файл заголовка модели rtwdemo_comp.h включает extern объявления для функций начального уровня инициализации, завершения и выполнения (выполнения) верхней модели.

    extern void rtwdemo_comp_initialize(RT_MODEL_rtwdemo_comp_T *const
      rtwdemo_comp_M);
    
    extern void Run(RT_MODEL_rtwdemo_comp_T *const rtwdemo_comp_M);
    
  • Описания функций точек входа ссылочной модели

    Файл заголовка slprj/ert/rtwdemo_func_dinteg/rtwdemo_func_dinteg.h включает extern объявления для функций точек входа ссылочной модели.

    extern void rtwdemo_func_dinteg_initialize(const char_T **rt_errorStatus,
      RT_MODEL_rtwdemo_func_dinteg_T *const rtwdemo_func_dinteg_M);
    extern real_T rtwdemo_func_dinteg_multiinstfunc(RT_MODEL_rtwdemo_func_dinteg_T * 
      const rtwdemo_func_dinteg_M, const real_T rtu_u);
    extern void rtwdemo_func_dinteg_Start(RT_MODEL_rtwdemo_func_dinteg_T *const 
      rtwdemo_func_dinteg_M, const real_T *rtu_In1, const real_T *rtu_In2, real_T
      *rty_Out2, real_T *rty_Out1);
    

Создание и проверка кода C++

Создайте код C++ для модели.

  • Код функции для многоэкземплярного функционального блока Simulink

    При размещении блока функции Simulink в области в ссылочной модели, которая используется несколько раз в другой модели, генератор кода помещает код функции в model.cpp для ссылочной модели. В этом примере генератор кода размещает код функции для multiinstfunc в slprj/ert/rtwdemo_func_dinteg/rtwdemo_func_dinteg_cpp.cpp.

    real_T rtwdemo_func_dintegModelClass::multiinstfunc(const real_T rtu_u)
    {
      real_T rtb_TmpLatchAtInOutport1;
      real_T rtb_TmpLatchAtIn2Outport1;
      real_T rty_y_0;
    
      rtb_TmpLatchAtInOutport1 = *rtwdemo_func_dinteg_cprtrtu_In1;
    
      rtb_TmpLatchAtIn2Outport1 = *rtwdemo_func_dinteg_cprtrtu_In2;
    
      *rtwdemo_func_dinteg_crtrty_Out2 = 2.0 * rtb_TmpLatchAtInOutport1;
    
      rtwdemo_func_dinteg_c_func_calc(rtb_TmpLatchAtIn2Outport1,
        rtwdemo_func_dinteg_crtrty_Out1);
    
      rty_y_0 = rtwdemo_func_dinteg_cpprtDW.DiscreteIntegrator_DSTATE;
    
      rtwdemo_func_dinteg_cpprtDW.DiscreteIntegrator_DSTATE += 0.1 * rtu_u;
      return rty_y_0;
    }
  • Код функции для блока функции Simulink, определенного в подсистеме

    Генератор кода помещает код функции для блока Simulink Function, который определяется в подсистеме в model.cpp для модели, содержащей подсистему. В этом примере генератор кода размещает код функции для func_calc в slprj/ert/rtwdemo_func_dinteg/rtwdemo_func_dinteg_cpp.cpp.

    void rtwdemo_func_dintegModelClass::rtwdemo_func_dinteg_c_func_calc(real_T rtu_u,
      real_T *rty_y)
    {
      rtwdemo_func_dinteg_cpprtDW.calcMem =
        rtwdemo_func_dinteg_cpprtDW.UnitDelay_DSTATE;
    
      *rty_y = rtwdemo_func_dinteg_cpprtDW.UnitDelay_DSTATE;
    
      rtwdemo_func_dinteg_cpprtDW.UnitDelay_DSTATE = rtu_u * 0.07;
    }
    
  • Структура, в которой хранятся данные нескольких экземпляров для многократно используемых функций

    Генератор кода использует структуру, аналогичную модели реального времени (RT_MODEL) структура данных для хранения многоэкземплярных данных, связанных с Reusable function. Генератор кода определяет структуру в slprj/ert/rtwdemo_func_dinteg/rtwdemo_func_dinteg_cpp.h.

    typedef struct rtwdemo_func_dinteg_cpp_tag_RTM rtwdemo_func_dinteg_cp_RT_MODEL;
    
  • Код инициализации для многоэкземплярной ссылочной модели

    Для каждого экземпляра ссылочной модели, который включает в себя один и тот же блок Simulink Function, генератор кода создает код инициализации и функции запуска. Одна копия кода инициализации определена в slprj/ert/rtwdemo_func_dinteg/rtwdemo_func_dinteg_cpp.cpp.

    void rtwdemo_func_dintegModelClass::start(real_T *rtu_In1, real_T *rtu_In2,
      real_T *rty_Out2, real_T *rty_Out1)
    {
      rtwdemo_func_dinteg_cprtrtu_In1 = rtu_In1;
      rtwdemo_func_dinteg_cprtrtu_In2 = rtu_In2;
      rtwdemo_func_dinteg_crtrty_Out2 = rty_Out2;
      rtwdemo_func_dinteg_crtrty_Out1 = rty_Out1;
    }
    .
    .
    .
    void rtwdemo_func_dintegModelClass::initializeRTM()
    {
      (void) memset((void *)((&rtwdemo_func_dinteg_cpprtM)), 0,
                    sizeof(rtwdemo_func_dinteg_cp_RT_MODEL));
    }
    

    Код инициализации вызывается для каждого экземпляра ссылочной модели, который содержит один и тот же блок функции Simulink. Этот код находится в файле rtwdemo_comp_cpp.cpp в папке построения.

    .
    .
    .
    
    Instance1MDLOBJ0.initializeRTM();
    
    Instance1MDLOBJ0.setErrorStatusPointer(rtmGetErrorStatusPointer((&rtM)));
    Instance1MDLOBJ0.initialize();
    
    Instance2MDLOBJ1.initializeRTM();
    
    Instance2MDLOBJ1.setErrorStatusPointer(rtmGetErrorStatusPointer((&rtM)));
    	
    Instance1MDLOBJ0.start(&rtU.In2, &rtU.In3, &rtY.Out2, &rtY.Out3);
    
    Instance2MDLOBJ1.start(&rtwU.In4, &rtwU.In5, &rtY.Out4, &rtY.Out5);
    }
  • Объявление высшего класса модели

    Файл заголовка модели rtwdemo_comp_cpp.h включает объявление класса для модели верхнего уровня.

    class rtwdemo_compModelClass {
     public:
      ExtU rtU;
    
      ExtY rtY;
    
      void initialize();
    
      void Run();
    
      rtwdemo_compModelClass();
    
      ~rtwdemo_compModelClass();
    
      RT_MODEL * getRTM();
    
     private:
      RT_MODEL rtM;
    
      rtwdemo_func_dintegModelClass Instance1MDLOBJ0;
    
      rtwdemo_func_dintegModelClass Instance2MDLOBJ1;
    };
    
  • Объявление класса ссылочной модели

    Файл заголовка slprj/ert/rtwdemo_func_dinteg/rtwdemo_func_dinteg_cpp.h включает объявление класса для ссылочной модели.

    class rtwdemo_func_dintegModelClass {
     public:
      real_T multiinstfunc(const real_T rtu_u);
    
      void start(real_T *rtu_In1, real_T *rtu_In2, real_T *rty_Out2, real_T
    	            *rty_Out1);
    
      rtwdemo_func_dintegModelClass();
    	
      ~rtwdemo_func_dintegModelClass();
    
      rtwdemo_func_dinteg_cp_RT_MODEL * getRTM();
    
      void initializeRTM();
    
      void setErrorStatusPointer(const char_T **rt_errorStatus);
    
     private:
      rtwdemo_func_dinteg_cpp_DW rtwdemo_func_dinteg_cpprtDW;
    
      const real_T *rtwdemo_func_dinteg_cprtrtu_In1;
      const real_T *rtwdemo_func_dinteg_cprtrtu_In2;
      real_T *rtwdemo_func_dinteg_crtrty_Out2;
      real_T *rtwdemo_func_dinteg_crtrty_Out1;
    
      rtwdemo_func_dinteg_cp_RT_MODEL rtwdemo_func_dinteg_cpprtM;
    
      void rtwdemo_func_dinteg_c_func_calc(real_T rtu_u, real_T *rty_y);
    };

Ограничения

Эти ограничения на генерацию кода применяются к моделям export-function, которые включают несколько экземпляров блока Simulink Function.

  • Необходимо задать параметр конфигурации модели Pass root-level I/O как Part of model data structure.

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

  • Нельзя:

    • Создайте код, если модель export-function включает варианты модели.

    • Вызовите созданный код из диаграммы Stateflow ®.

    • Включите интерфейс обмена данными во внешнем режиме.

Связанные темы