Создайте 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 КБ.