Когда Simulink® модель содержит S-функцию, и соответствующий конечный файл блока TLC существует для той S-функции, генератор кода встраивает S-функцию. Встраивание S-функции может произвести более эффективный код путем устранения слоя API S-функции из сгенерированного кода.
Для S-функций, которые могут выполнить множество задач, встроив их, дает вам возможность сгенерировать код только для текущего набора режима работы для каждого экземпляра блока. Как пример этого, если бы S-функция принимает произвольную ширину сигнала и циклы через каждый элемент сигнала, вы хотели бы сгенерировать встроенный код, который имеет циклы, когда сигнал имеет два или больше элемента, но генерирует простое нециклично выполненное вычисление, когда сигнал имеет всего один элемент.
Уровень 1 C S-функции MEX (записанный в более старую форму API S-функции), которые не встраиваются, заставят сгенерированный код выполнять вызовы ко всем этим функциям, даже если стандартная программа будет пуста для конкретной S-функции.
Функция | Цель |
---|---|
Инициализируйте массив размеров | |
Инициализируйте массив шагов расчета | |
Инициализируйте состояния | |
Вычислите выходные параметры | |
Обновите дискретные состояния | |
Вычислите производные непрерывных состояний | |
Вымойтесь, когда симуляция завершит работу |
Уровень 2 C S-функции MEX (i.e., записанные в текущий 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-функции “встраивает” S-функцию путем направления Компилятора Выходного языка, чтобы вставить только операторы, заданные в конечном файле.
В общем случае встраивание S-функции особенно полезно когда
Время, требуемое выполнить содержимое S-функции, мало по сравнению с издержками, требуемыми вызывать S-функцию.
Определенные стандартные программы S-функции пусты (e.g., mdlUpdate
).
Поведение S-функции изменяется между симуляцией и генерацией кода. Например, S-функции ввода-вывода драйвера устройства могут читать из MATLAB® рабочая область в процессе моделирования, но читают из фактического аппаратного адреса в сгенерированном коде.
S-функция может записать два различных типов параметров в
файл для файлов Компилятора Выходного языка для доступа:model
.rtw
Установки параметров: Они соответствуют ненастраиваемым параметрам (обычно установленный от флажков и меню на S-функции маскированной), которые записаны через mdlRTW
метод использования S-функции ssWriteRTWParamSettings
. Файл реализации S-function TLC может затем непосредственно получить доступ к значениям этих установок параметров от SFcnParamSettings
запись в блоке.
Настраиваемые параметры: к Этому классу параметров можно получить доступ, когда они указаны как параметры периода выполнения в S-функции. Обратите внимание на то, что такие настраиваемые параметры автоматически выписаны к
файл. В файле TLC для S-функции можно получить доступ к параметрам периода выполнения и их атрибутам с помощью model
.rtwLibBlockParameter
библиотечная функция и ее варианты.
Для получения дополнительной информации о том, как создать и использовать параметры периода выполнения, видит, Создают и Параметры периода выполнения S-функции Обновления. Также смотрите пример sfcndemo_runtime
в примерах S-функции для того, как создать и использовать два класса параметров. Исходные файлы в качестве примера, которые можно смотреть и адаптировать,
Предположим, что у вас есть простая S-функция, которая подражает блоку Gain, с одним входом, одним выходом и скалярным усилением. Таким образом, y = u * p
. Если именем блока Simulink является foo
и именем S-функции Уровня 2 является foogain
, S-функция MEX C должна содержать этот код:
#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.
Для получения дополнительной информации о них S-функция связанные библиотечные функции C, смотрите, Конфигурируют Функции S-функции C/C++. Для получения информации о том, как сгенерировать код, смотрите, Конфигурируют Модель и Генерируют Код и Подходы для Строительных норм и правил, Сгенерированных из Моделей Simulink.
Без файла TLC, чтобы задать специфические особенности S-функции, генератор кода должен вызвать S-функцию файла MEX через API S-функции. Следующим кодом является
файл для невстроенной S-функции (i.e., никакой соответствующий файл 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 и сгенерированном выходе:
Направляющий %implements
TLC требуется конечными файлами блока и должен быть первый исполняемый оператор в конечном файле блока. Эта директива препятствует тому, чтобы Компилятор Выходного языка выполнил несоответствующий конечный файл для S-функции
foogain
.
Вход к foo
rtGROUND
(глобальная переменная Simulink Coder™ равняется 0,0), потому что foo
единственный блок в модели, и ее вход не связан.
Включая файл TLC для 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
; встраивание устраняет этот код: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™ без изменений в S-функции MEX C или конечном файле блока.
По умолчанию программное обеспечение Simulink Accelerator вызывает вашу S-функцию MEX C как часть ускоренной симуляции модели. Если вы предпочитаете иметь акселератор, встраивают вашу S-функцию прежде, чем запустить ускоренную модель, говорят акселератору использовать ваш конечный файл блока, чтобы встроить S-функцию с SS_OPTION_USE_TLC_WITH_ACCELERATOR
отметьте в вызове ssSetOptions()
в mdlInitializeSizes
функция той S-функции.
Обратите внимание на то, что память и работает, размер вектора и использование должны быть тем же самым для сгенерированного кода TLC и S-функции MEX C, или программное обеспечение Simulink Accelerator не может выполнить встроенный код правильно. Это вызвано тем, что S-функция MEX C называется, чтобы инициализировать блок и его векторы работы, вызывая mdlInitializeSizes
, mdlInitializeConditions
, mdlCheckParameters
, mdlProcessParameters
, и mdlStart
функции. В случае постоянного распространения сигнала, mdlOutputs
называется от S-функции MEX C во время фазы инициализации выполнения модели.
Во время продвигающейся во время фазы ускоренного выполнения модели, код, сгенерированный Output
и Update
методы блока TLC выполнятся, плюс Derivatives
и методы пересечения нулем, если они существуют. Start
метод конечного файла блока не используется в генерации кода для ускоренной модели.