Запись файлов S-функции и TLC оболочки

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

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

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

MEX S-Function Wrapper

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

Примечание

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

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

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

S-функции Wrapper полезны, когда вы создаете алгоритмы, которые являются процедурными или когда вы интегрируете унаследованный код в модель 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 */

The 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 что 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-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 КБ.

Похожие темы