exponenta event banner

S-функция оболочки записи и файлы TLC

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

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

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

Оболочка S-функции MEX

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

Примечание

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

Предположим, что у вас есть алгоритм (то есть функция C) под названием my_alg который находится в файле my_alg.c. Вы можете интегрировать my_alg в модель Simulink путем создания оболочки MEX S-функции (например, wrapsfcn.c). Модель Simulink может вызвать my_alg из S-функционального блока. 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-функции (то, что вводится в диалоговом окне Simulink S-Function block).

  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

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

Подпрограмма 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

Оболочка S-функции TLC

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

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

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

Посмотрите, как генератор кода выполняет S-функции, которые не встроены. Неинлинная S-функция идентифицируется отсутствием файла sfunction.tlc и существование sfunction.mex. При генерации кода для неинлинной 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-функционального блока в модели. Можно значительно сократить эти издержки, создав оболочку 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 что inlines 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-Функциональный блок и генерирует код в C:

%implements "wrapsfcn" "C"

Следующая задача - сообщить генератору кода, что подпрограмма my_alg должен быть объявлен как внешний в сгенерированном wrapper.h файл для любого wrapsfcn S - функциональные блоки в модели. Сделать это объявление один раз для всех wrapsfcn S-функциональные блоки с помощью 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 КБ памяти.

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