Создайте S-функции, которые работают без проблем с Simulink® и продукты генератора кода при помощи концепции обертки. Вы можете:
Интерфейсируйте свои алгоритмы в моделях Simulink, записывая оболочки MEX S-функции ().sfunction.mex
Направьте генератор кода, чтобы вставить ваш алгоритм в сгенерированный код, создав оболочку S-функции TLC ().sfunction.tlc
Создание 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 + +, который содержит алгоритм. Первые три операторов:
Определите имя S-функции (что вы вводите в диалоговом окне Simulink S-Function block).
Укажите, что S-функция использует формат уровня 2.
Обеспечьте доступ к 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 является файлом TLC, который задает, как генератор кода вызывает ваш код. Для примера можно вписать вызов в my_alg в mdlOutputs раздел сгенерированного кода. В примере MEX S-Function Wrapper вызов на my_alg встроена в mdlOutputs раздел как:
*y = my_alg(*uPtrs[0]);
Когда вы создаете оболочку S-функции TLC, цель состоит в том, чтобы встраивать тот же тип вызова в сгенерированный код.
Посмотрите, как генератор кода выполняет S-функции, которые не встроены. Нелинейная S-функция идентифицируется отсутствием файла и существование sfunction.tlc. При генерации кода для неинлинфицированной S-функции генератор кода производит вызов на sfunction.mexmdlOutputs через указатель на функцию, который в этом примере затем вызывает my_alg.
Пример оболочки содержит одну S-функцию, wrapsfcn.mex. Необходимо скомпилировать и связать дополнительный модуль, my_alg, с сгенерированным кодом. В командной строке MATLAB введите:
set_param('wrapper/S-Function','SFunctionModules','my_alg')
Код, сгенерированный при использовании 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-функции, 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-функции оболочки требуется файл для S-функции. Файл TLC должен содержать вызов функции на sfunction.tlcmy_alg. Рисунок показывает отношения между алгоритмом, S-функцией оболочки и файл.sfunction.tlc

Для ввода вызова в my_alg, поместите вызов функции в файл с таким же именем, что и S-функция (в этом примере sfunction.tlcwrapsfcn.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 КБ.