Когда модель Simulink ® содержит S-функцию и для этой S-функции существует соответствующий целевой файл блока TLC, генератор кода встраивает S-функцию. Встраивание S-функции может обеспечить более эффективный код путем исключения уровня API S-функции из сгенерированного кода .
Для S-функций, которые могут выполнять различные задачи, их встраивание дает возможность создавать код только для текущего режима работы, установленного для каждого экземпляра блока. В качестве примера, если S-функция принимает произвольную ширину сигнала и закольцовывает каждый элемент сигнала, необходимо создать встроенный код, который имеет закольцовывания, когда сигнал имеет два или более элементов, но генерирует простое не закольцованное вычисление, когда сигнал имеет только один элемент.
S-функции уровня 1 C MEX (записанные в более старую форму API S-функции), которые не встроены, заставят сгенерированный код вызывать все эти функции, даже если процедура для конкретной S-функции пуста.
| Функция | Цель |
|---|---|
Инициализация массива размеров | |
Инициализация массива времени выборки | |
Инициализация состояний | |
Вычислить выходные данные | |
Обновление дискретных состояний | |
Вычисление производных непрерывных состояний | |
Очистка после завершения моделирования |
S-функции уровня 2 C MEX (т.е. те, которые записаны в текущий API S-функции), которые не встроены, выполняют вызовы вышеупомянутых функций, за следующими исключениями:
mdlInitializeConditions вызывается только в том случае, если MDL_INITIALIZE_CONDITIONS объявлен с помощью #define.
mdlStart вызывается только в том случае, если MDL_START объявлен с помощью #define.
mdlUpdate вызывается только в том случае, если MDL_UPDATE объявлен с помощью #define.
mdlDerivatives вызывается только в том случае, если MDL_DERIVATIVES объявлен с помощью #define.
Встраивая S-функцию, можно исключить вызовы этих, возможно, пустых функций в цикле моделирования. Это может значительно повысить эффективность генерируемого кода.
Для включения S-функции с именем , создается пользовательский целевой файл S-функционального блока с именем sfunc_name и поместите его в ту же папку, что и MEX-файл S-функции. Затем во время построения целевой файл выполняется вместо установки вызовов функции в S-функцию. sfunc_name.tlc.c файл. Целевой файл S-функции «встроен» в S-функцию, указывая компилятору целевого языка вставлять только инструкции, определенные в целевом файле.
В общем, встраивание S-функции особенно полезно, когда
Время, необходимое для выполнения содержимого S-функции, невелико по сравнению со служебными данными, необходимыми для вызова S-функции.
Некоторые процедуры S-функций пусты (например, mdlUpdate).
Поведение S-функции изменяется между моделированием и генерацией кода. Например, S-функции ввода-вывода драйвера устройства могут считываться из рабочего пространства MATLAB ® во время моделирования, но считываться с фактического аппаратного адреса в сгенерированном коде.
S-функция может записывать два различных типа параметров в файл для файлов компилятора целевого языка для доступа:model.rtw
Параметры настройки: Они соответствуют неперестраиваемым параметрам (обычно установленным из флажков и меню на маскированной S-функции), которые записываются через mdlRTW способ S-функции с использованием ssWriteRTWParamSettings. Затем файл реализации TLC S-функции может непосредственно обращаться к значениям этих настроек параметров из SFcnParamSettings запись в блоке.
Настраиваемые параметры: К этому классу параметров можно получить доступ, если они зарегистрированы как параметры времени выполнения в S-функции. Обратите внимание, что такие настраиваемые параметры автоматически записываются в файл. В файле TLC для S-функции можно получить доступ к параметрам времени выполнения и их атрибутам с помощью model.rtwLibBlockParameter библиотечная функция и ее варианты.
Дополнительные сведения о создании и использовании параметров времени выполнения см. в разделе Создание и обновление параметров времени выполнения S-функции. Также см. пример sfcndemo_runtime в примерах S-функций для создания и использования двух классов параметров. Примеры исходных файлов, которые можно проверить и адаптировать:
toolbox/simulink/simdemos/simfeatures/src/sfun_runtime1.c
toolbox/simulink/simdemos/simfeatures/tlc_c/sfun_runtime1.tlc
toolbox/simulink/simdemos/simfeatures/src/sfun_runtime2.c
toolbox/simulink/simdemos/simfeatures/tlc_c/sfun_runtime2.tlc
toolbox/simulink/simdemos/simfeatures/src/sfun_runtime3.c
toolbox/simulink/simdemos/simfeatures/tlc_c/sfun_runtime3.tlc
Предположим, что у вас есть простая S-функция, которая имитирует блок усиления, с одним входом, одним выходом и скалярным усилением. То есть y = u * p. Если именем блока Simulink является foo и имя S-функции уровня 2: foogain, S-функция C MEX должна содержать следующий код:
#define S_FUNCTION_NAME foogain
#define S_FUNCTION_LEVEL 2
#include "simstruc.h"
#define GAIN mxGetPr(ssGetSFcnParam(S,0))[0]
static void mdlInitializeSizes(SimStruct *S)
{
ssSetNumContStates (S, 0);
ssSetNumDiscStates (S, 0);
if (!ssSetNumInputPorts(S, 1)) return;
ssSetInputPortWidth (S, 0, 1);
ssSetInputPortDirectFeedThrough(S, 0, 1);
if (!ssSetNumOutputPorts(S, 1)) return;
ssSetOutputPortWidth (S, 0, 1);
ssSetNumSFcnParams (S, 1);
ssSetNumSampleTimes (S, 0);
ssSetNumIWork (S, 0);
ssSetNumRWork (S, 0);
ssSetNumPWork (S, 0);
}
static void
mdlOutputs(SimStruct *S, int_T tid)
{
real_T *y = ssGetOutputPortRealSignal(S, 0);
const InputRealPtrsType u = ssGetInputPortRealSignalPtrs(S, 0);
y[0] = (*u)[0] * GAIN;
}
static void
mdlInitializeSampleTimes(SimStruct *S){}
static void
mdlTerminate(SimStruct *S) {}
#define MDL_RTW /* Change to #undef to remove function */
#if defined(MDL_RTW)&&(defined(MATLAB_MEX_FILE)||defined(NRT))
static void
mdlRTW (SimStruct *S)
{
if (!ssWriteRTWParameters(S, 1,SSWRITE_VALUE_VECT,"Gain","",
mxGetPr(ssGetSFcnParam(S,0)),1))
{
return;
}
}
#endif
#ifdef MATLAB_MEX_FILE
#include "simulink.c"
#else
#include "cg_sfun.h"
#endifВ следующих двух разделах показана разница в сгенерированном коде для содержащий неинлайнированные и встроенные версии S-функции model.cfoogain. Модель не содержит других блоков Simulink.
Дополнительные сведения об этих функциях библиотеки C, связанных с S-функциями, см. в разделе Настройка функций C/C + + S-функций. Дополнительные сведения о создании кода см. в разделах Настройка модели и Создание кода, а также Выбор подхода построения и настройка процесса построения.
Без файла TLC для определения специфики S-функции генератор кода должен вызвать S-функцию MEX-файла через API S-функции. Следующий код: файл для неинлинной S-функции (т.е. соответствующий файл TLC не существует).model.c
Неинлинированная S-функция
/*
* model.c
.
.
.
*/
real_T untitled_RGND = 0.0; /* real_T ground */
/* Start the model */
void MdlStart(void)
{
/* (no start code required) */
}
/* Compute block outputs */
void MdlOutputs(int_T tid)
{
/* Level2 S-Function Block: <Root>/S-Function (foogain) */
{
SimStruct *rts = ssGetSFunction(rtS, 0);
sfcnOutputs(rts, tid);
}
}
/* Perform model update */
void MdlUpdate(int_T tid)
{
/* (no update code required) */
}
/* Terminate function */
void MdlTerminate(void)
{
/* Level2 S-Function Block: <Root>/S-Function (foogain) */
{
SimStruct *rts = ssGetSFunction(rtS, 0);
sfcnTerminate(rts);
}
}
#include "model_reg.h"
/* [EOF] model.c */Встроенная S-функция. Этот код: с model.cfoogain S-функция полностью встроена:
/*
* model.c
.
.
.
*/
/* Start the model */
void MdlStart(void)
{
/* (no start code required) */
}
/* Compute block outputs */
void MdlOutputs(int_T tid)
/* S-Function block: <Root>/S-Function */
/* NOTE: There are no calls to the S-function API in the inlined
version of model.c. */
rtB.S_Function = 0.0 * rtP.S_Function_Gain;
}
/* Perform model update */
void MdlUpdate(int_T tid)
{
/* (no update code required) */
}
/* Terminate function */
void MdlTerminate(void)
{
/* (no terminate code required) */
}
#include "model_reg.h"
/* [EOF] model.c */Если включить этот целевой файл для этого S-функционального блока, результат код - model.c
rtB.S_Function = 0.0 * rtP.S_Function_Gain;
Включение файла TLC резко уменьшило размер кода и увеличило эффективность выполнения сгенерированного кода. В этих примечаниях представлена некоторая информация о коде TLC и сгенерированных выходных данных:
Директива TLC %implements требуется для целевых файлов блоков и должна быть первой исполняемой инструкцией в целевом файле блоков. Эта директива запрещает компилятору целевого языка выполнять неподходящий целевой файл для S-функции foogain.
Вход в foo является rtGROUND (глобальная Coder™ Simulink равна 0,0), поскольку foo является единственным блоком в модели, и его вход не подключен.
Включение файла TLC для foogain устраняет необходимость в сегменте регистрации S-функции для foogain. Это значительно уменьшает размер кода.
Код TLC встроен в gain когда процесс построения сконфигурирован для встроенных значений параметров. Например, если параметр S-функции указан как 2.5 в диалоговом окне S-функции, TLC Outputs функция генерирует
rtB.foo = input * 2.5;
Используйте %generatefile директива, если ваша операционная система имеет ограничение по размеру имени файла и имя S-функции foosfunction (что превышает предел). В этом случае необходимо включить следующую инструкцию в системный целевой файл (где-либо до ссылки на этот целевой файл S-функционального блока).
%generatefile foosfunction "foosfunc.tlc"
Этот оператор сообщает компилятору целевого языка об открытии foosfunc.tlc вместо foosfunction.tlc.
Включение S-функции уровня 2 значительно уменьшает размер код. Функции регистрации моделей являются длительными; в этом примере большая часть кода была исключена. Код ниже подчеркивает разницу между неинлайнированной и встроенной версиями model_reg.h; встраивание устраняет этот код:model_reg.h
/*
* model_reg.h
*
*/
/* Normal model initialization code independent of
S-functions */
/* child S-Function registration */
ssSetNumSFunctions(rtS, 1);
/* register each child */
{
static SimStruct childSFunctions[1];
static SimStruct *childSFunctionPtrs[1];
(void)memset((char_T *)&childSFunctions[0], 0,
sizeof(childSFunctions));
ssSetSFunctions(rtS, &childSFunctionPtrs[0]);
{
int_T i;
for(i = 0; i < 1; i++) {
ssSetSFunction(rtS, i, &childSFunctions[i]);
}
}
/* Level2 S-Function Block: untitled/<Root>/S-Function
(foogain) */
{
extern void foogain(SimStruct *rts);
SimStruct *rts = ssGetSFunction(rtS, 0);
/* timing info */
static time_T sfcnPeriod[1];
static time_T sfcnOffset[1];
static int_T sfcnTsMap[1];
{
int_T i;
for(i = 0; i < 1; i++) {
sfcnPeriod[i] = sfcnOffset[i] = 0.0;
}
}
ssSetSampleTimePtr(rts, &sfcnPeriod[0]);
ssSetOffsetTimePtr(rts, &sfcnOffset[0]);
ssSetSampleTimeTaskIDPtr(rts, sfcnTsMap);
ssSetMdlInfoPtr(rts, ssGetMdlInfoPtr(rtS));
/* inputs */
{
static struct _ssPortInputs inputPortInfo[1];
_ssSetNumInputPorts(rts, 1);
ssSetPortInfoForInputs(rts, &inputPortInfo[0]);
/* port 0 */
{
static real_T const *sfcnUPtrs[1];
sfcnUPtrs[0] = &untitled_RGND;
ssSetInputPortWidth(rts, 0, 1);
ssSetInputPortSignalPtrs(rts, 0,
(InputPtrsType)&sfcnUPtrs[0]);
}
}
/* outputs */
{
static struct _ssPortOutputs outputPortInfo[1];
_ssSetNumOutputPorts(rts, 1);
ssSetPortInfoForOutputs(rts, &outputPortInfo[0]);
ssSetOutputPortWidth(rts, 0, 1);
ssSetOutputPortSignal(rts, 0, &rtB.S_Function);
}
/* path info */
ssSetModelName(rts, "S-Function");
ssSetPath(rts, "untitled/S-Function");
ssSetParentSS(rts, rtS);
ssSetRootSS(rts, ssGetRootSS(rtS));
ssSetVersion(rts, SIMSTRUCT_VERSION_LEVEL2);
/* parameters */
{
static mxArray const *sfcnParams[1];
ssSetSFcnParamsCount(rts, 1);
ssSetSFcnParamsPtr(rts, &sfcnParams[0]);
ssSetSFcnParam(rts, 0, &rtP.S_Function_P1Size[0]);
}
/* registration */
foogain(rts);
sfcnInitializeSizes(rts);
sfcnInitializeSampleTimes(rts);
/* adjust sample time */
ssSetSampleTime(rts, 0, 0.2);
ssSetOffsetTime(rts, 0, 0.0);
sfcnTsMap[0] = 0;
/* Update the InputPortReusable and BufferDstPort flags for
each input port */
ssSetInputPortReusable(rts, 0, 0);
ssSetInputPortBufferDstPort(rts, 0, -1);
/* Update the OutputPortReusable flag of each output port */
}
}Чтобы избежать ненужных вызовов S-функции и создать минимальный код, необходимый для S-функции, следующий файл TLC, foogain.tlc, приводится в качестве примера.
%implements "foogain" "C" %function Outputs (block, system) Output /* %<Type> block: %<Name> */ %% %assign y = LibBlockOutputSignal (0, "", "", 0) %assign u = LibBlockInputSignal (0, "", "", 0) %assign p = LibBlockParameter (Gain, "", "", 0) %<y> = %<u> * %<p>; %endfunction
Данные экземпляра - это дополнительные данные или рабочая память, уникальная для каждого экземпляра блока в модели Simulink. Это не включает в себя данные параметров или состояний (которые хранятся в параметрах модели и векторах состояний соответственно), а скорее используется для кэширования промежуточных результатов или производных представлений параметров и режимов. Одним из примеров данных экземпляра является буфер, используемый блоком задержки передачи.
Выделение и использование памяти для каждого экземпляра может быть выполнено несколькими способами в S-функции уровня 2: ssSetUserData, рабочие векторы (например, ssSetRWorkValue, ssSetIWorkValue) или рабочие векторы типа данных, известные как DWork векторы. Для наименьших усилий при написании целевого файла S-функции и блока и для автоматического соответствия как статическим, так и malloc данные экземпляра о целевых объектах, таких как grtиспользуйте рабочие векторы типа данных при записи S-функций с данными экземпляра.
Преимущества двояки. Во-первых, написание S-функции более прост, в том, что распределение памяти и освобождения обрабатываются для вас Simulink. Во-вторых, DWork векторы записываются в для вас автоматически, включая model.rtwDWork имя, тип данных и размер. Это упрощает запись целевого файла блока, так как не нужно писать код TLC для выделения и освобождения DWork память.
Кроме того, если требуется объединить группы DWork векторы в структуры для передачи в функции, можно заполнить структуру указателями на DWork массивы в обеих S-функциях mdlStart и целевой файл блока Start способ обеспечивает согласованность между S-функцией и обработкой данных сгенерированным кодом.
Наконец, использование DWork делает простым создание определенной версии кода (типы данных, скаляр и векторизация и т.д.) для каждого экземпляра блока, который соответствует реализации в S-функции. Обе реализации используют DWork таким же образом, чтобы встроенный код можно было использовать с программным обеспечением Simulink Accelerator™ без изменений функции C MEX S или целевого файла блока.
По умолчанию программа Simulink Accelerator вызывает функцию C MEX S как часть ускоренного моделирования модели. Если перед запуском ускоренной модели акселератор должен быть встроен в S-функцию, попросите акселератор использовать целевой файл блока для встраивания S-функции с помощью SS_OPTION_USE_TLC_WITH_ACCELERATOR флаг в вызове ssSetOptions() в mdlInitializeSizes функции этой S-функции.
Следует отметить, что размер и использование памяти и рабочего вектора должны быть одинаковыми для сгенерированного кода TLC и S-функции C MEX, или программное обеспечение Simulink Accelerator не может правильно выполнить встроенный код. Это происходит потому, что S-функция C MEX вызывается для инициализации блока и его рабочих векторов, вызывая mdlInitializeSizes, mdlInitializeConditions, mdlCheckParameters, mdlProcessParameters, и mdlStart функции. В случае постоянного распространения сигнала mdlOutputs вызывается из S-функции C MEX во время фазы инициализации выполнения модели.
В течение фазы временного сдвига ускоренного выполнения модели код, генерируемый Output и Update будут выполняться блочные методы TLC, плюс Derivatives и методы пересечения нуля, если они существуют. Start способ целевого файла блока не используется при формировании кода для ускоренной модели.