Когда Simulink® модель содержит S-функцию, и соответствующий целевой файл блока TLC существует для этой S-функции, генератор кода встраивает S-функцию. Введение S-функции может создать более эффективный код путем исключения слоя S-функции API из сгенерированного кода.
Для S-функций, которые могут выполнять самые разные задачи, вставка их дает вам возможность сгенерировать код только для текущего режима работы, установленного для каждого образца блока. В качестве примера этого, если S-функция принимает произвольную ширину сигнала и закольцовывает через каждый элемент сигнала, вы хотели бы сгенерировать inlined код, который имеет циклы, когда сигнал имеет два или более элемента, но генерирует простое некольцованное вычисление, когда сигнал имеет только один элемент.
MEX S-функции уровня 1 C (записанные в более раннюю форму S-функционального API), которые не встроены, заставят сгенерированный код выполнять вызовы всех этих функций, даже если стандартная программа пуста для конкретной S-функции.
Функция | Цель |
---|---|
Инициализируйте массив размеров | |
Инициализируйте массив шагов расчета | |
Инициализируйте состояния | |
Вычислите выходы | |
Обновление дискретных состояний | |
Вычислите производные непрерывных состояний | |
Очистка, когда симуляция заканчивается |
MEX S-функции уровня 2 C (т.е. те, которые записаны в текущий API S-функции), которые не встроены, осуществляют вызовы вышеуказанных функций за следующими исключениями:
mdlInitializeConditions
вызывается только в том случае, если MDL_INITIALIZE_CONDITIONS
объявлен как #define
.
mdlStart
вызывается только в том случае, если MDL_START
объявлен как #define
.
mdlUpdate
вызывается только в том случае, если MDL_UPDATE
объявлен как #define
.
mdlDerivatives
вызывается только в том случае, если MDL_DERIVATIVES
объявлен как #define
.
Путем вставки S-функции можно исключить вызовы этих, возможно, пустых функций в цикле симуляции. Это может значительно улучшить эффективность сгенерированного кода.
Для ввода S-функции, вызываемой
, вы создаете пользовательский целевой файл блока s-function sfunc
Имя
и поместите его в ту же папку, что и Файл MEX S-функции. Затем во время сборки выполняется целевой файл вместо настройки вызовов функции в S-функцию sfunc
_name.tlc.c
файл. Целевой файл S-функции «inlines» S-функции путем направления Target Language Compiler вставлять только операторы, определенные в целевом файле.
В целом, встраивание S-функции особенно полезно, когда
Время, необходимое для выполнения содержимого S-функции, невелико по сравнению с накладными расходами, необходимыми для вызова S-функции.
Некоторые стандартные программы S-функций являются пустыми (например, mdlUpdate
).
Поведение S-функции изменяется между симуляцией и генерацией кода. Для примера драйвер устройства ввода-вывода S-функции могут считываться из MATLAB® рабочая область во время симуляции, но считанная с фактического аппаратного адреса в сгенерированном коде.
S-функция может записать два разных типа параметров в
файл для доступа к файлам компилятора целевого языка:model
.rtw
Настройки параметра: Они соответствуют нетронутым параметрам (обычно устанавливаемым из флажков и меню на маскированной S-функции), которые записываются через mdlRTW
метод S-функции с использованием ssWriteRTWParamSettings
. Файл реализации S-функции TLC может затем получить прямой доступ к значениям этих настроек параметра из SFcnParamSettings
запись в блок.
Настраиваемые параметры: К этому классу параметров можно получить доступ, когда они зарегистрированы как параметры во время выполнения в S-функции. Обратите внимание, что такие настраиваемые параметры автоматически записываются в
файл. В рамках файла TLC для S-функции можно получить доступ к параметрам во время выполнения и их атрибутам с помощью model
.rtwLibBlockParameter
библиотечная функция и ее варианты.
Для получения дополнительной информации о том, как создать и использовать параметры во время выполнения, смотрите Создать и обновить параметры во время выполнения S-функции. Также см. пример sfcndemo_runtime
в примерах S-функций для создания и использования двух классов параметров. Примерами исходных файлов, которые можно просматривать и адаптировать, являются
Предположим, что у вас есть простая S-функция, которая имитирует блок Gain с одним входом, одним выходом и скалярным усилением. То есть 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-Function. Для получения информации о том, как сгенерировать код, смотрите Configure Model and Generate Code и Choose Build Approach и Configure Build Process.
Без файла для определения спецификы S-функции генератор кода должен вызвать Файл MEX через S-function API. Следующий код является
файл для нелинейной 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-function, результат
код есть model
.c
rtB.S_Function = 0.0 * rtP.S_Function_Gain;
Включение файла TLC резко уменьшило размер кода и увеличило эффективность выполнения сгенерированного кода. Эти примечания выделяют некоторую информацию о коде TLC и сгенерированном выходе:
Директива TLC %implements
требуется для блока целевых файлов и должен быть первым исполняемым оператором в блок целевом файле. Эта директива препятствует выполнению компилятором целевого языка неприемлемого целевого файла для S-функции foogain
.
Вход в foo
является rtGROUND
(a Simulink Coder™ глобальное значение равно 0,0), поскольку foo
является единственным блоком в модели, и его вход не связан.
Включение файла для foogain
устраняет необходимость в сегменте S-функции регистрации для foogain
. Это значительно уменьшает размер кода.
Код TLC вводит gain
параметр, когда процесс сборки сконфигурирован на встроенные значения параметров. Для примера, если параметр S-функции задан как 2,5 в диалоговом окне S-функции, TLC Outputs
функция генерирует
rtB.foo = input * 2.5;
Используйте %generatefile
директива, если ваша операционная система имеет ограничение по размеру имени файла, и имя S-функции: foosfunction
(что превышает предел). В этом случае вы включите следующий оператор в системный целевой файл (где угодно до ссылки на этот целевой файл блока s-function).
%generatefile foosfunction "foosfunc.tlc"
Этот оператор сообщает целевому языковому компилятору открыть foosfunc.tlc
вместо foosfunction.tlc
.
Включение S-функции уровня 2 значительно уменьшает размер
код. Функции регистрации модели являются длительными; большая часть кода была исключена в этом примере. Приведенный ниже код подчеркивает различие между неинлинговыми и встроенными версиями model
_reg.h
; inlining устраняет этот код: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-function или блочного целевого файла.
По умолчанию программное обеспечение Simulink Accelerator вызывает вашу S-функцию C MEX как часть ускоренной симуляции модели. Если вы предпочитаете, чтобы Accelerator включил вашу S-функцию перед запуском ускоренной модели, скажите Accelerator использовать ваш блочный целевой файл, чтобы встроить 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
block TLC методы будут выполняться, плюс Derivatives
и методы пересечения нулем, если они существуют. Start
способ блочного целевого файла не используется при генерации кода для ускоренной модели.