Встройте S-функции MEX C

Встроенный обзор S-функции

Когда модель Simulink® содержит S-функцию, и соответствующий конечный файл блока TLC существует для той S-функции, генератор кода встраивает S-функцию. Встраивание S-функции может произвести более эффективный код путем устранения слоя API S-функции из сгенерированного кода.

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

Уровень 1 C S-функции MEX (записанный в более старую форму API S-функции), которые не встраиваются, заставят сгенерированный код выполнять вызовы ко всем этим функциям, даже если стандартная программа будет пуста для конкретной S-функции.

ФункцияЦель

mdlInitializeSizes

Инициализируйте массив размеров

mdlInitializeSampleTimes

Инициализируйте массив шагов расчета

mdlInitializeConditions

Инициализируйте состояния

mdlOutputs

Вычислите выходные параметры

mdlUpdate

Обновите дискретные состояния

mdlDerivatives

Вычислите производные непрерывных состояний

mdlTerminate

Вымойтесь, когда симуляция завершит работу

Уровень 2 C S-функции MEX (т.е. записанные в текущий API S-функции), которые не встраиваются, выполняют вызовы к вышеупомянутым функциям за следующими исключениями:

  • mdlInitializeConditions называется только если MDL_INITIALIZE_CONDITIONS объявляется с #define.

  • mdlStart называется только если MDL_START объявляется с #define.

  • mdlUpdate называется только если MDL_UPDATE объявляется с #define.

  • mdlDerivatives называется только если MDL_DERIVATIVES объявляется с #define.

Путем встраивания S-функции можно устранить вызовы их возможно пустые функции в цикле симуляции. Это может значительно повысить эффективность сгенерированного кода.

Встраивать S-функцию под названием sfuncИмя, вы создаете пользовательский конечный файл Блока s-function под названием sfunc_name.tlc и поместите его в ту же папку как файл MEX S-функции. Затем во время изготовления конечный файл выполняется вместо того, чтобы настроить вызовы функции в S-функцию .c файл. Конечный файл S-функции “встраивает” S-функцию путем направления Компилятора Выходного языка, чтобы вставить только операторы, заданные в конечном файле.

В общем случае встраивание S-функции особенно полезно когда

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

  • Определенные стандартные программы S-функции пусты (например, mdlUpdate).

  • Поведение S-функции изменяется между симуляцией и генерацией кода. Например, S-функции ввода-вывода драйвера устройства могут читать из рабочей области MATLAB® в процессе моделирования, но читать из фактического аппаратного адреса в сгенерированном коде.

S-параметры-функции

S-функция может записать два различных типов параметров в model.rtw файл для файлов Компилятора Выходного языка для доступа:

  • Установки параметров: Они соответствуют ненастраиваемым параметрам (обычно установленный от флажков и меню на S-функции маскированной), которые записаны через mdlRTW метод S-функции с помощью ssWriteRTWParamSettings. Файл реализации S-function TLC может затем непосредственно получить доступ к значениям этих установок параметров от SFcnParamSettings запись в блоке.

  • Настраиваемые параметры: к Этому классу параметров можно получить доступ, когда они указаны как параметры периода выполнения в S-функции. Обратите внимание на то, что такие настраиваемые параметры автоматически выписаны к model.rtw файл. В файле TLC для S-функции можно получить доступ к параметрам периода выполнения и их атрибутам с помощью LibBlockParameter библиотечная функция и ее варианты.

Для получения дополнительной информации о том, как создать и использовать параметры периода выполнения, видит, Создают и Параметры периода выполнения S-функции Обновления (Simulink). Также смотрите пример sfcndemo_runtime в примерах S-функции для того, как создать и использовать два класса параметров. Исходные файлы в качестве примера, которые можно смотреть и адаптировать,

Пример кода для S-функции

Предположим, что у вас есть простая S-функция, которая подражает блоку Gain, с одним входом, одним выходом и скалярным усилением. Таким образом, y = u * p. Если именем блока Simulink является foo и именем S-функции Уровня 2 является foogain, S-функция MEX C должна содержать этот код:

#define S_FUNCTION_NAME foogain
#define S_FUNCTION_LEVEL 2
#include "simstruc.h"
#define GAIN mxGetPr(ssGetSFcnParam(S,0))[0]

static void mdlInitializeSizes(SimStruct *S)
{
  ssSetNumContStates		(S, 0);
  ssSetNumDiscStates		(S, 0);
  
  if (!ssSetNumInputPorts(S, 1)) return;
  ssSetInputPortWidth            (S, 0, 1);
  ssSetInputPortDirectFeedThrough(S, 0, 1);
  
  if (!ssSetNumOutputPorts(S, 1)) return;
  ssSetOutputPortWidth          (S, 0, 1);
  
  ssSetNumSFcnParams		(S, 1);
  ssSetNumSampleTimes		(S, 0);  
  ssSetNumIWork		(S, 0);
  ssSetNumRWork		(S, 0);
  ssSetNumPWork		(S, 0);
}
 
static void
mdlOutputs(SimStruct *S, int_T tid)
{
  real_T *y = ssGetOutputPortRealSignal(S, 0);
  const InputRealPtrsType u = ssGetInputPortRealSignalPtrs(S, 0);

  y[0] = (*u)[0] * GAIN;
}

static void
mdlInitializeSampleTimes(SimStruct *S){}

static void
mdlTerminate(SimStruct *S) {}

#define MDL_RTW  /* Change to #undef to remove function */
#if defined(MDL_RTW)&&(defined(MATLAB_MEX_FILE)||defined(NRT))
static void
mdlRTW (SimStruct *S)
{
  if (!ssWriteRTWParameters(S, 1,SSWRITE_VALUE_VECT,"Gain","",
                            mxGetPr(ssGetSFcnParam(S,0)),1)) 
  {
    return;
  }
}
#endif

#ifdef  MATLAB_MEX_FILE
#include "simulink.c" 
#else
#include "cg_sfun.h"
#endif

Следующие два раздела показывают различие в сгенерированном коде для modelC содержа невстроенные и встроенные версии S-функции foogain. Модель не содержит никакие другие блоки Simulink.

Для получения дополнительной информации о них S-функция связанные библиотечные функции C, смотрите, Конфигурируют Функции S-функции C/C++ (Simulink). Для получения информации о том, как сгенерировать код, смотрите, Конфигурируют Модель и Генерируют Код и Выбирают Build Approach и Configure Build Process.

Сравнение Невстроенных и Встроенных Версий model.c

Без файла TLC, чтобы задать специфические особенности S-функции, генератор кода должен вызвать S-функцию файла MEX через API S-функции. Следующим кодом является modelC файл для невстроенной S-функции (т.е. никакой соответствующий файл TLC существует).

Невстроенная S-функция

/*
 * model.c
.
.
.
*/
real_T untitled_RGND = 0.0;             /* real_T ground */
/* Start the model */
void MdlStart(void)
{
  /* (no start code required) */
}
/* Compute block outputs */
void MdlOutputs(int_T tid)
{
  /* Level2 S-Function Block: <Root>/S-Function (foogain) */
  {
    SimStruct *rts = ssGetSFunction(rtS, 0);
    sfcnOutputs(rts, tid);
  }
}
/* Perform model update */
void MdlUpdate(int_T tid)
{
  /* (no update code required) */
}
/* Terminate function */
void MdlTerminate(void)
{
  /* Level2 S-Function Block: <Root>/S-Function (foogain) */
  {
    SimStruct *rts = ssGetSFunction(rtS, 0);
    sfcnTerminate(rts);
  }
}
#include "model_reg.h"
/* [EOF] model.c */

Встроенная S-функция.  Этим кодом является modelC с foogain S-функция полностью встроила:

/*
 * model.c
.
.
.
*/
/* Start the model */
void MdlStart(void)
{
  /* (no start code required) */
}

/* Compute block outputs */
void MdlOutputs(int_T tid)

  /* S-Function block: <Root>/S-Function */
  /* NOTE: There are no calls to the S-function API in the inlined 
     version of model.c. */
  rtB.S_Function = 0.0 * rtP.S_Function_Gain;
}

/* Perform model update */
void MdlUpdate(int_T tid)
{
  /* (no update code required) */
}

/* Terminate function */
void MdlTerminate(void)
{
  /* (no terminate code required) */
}

#include "model_reg.h"

/* [EOF] model.c */

Если вы включаете этот конечный файл для этого Блока s-function, получившегося modelC код

rtB.S_Function = 0.0 * rtP.S_Function_Gain;

Включая файл TLC решительно уменьшил размер кода и увеличил КПД выполнения сгенерированного кода. Эти примечания подсвечивают некоторую информацию о коде TLC и сгенерированном выходе:

  • Направляющий %implements TLC требуется конечными файлами блока и должен быть первый исполняемый оператор в конечном файле блока. Эта директива препятствует тому, чтобы Компилятор Выходного языка выполнил несоответствующий конечный файл для S-функции foogain.

  • Вход к foo rtGROUND (глобальная переменная Simulink Coder™ равняется 0,0), потому что foo единственный блок в модели, и ее вход не связан.

  • Включая файл TLC для foogain избавляет от необходимости регистрационный сегмент S-функции для foogain. Это значительно уменьшает размер кода.

  • Код TLC встраивает gain параметр, когда процесс сборки сконфигурирован, чтобы встроить значения параметров. Например, если S-параметр-функции задан как 2,5 в диалоговом окне S-функции, Outputs TLC функция генерирует

    rtB.foo = input * 2.5;
  • Используйте %generatefile директивой, если ваша операционная система имеет ограничение размера имени файла и имя S-функции, является foosfunction (который превышает предел). В этом случае вы включали бы следующий оператор в системный конечный файл (где угодно до ссылки на этот конечный файл Блока s-function).

    %generatefile foosfunction "foosfunc.tlc"

    Этот оператор говорит Компилятору Выходного языка открывать foosfunc.tlc вместо foosfunction.tlc.

Сравнение Невстроенных и Встроенных Версий model_reg.h

Встраивание S-функции Уровня 2 значительно уменьшает размер model_reg.h код. Регистрационные функции модели долги; большая часть кода была устранена в этом примере. Код ниже подсвечивает различие между невстроенными и встроенными версиями model_reg.h; встраивание устраняет этот код:

/*
 * model_reg.h
 *
*/
/* Normal model initialization code independent of 
      S-functions  */

/* child S-Function registration */
  ssSetNumSFunctions(rtS, 1);

  /* register each child */
  {
    static SimStruct childSFunctions[1];
    static SimStruct *childSFunctionPtrs[1];

    (void)memset((char_T *)&childSFunctions[0], 0, 
                  sizeof(childSFunctions));
    ssSetSFunctions(rtS, &childSFunctionPtrs[0]);
    {
      int_T i;

      for(i = 0; i < 1; i++) {
        ssSetSFunction(rtS, i, &childSFunctions[i]);
      }
    }

    /* Level2 S-Function Block: untitled/<Root>/S-Function 
       (foogain) */
    {
      extern void foogain(SimStruct *rts);
      SimStruct *rts = ssGetSFunction(rtS, 0);

      /* timing info */
      static time_T sfcnPeriod[1];
      static time_T sfcnOffset[1];
      static int_T sfcnTsMap[1];

      {
        int_T i;

        for(i = 0; i < 1; i++) {
          sfcnPeriod[i] = sfcnOffset[i] = 0.0;
        }
      }
      ssSetSampleTimePtr(rts, &sfcnPeriod[0]);
      ssSetOffsetTimePtr(rts, &sfcnOffset[0]);
      ssSetSampleTimeTaskIDPtr(rts, sfcnTsMap);
      ssSetMdlInfoPtr(rts, ssGetMdlInfoPtr(rtS));

      /* inputs */
      {
        static struct _ssPortInputs inputPortInfo[1];

        _ssSetNumInputPorts(rts, 1);
        ssSetPortInfoForInputs(rts, &inputPortInfo[0]);

        /* port 0 */
        {
          static real_T const *sfcnUPtrs[1];

          sfcnUPtrs[0] = &untitled_RGND;
          ssSetInputPortWidth(rts, 0, 1);
          ssSetInputPortSignalPtrs(rts, 0, 
              (InputPtrsType)&sfcnUPtrs[0]);
        }
      }

      /* outputs */
      {
        static struct _ssPortOutputs outputPortInfo[1];
        _ssSetNumOutputPorts(rts, 1);
        ssSetPortInfoForOutputs(rts, &outputPortInfo[0]);
        ssSetOutputPortWidth(rts, 0, 1);
        ssSetOutputPortSignal(rts, 0, &rtB.S_Function);
      }

      /* path info */
      ssSetModelName(rts, "S-Function");
      ssSetPath(rts, "untitled/S-Function");
      ssSetParentSS(rts, rtS);
      ssSetRootSS(rts, ssGetRootSS(rtS));
      ssSetVersion(rts, SIMSTRUCT_VERSION_LEVEL2);

      /* parameters */
      {
        static mxArray const *sfcnParams[1];

        ssSetSFcnParamsCount(rts, 1);
        ssSetSFcnParamsPtr(rts, &sfcnParams[0]);

        ssSetSFcnParam(rts, 0, &rtP.S_Function_P1Size[0]);
      }

      /* registration */
      foogain(rts);

      sfcnInitializeSizes(rts);
      sfcnInitializeSampleTimes(rts);

      /* adjust sample time */
      ssSetSampleTime(rts, 0, 0.2);
      ssSetOffsetTime(rts, 0, 0.0);
      sfcnTsMap[0] = 0;

      /* Update the InputPortReusable and BufferDstPort flags for 
        each input port */
      ssSetInputPortReusable(rts, 0, 0);
      ssSetInputPortBufferDstPort(rts, 0, -1);

      /* Update the OutputPortReusable flag of each output port */
    }
  }

Файл TLC, чтобы Встроить S-функцию foogain

Избегать ненужных вызовов S-функции и генерировать минимальный код, требуемый для S-функции, следующего файла TLC, foogain.tlc, обеспечивается как пример.

%implements "foogain" "C"

%function Outputs (block, system) Output
  /* %<Type> block: %<Name> */
  %%
  %assign y = LibBlockOutputSignal (0, "", "", 0)
  %assign u = LibBlockInputSignal (0, "", "", 0)
  %assign p = LibBlockParameter (Gain, "", "", 0)
  %<y> = %<u> * %<p>;
%endfunction

Данные об экземпляре блока управления глазом к генерации кода

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

Выделение и использование памяти на основе экземпляра экземпляром могут быть сделаны несколько путей в S-функции Уровня 2: через ssSetUserData, работайте векторы (например, ssSetRWorkValue, ssSetIWorkValue), или введенные данными векторы работы, известные как DWork векторы. Для самого маленького усилия в записи S-функции и конечного файла блока и для автоматического соответствия и к статическому и к malloc данные об экземпляре по целям, таким как grt, используйте введенные данными векторы работы при записи S-функций с данными об экземпляре.

Преимущества являются двукратными. Во-первых, запись S-функции является более прямой, в этом выделения памяти и освобождает, обработаны для вас Simulink. Во-вторых, DWork векторы записаны в model.rtw файл для вас автоматически, включая DWork имя, тип данных и размер. Это делает запись конечного файла блока легче, потому что вы не должны писать код TLC для выделения и освобождения DWork memory.

Кроме того, если вы хотите связать группы DWork векторы в структуры для передачи функциям, можно заполнить структуру с указателями на DWork массивы в обеих ваших S-функциях mdlStart функционируйте и конечный файл блока Start метод, достигая непротиворечивости между S-функцией и обработкой сгенерированного кода данных.

Наконец, использование DWork делает его прямым, чтобы создать определенную версию кода (типы данных, скаляр по сравнению с векторизованным, и т.д.) для каждого экземпляра блока, который совпадает с реализацией в S-функции. Обе реализации используют DWork таким же образом так, чтобы встроенный код может использоваться с программным обеспечением Simulink Accelerator™ без изменений в S-функции MEX C или конечном файле блока.

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

По умолчанию программное обеспечение Simulink Accelerator вызывает вашу S-функцию MEX C как часть ускоренной симуляции модели. Если вы предпочитаете иметь акселератор, встраивают вашу S-функцию прежде, чем запустить ускоренную модель, говорят акселератору использовать ваш конечный файл блока, чтобы встроить S-функцию с SS_OPTION_USE_TLC_WITH_ACCELERATOR отметьте в вызове ssSetOptions() в mdlInitializeSizes функция той S-функции.

Обратите внимание на то, что память и работает, размер вектора и использование должны быть тем же самым для сгенерированного кода TLC и S-функции MEX C, или программное обеспечение Simulink Accelerator не может выполнить встроенный код правильно. Это вызвано тем, что S-функция MEX C называется, чтобы инициализировать блок и его векторы работы, вызывая mdlInitializeSizes, mdlInitializeConditions, mdlCheckParameters, mdlProcessParameters, и mdlStart функции. В случае постоянного распространения сигнала, mdlOutputs называется от S-функции MEX C во время фазы инициализации выполнения модели.

Во время продвигающейся во время фазы ускоренного выполнения модели код сгенерирован Output и Update методы блока TLC выполнятся плюс Derivatives и методы пересечения нулем, если они существуют. Start метод конечного файла блока не используется в генерации кода для ускоренной модели.

Похожие темы