Запишите S-функцию обертки и файлы TLC

Создайте S-функции, которые работают беспрепятственно с Simulink® и продуктами генератора кода при помощи концепции обертки. Вы можете:

  • Соедините интерфейсом со своими алгоритмами в моделях Simulink путем записи оберток S-функции MEX (sfunctionMEX).

  • Направьте генератор кода, чтобы вставить ваш алгоритм в сгенерированный код путем создания обертки S-функции TLC (sfunction.tlc).

Обертка S-функции MEX

Создание S-функций при помощи обертки S-функции позволяет вам вставить алгоритмы C/C++ кода в модели Simulink и сгенерированный код с минимальным изменением в вашей исходной функции C/C++. Оберткой S-функции MEX является S-функция, которая вызывает код, который находится в другом модуле.

Примечание

Используйте обертку S-функции MEX только в версии MATLAB®, в которой вы создали обертку.

Предположим, что у вас есть алгоритм (то есть, функция C) названный my_alg это находится в файле my_alg.c. Можно интегрировать my_alg в модель Simulink путем создания обертки S-функции MEX (например, wrapsfcn.c). Модель Simulink может затем вызвать my_alg от Блока s-function. S-функция Simulink содержит набор пустых функций, которых механизм Simulink требует в различных связанных с API целях. Например, несмотря на то, что только mdlOutputs вызовы my_alg, механизм вызывает mdlTerminate, даже при том, что эта стандартная программа S-функции не выполняет действия.

Можно встроить вызов my_alg в сгенерированном коде путем создания обертки S-функции TLC (например, wrapsfcn.tlc). Можно устранить пустые вызовы функции. Можно избежать издержек выполнения mdlOutputs функционируйте и можно затем устранить my_alg функция.

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

  • Интерпретирующий по своей природе (то есть, высоко параметрированный рабочими режимами)

  • В большой степени оптимизированный (то есть, никакие дополнительные тесты, чтобы решить то, чем режим код управляет в),

затем необходимо создать полностью встроенный файл TLC для S-функции.

Следующий рисунок показывает концепцию S-функции обертки.

Используя обертку S-функции, чтобы импортировать алгоритмы в вашу модель Simulink означает, что S-функция служит интерфейсом, который вызывает ваши алгоритмы C/C++ от mdlOutputs. Можно быстро интегрировать большие автономные программы C/C++ в модель, не имея необходимость изменять код.

Эта демонстрационная модель включает обертку S-функции.

Два файла сопоставлены с wrapsfcn блок: обертка S-функции и код C/C++, который содержит алгоритм. Первые три оператора:

  1. Задайте имя S-функции (что вы вводите в диалоговое окно Блока s-function Simulink).

  2. Укажите, что S-функция использует формат уровня 2.

  3. Обеспечьте доступ к SimStruct структура данных. SimStruct содержит указатели на данные, используемые в процессе моделирования и генерация кода, и задает макросы, которые хранят данные в и получают данные от SimStruct.

#define S_FUNCTION_NAME wrapsfcn
#define S_FUNCTION_LEVEL 2
#include "simstruc.h"

extern real_T my_alg(real_T u);  /* Declare my_alg as extern */

/*
 * mdlInitializeSizes - initialize the sizes array
 */
static void mdlInitializeSizes(SimStruct *S)
{

    ssSetNumSFcnParams( S, 0); /*number of input arguments*/

    if (!ssSetNumInputPorts(S, 1)) return;
    ssSetInputPortWidth(S, 0, 1);
    ssSetInputPortDirectFeedThrough(S, 0, 1);

    if (!ssSetNumOutputPorts(S,1)) return;
    ssSetOutputPortWidth(S, 0, 1);
    
    ssSetNumSampleTimes( S, 1);
}

/*
 * mdlInitializeSampleTimes - indicate that this S-function runs
 * at the rate of the source (driving block)
 */
static void mdlInitializeSampleTimes(SimStruct *S)
{
    ssSetSampleTime(S, 0, INHERITED_SAMPLE_TIME);
    ssSetOffsetTime(S, 0, 0.0);
} 


/*
 * mdlOutputs - compute the outputs by calling my_alg, which
 * resides in another module, my_alg.c
 */
static void mdlOutputs(SimStruct *S, int_T tid)
{
    InputRealPtrsType uPtrs = ssGetInputPortRealSignalPtrs(S,0);
    real_T            *y    = ssGetOutputPortRealSignal(S,0);
    *y = my_alg(*uPtrs[0]); /* Call my_alg in mdlOutputs */
 }
/*
 * mdlTerminate - called when the simulation is terminated.
 */
static void mdlTerminate(SimStruct *S)
{
}

#ifdef MATLAB_MEX_FILE /* Is this file being compiled as a MEX-file? */
#include "simulink.c" /* MEX-file interface mechanism */
#else
#include "cg_sfun.h" /* Code generation registration function */
#endif

Для получения дополнительной информации смотрите Шаблоны для S-функций C (Simulink).

Стандартная программа S-функции mdlOutputs содержит вызов функции к my_alg, который является функцией C, содержащей алгоритм, который выполняет S-функция. Для my_alg.c, код:

#ifdef MATLAB_MEX_FILE
#include "tmwtypes.h"
#else
#include "rtwtypes.h"
#endif
real_T my_alg(real_T u)
{
return(u * 2.0);
}

Для получения дополнительной информации смотрите, Управляют Зависимостями от Файла Процесса сборки.

S-функция обертки wrapsfcn вызовы my_alg, который вычисляет u * 2.0. Создавать wrapsfcn.mex, используйте эту команду:

mex wrapsfcn.c my_alg.c

Обертка TLC S-функции

Обертка S-функции TLC является файлом TLC, который задает, как генератор кода вызывает ваш код. Например, можно встроить вызов my_alg в mdlOutputs раздел сгенерированного кода. В примере Обертки S-функции MEX, вызове my_alg встраивается в mdlOutputs разделите как:

*y = my_alg(*uPtrs[0]);

Когда вы создаете обертку S-функции TLC, цель состоит в том, чтобы встроить тот же тип вызова в сгенерированном коде.

Посмотрите на то, как генератор кода выполняет S-функции, которые не встраиваются. Невстроенная S-функция идентифицирована отсутствием файла sfunction.tlc и существование sfunctionMEX. При генерации кода для невстроенной S-функции генератор кода производит вызов mdlOutputs через указатель функции, что, в этом примере, затем вызывает my_alg.

Пример обертки содержит одну S-функцию, wrapsfcn.mex. Необходимо скомпилировать и соединить дополнительный модуль, my_alg, со сгенерированным кодом. В командной строке MATLAB введите:

set_param('wrapper/S-Function','SFunctionModules','my_alg')

Код наверху для невстроенных S-функций

Код сгенерирован при использовании grt.tlc как системный конечный файл без wrapsfcn.tlc :

<Generated code comments for wrapper model with noninlined wrapsfcn S-function>

#include <math.h>
#include <string.h>
#include "wrapper.h"
#include "wrapper.prm"

/* Start the model */
void mdlStart(void)
{
  /* (start code not required) */
}

/* Compute block outputs */
void mdlOutputs(int_T tid)
{
  /* Sin Block: <Root>/Sin */
  rtB.Sin = rtP.Sin.Amplitude *
    sin(rtP.Sin.Frequency * ssGetT(rtS) + rtP.Sin.Phase);

  /* Level2 S-Function Block: <Root>/S-Function (wrapsfcn) */
 {
    /* Noninlined S-functions create a SimStruct object and
     * generate a call to S-function routine mdlOutputs
     */
    SimStruct *rts = ssGetSFunction(rtS, 0);
    sfcnOutputs(rts, tid);
  }

  /* Outport Block: <Root>/Out */
  rtY.Out = rtB.S_Function;
}

/* Perform model update */
void mdlUpdate(int_T tid)
{
  /* (update code not required) */
}

/* Terminate function */
void mdlTerminate(void)
{
  /* Level2 S-Function Block: <Root>/S-Function (wrapsfcn) */
  {
/* Noninlined S-functions require a SimStruct object and
     * the call to S-function routine mdlTerminate
     */
    SimStruct *rts = ssGetSFunction(rtS, 0);
    sfcnTerminate(rts);
  }
}

#include "wrapper.reg"

/* [EOF] wrapper.c */

wrapper.reg сгенерированный файл содержит инициализацию SimStruct для Блока s-function обертки. Существует один дочерний SimStruct для каждого Блока s-function в вашей модели. Можно значительно уменьшать эти издержки путем создания обертки TLC для S-функции.

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

Сгенерированный код выполняет вызов к вашей S-функции, wrapsfcn.c, в mdlOutputs при помощи этого кода:

SimStruct *rts = ssGetSFunction(rtS, 0);
sfcnOutputs(rts, tid);

Этот вызов имеет вычислительные издержки, сопоставленные с ним. Механизм Simulink создает SimStruct структура данных для Блока s-function. Генератор кода создает вызов через указатель функции, чтобы выполнить mdlOutputs, затем mdlOutputs вызовы my_alg. Путем встраивания вызова алгоритма C/C++, my_alg, можно устранить обоих SimStruct и дополнительный вызов функции, таким образом, повышая эффективность и уменьшая размер сгенерированного кода.

Встраивание S-функции обертки требует sfunction.tlc файл для S-функции. Файл TLC должен содержать вызов функции к my_alg. Рисунок показывает отношения между алгоритмом, S-функцией обертки и sfunction.tlc файл.

Встраивать вызов my_alg, поместите свой вызов функции в sfunction.tlc файл с тем же именем как S-функция (в этом примере, wrapsfcn.tlc). Компилятор Выходного языка заменяет метод по умолчанию размещения вызовов вашей S-функции в сгенерированном коде.

Этот код является файлом TLC wrapsfcn.tlc это встраивает wrapsfcn.c:

%% File    : wrapsfcn.tlc
%% Abstract:
%%      Example inlined tlc file for S-function wrapsfcn.c
%%

%implements "wrapsfcn" "C"

%% Function: BlockTypeSetup ====================================================
%% Abstract:
%%      Create function prototype in model.h as:
%%      "extern real_T my_alg(real_T u);" 
%%
%function BlockTypeSetup(block, system) void
  %openfile buffer
    extern real_T my_alg(real_T u); /* This line is placed in wrapper.h */
  %closefile buffer
  %<LibCacheFunctionPrototype(buffer)>
%endfunction %% BlockTypeSetup

%% Function: Outputs ===========================================================
%% Abstract:
%%      y = my_alg( u );
%%
%function Outputs(block, system) Output
  /* %<Type> Block: %<Name> */
  %assign u = LibBlockInputSignal(0, "", "", 0)
  %assign y = LibBlockOutputSignal(0, "", "", 0)
  %% PROVIDE THE CALLING STATEMENT FOR "algorithm"
  %% The following line is expanded and placed in mdlOutputs within wrapper.c
  %<y> = my_alg(%<u>); 

%endfunction %% Outputs

Первый раздел этого кода встраивает wrapsfcn Блок s-function и генерирует код в C:

%implements "wrapsfcn" "C"

Следующая задача состоит в том, чтобы сообщить генератору кода что стандартный my_alg должен быть объявлен как внешний в сгенерированном wrapper.h файл для любого wrapsfcn Блоки s-function в модели. Сделайте это объявление однажды для всего wrapsfcn Блоки s-function при помощи BlockTypeSetup функция. В этой функции вы направляете Компилятор Выходного языка, чтобы создать буфер и кэшировать my_alg как extern в wrapper.h сгенерированный заголовочный файл.

Последний шаг является встраиванием вызова функционального my_alg. Outputs функция встраивает вызов. В этой функции вы получаете доступ к вводу и выводу блока и помещаете прямой вызов my_alg. Вызов встраивается в wrapper.c.

Встроенный код

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

void mdlOutputs(int_T tid)
{
  /* Sin Block: <Root>/Sin */
  rtB.Sin = rtP.Sin.Amplitude *
    sin(rtP.Sin.Frequency * ssGetT(rtS) + rtP.Sin.Phase);

  /* S-Function Block: <Root>/S-Function */
  rtB.S_Function = my_alg(rtB.Sin); /* Inlined call to my_alg */

  /* Outport Block: <Root>/Out */
  rtY.Out = rtB.S_Function;
}

wrapper.reg не создает дочерний SimStruct для S-функции, потому что сгенерированный код вызывает my_alg непосредственно, устраняя более чем 1 Кбайт использования памяти.

Похожие темы