Используйте выражение, сворачивающееся, чтобы увеличить эффективность кода, сгенерированного вашими собственными встроенными Блоками s-function путем вызова макросов, обеспеченных в API S-функции.
API S-функции позволяет вам задать, должен ли данный Блок s-function номинально принять выражения в данном входном порту. Блок не должен всегда принимать выражения. Например, если адрес сигнала во входе используется, выражения не должны быть приняты в том входе, потому что не возможно взять адрес выражения.
API S-функции также позволяет вам задать, может ли выражение представлять вычисления, сопоставленные с данным выходным портом. Когда вы запрашиваете выражение в порте ввода или вывода блока, механизм Simulink® определяет, может ли он соблюдать тот запрос, учитывая контекст блока. Например, механизм может отклонить просьбу блока выводить выражение, если целевой блок не принимает выражения в своем входе, если целевой блок имеет функцию обновления, или если несколько выходных мест назначения существуют.
Решение соблюдать или отклонить просьбу выводить выражение может также зависеть от категории выходного выражения использование блока.
Чтобы использовать в своих интересах выражение, сворачивающееся в ваших S-функциях, необходимо понять, когда запросить принятие и генерацию выражений для определенных блоков. Вы не должны понимать алгоритм, которого механизм Simulink принимает решение принять или отклонить эти просьбы. Однако, если вы хотите проследить между моделью и сгенерированным кодом, полезно понять некоторые более общие ситуации, которые приводят к отказу запроса.
Когда вы реализуете S-функцию MEX C, можно задать, должен ли код, соответствующий выводу блока, быть сгенерирован как выражение. Если блок генерирует выражение, необходимо указать, что выражение является постоянным, тривиальным, или типичным.
Постоянное выходное выражение является прямым доступом к одному из параметров блока. Например, вывод блока Constant задан как константное выражение, потому что выходное выражение является просто прямым доступом к параметру Value
блока.
Тривиальное выходное выражение является выражением, которое может быть повторено без потери производительности, когда выходной порт имеет несколько выходных мест назначения. Например, вывод блока Unit Delay задан как тривиальное выражение, потому что выходное выражение является просто прямым доступом к состоянию блока. Поскольку выходное выражение не имеет вычислений, оно может быть повторено несколько раз, не ухудшая производительность сгенерированного кода.
Типичное выходное выражение является выражением, которое должно быть принято, чтобы иметь потерю производительности, если повторено. По сути, типичное выходное выражение не подходит для повторения, когда выходной порт имеет несколько выходных мест назначения. Например, вывод блока Sum является дженериком, а не тривиальным выражением, потому что это является дорогостоящим, чтобы повторно вычислить выходное выражение блока Sum как вход к нескольким блокам.
Рассмотрите эту блок-схему. Блок Delay имеет несколько мест назначения, все же его вывод определяется как тривиальное выходное выражение, так, чтобы он мог использоваться несколько раз, не ухудшая эффективность кода.
Эта выборка кода показывает код, сгенерированный от блока Unit Delay в этой блок-схеме. Три корневых выходных параметров непосредственно присвоены от состояния блока Unit Delay, который хранится в поле структуры глобальных данных rtDWork
. Поскольку присвоение является прямым без выражений, нет никакой потери производительности, сопоставленной с использованием тривиального выражения для нескольких мест назначения.
void MdlOutputs(int_T tid) { ... /* Outport: <Root>/Out1 incorporates: * UnitDelay: <Root>/Unit Delay */ rtY.Out1 = rtDWork.Unit_Delay_DSTATE; /* Outport: <Root>/Out2 incorporates: * UnitDelay: <Root>/Unit Delay */ rtY.Out2 = rtDWork.Unit_Delay_DSTATE; /* Outport: <Root>/Out3 incorporates: * UnitDelay: <Root>/Unit Delay */ rtY.Out3 = rtDWork.Unit_Delay_DSTATE; ... }
Сгенерированный код показывает, как код сгенерирован для блоков Суммы с синглом и несколькими местами назначения.
С другой стороны, рассмотрите блоки Суммы в этой модели:
Верхний блок Sum в модели генерирует сигнал, маркировал non_triv
. Вычисление этого выходного сигнала включает два умножения и сложение. Если бы блоку Sum вывод разрешили сгенерировать выражение, даже когда блок имел несколько мест назначения, операции блока были бы дублированы в сгенерированном коде. В этом случае сгенерированные выражения распространились бы к четырем умножению и двум сложениям. Это ухудшило бы эффективность программы. Соответственно выводу блока Sum не позволяют быть выражением, потому что это имеет несколько мест назначения.
Механизм Simulink не разрешает выводу верхнего блока Sum быть выражением, потому что non_triv
сигнала направляется двум выходным местам назначения. Вместо этого результат умножения и операций сложения хранится во временной переменной (rtb_non_triv)
, на который ссылаются дважды в операторах, которые следуют, как замечено в выборке кода ниже.
Напротив, более низкий блок Sum, который имеет только одно выходное место назначения (Out2
), действительно генерирует выражение.
void MdlOutputs(int_T tid) { /* local block i/o variables */ real_T rtb_non_triv; real_T rtb_Sine_Wave; /* Sum: <Root>/Sum incorporates: * Gain: <Root>/Gain * Inport: <Root>/u1 * Gain: <Root>/Gain1 * Inport: <Root>/u2 * * Regarding <Root>/Gain: * Gain value: rtP.Gain_Gain * * Regarding <Root>/Gain1: * Gain value: rtP.Gain1_Gain */ rtb_non_triv = (rtP.Gain_Gain * rtU.u1) + (rtP.Gain1_Gain * rtU.u2); /* Outport: <Root>/Out1 */ rtY.Out1 = rtb_non_triv; /* Sin Block: <Root>/Sine Wave */ rtb_Sine_Wave = rtP.Sine_Wave_Amp * sin(rtP.Sine_Wave_Freq * rtmGetT(rtM_model) + rtP.Sine_Wave_Phase) + rtP.Sine_Wave_Bias; /* Outport: <Root>/Out2 incorporates: * Sum: <Root>/Sum1 */ rtY.Out2 = (rtb_non_triv + rtb_Sine_Wave); }
API S-функции обеспечивает макросы, которые позволяют вам объявить, должен ли вывод блока быть выражением, и если так, чтобы задать категорию выражения. Эта таблица задает, когда объявить, что блок вывод постоянное, тривиальное, или типичное выходное выражение.
Типы выходных выражений
Категория выражения | Когда использовать |
---|---|
Постоянный | Используйте, только если блок вывод является прямым доступом к памяти к параметрам блоков. |
Тривиальный | Используйте, только если блок вывод является выражением, которое может появиться многократно в коде, не уменьшая эффективность (например, прямой доступ к памяти к полю вектора |
Типичный | Используйте, если выведенный выражение, но не постоянный или тривиальный. |
Необходимо объявить выходные параметры как выражения в функции mdlSetWorkWidths
использование макросов, заданных в API S-функции. Макросы имеют следующие аргументы:
SimStruct *S
: указатель на SimStruct
блока.
int idx:
основанный на нуле индекс выходного порта.
Передача bool value:
в ИСТИННОМ, если порт генерирует выходные выражения.
Следующие макросы доступны для установки вывода быть постоянным, тривиальным, или типичным выражением:
void ssSetOutputPortConstOutputExprInRTW(SimStruct *S, int idx, bool value)
void ssSetOutputPortTrivialOutputExprInRTW(SimStruct *S, int idx, bool value)
void ssSetOutputPortOutputExprInRTW(SimStruct *S, int idx, bool value)
Следующие макросы доступны для запроса состояния, установленного предшествующими вызовами макросов выше:
bool ssGetOutputPortConstOutputExprInRTW(SimStruct *S, int idx)
bool ssGetOutputPortTrivialOutputExprInRTW(SimStruct *S, int idx)
bool ssGetOutputPortOutputExprInRTW(SimStruct *S, int idx)
Набор типичных выражений является надмножеством набора тривиальных выражений, и набор тривиальных выражений является надмножеством набора константных выражений.
Поэтому, когда вы запрашиваете вывод, который собирался быть константным выражением с ssGetOutputPortTrivialOutputExprInRTW
, это возвращает True
. Константное выражение рассматривается тривиальным выражением, потому что это - прямой доступ к памяти, который может быть повторен, не ухудшая эффективность сгенерированного кода.
Точно так же вывод, который был сконфигурирован, чтобы быть постоянным или тривиальным выражением, возвращает True
, когда запрошено для его состояния как типичное выражение.
Блок может запросить, чтобы его вывод был представлен в коде как выражение. Такая просьба может быть отклонена, если целевой блок не может принять выражения в своем входном порту. Кроме того, условия, независимые от блока запроса и его целевых блоков, могут предотвратить принятие выражений.
Блок не должен быть сконфигурирован, чтобы принять выражения в его входном порту при следующих условиях:
Блок должен взять адрес своих входных данных. Не возможно взять адрес большинства типов входных выражений.
Код, сгенерированный для блока, ссылается на вход несколько раз (например, Abs или блоки Max). Это привело бы к дублированию потенциально сложного выражения и последующему ухудшению эффективности кода.
Если блок отказывается принимать выражения во входном порту, то блоку, который соединяется с тем входным портом, не разрешают вывести типичное или тривиальное выражение.
Просьба вывести константное выражение не отклонена, потому что нет никакой потери производительности для константного выражения, и программное обеспечение может взять адрес параметра.
API S-функции обеспечивает макросы, которые позволяют вам:
Задайте, должен ли вход блока принять непостоянные выражения (то есть, тривиальные или типичные выражения).
Запросите, принимает ли вход блока непостоянные выражения.
По умолчанию блокируйтесь, входные параметры не принимают непостоянные выражения.
Необходимо вызвать макросы в функции mdlSetWorkWidths
. Макросы имеют эти аргументы:
SimStruct *S
: указатель на SimStruct блока.
int idx:
основанный на нуле индекс входного порта.
Передача bool value:
в ИСТИННОМ, если порт принимает входные выражения; в противном случае передайте во ЛЖИ.
Макрос, доступный для определения, должен ли вход блока принять непостоянное выражение:
void ssSetInputPortAcceptExprInRTW(SimStruct *S, int portIdx, bool value)
Соответствующий макрос, доступный для запроса состояния, установленного любыми предшествующими вызовами ssSetInputPortAcceptExprInRTW
:
bool ssGetInputPortAcceptExprInRTW(SimStruct *S, int portIdx)
Даже после того, как определенный блок запрашивает, чтобы было позволено сгенерировать выходное выражение, что просьба может быть отклонена по типичным причинам. Эти причины включают, но не ограничиваются:
Выходное выражение нетривиально, и вывод имеет несколько мест назначения.
Выходное выражение является непостоянным, и вывод соединяется по крайней мере с одним местом назначения, которое не принимает выражения в его входном порту.
Вывод является тестовой точкой.
Вывод был присвоен внешний класс памяти.
Вывод должен храниться с помощью глобальных данных (например, вход к блоку слияния или блоку с состояниями).
Выходной сигнал является комплексным.
Вы не должны рассматривать эти типичные факторы при решении, использовать ли выражение, сворачивающееся для конкретного блока. Однако эти правила могут быть полезными, когда вы исследуете сгенерированный код и анализируете случаи, где оптимизация сворачивания выражения подавлена.
Чтобы использовать в своих интересах сворачивание выражения, измените реализацию блока TLC встроенной S-функции, таким образом, что это сообщает механизму Simulink, генерирует ли это или принимает выражения в
Входные порты, как объяснено в API S-функции, чтобы Задать Принятие Входного выражения.
Выходные порты, как объяснено в Категориях Выходных выражений.
Эта тема обсуждает требуемые модификации к реализации TLC.
В функции BlockInstanceSetup
вашей S-функции укажите свой блок, чтобы быть совместимыми со сворачиванием выражения. В противном случае сворачивание выражения, которое требуют или позволенный при выходных параметрах блока или входных параметрах, будет отключено, и временные переменные будут использоваться.
Чтобы указать соответствие сворачивания выражения, вызовите библиотечную функцию TLC LibBlockSetIsExpressionCompliant(block)
, который задан в
. Например:matlabroot/rtw/c/tlc/lib/utillib.tlc
%% Function: BlockInstanceSetup =========================================== %% %function BlockInstanceSetup(block, system) void %% %<LibBlockSetIsExpressionCompliant(block)> %% %endfunction
Можно условно отключить выражение, сворачивающееся при вводах и выводах блока путем совершения вызова к этой функции условно.
Если вы заменяете одну из реализаций блока TLC, обеспеченных генератором кода вашей собственной реализацией, вы не должны выполнять предыдущий вызов, пока вы не обновили свою реализацию.
Функция BlockOutputSignal
используется, чтобы сгенерировать код для скалярного выходного выражения или одного элемента нескалярного выходного выражения. Если ваш блок выводит выражение, необходимо добавить функцию BlockOutputSignal
. Прототип BlockOutputSignal
%function BlockOutputSignal(block,system,portIdx,ucv,lcv,idx,retType) void
Аргументы к BlockOutputSignal
- они:
block
: запись для блока, для которого генерируется выходное выражение
система:
запись для системы, содержащей блок
portIdx
: основанный на нуле индекс выходного порта, для которого генерируется выражение
ucv
: определение переменной контроля за работой пользователей выходного элемента, для которого генерируется код
lcv
: контрольная переменная цикла, задающая выходной элемент, для которого генерируется код
idx :
предупредите об индексе, задающем выходной элемент, для которого генерируется код
retType
: вектор символов, задающий тип доступа сигнала, желал:
"Signal"
задает содержимое или адрес выходного сигнала
"SignalAddr"
задает адрес выходного сигнала
Функция BlockOutputSignal
возвращает вектор символов для выходного сигнала или адреса. Вектор символов должен осуществить приоритет выражения при помощи открытия и завершения круглых скобок, если выражение не состоит из вызова функции. Адрес выражения может только быть возвращен для константного выражения; это - адрес параметра, к памяти которого получают доступ. Код, реализующий функцию BlockOutputSignal
для блока Constant:
%% Function: BlockOutputSignal ================================================= %% Abstract: %% Return the reference to the parameter. This function *may* %% be used by Simulink when optimizing the Block IO data structure. %% %function BlockOutputSignal(block,system,portIdx,ucv,lcv,idx,retType) void %switch retType %case "Signal" %return LibBlockParameter(Value,ucv,lcv,idx) %case "SignalAddr" %return LibBlockParameterAddr(Value,ucv,lcv,idx) %default %assign errTxt = "Unsupported return type: %<retType>" %<LibBlockReportError(block,errTxt)> %endswitch %endfunction
Код, реализующий функцию BlockOutputSignal
для блока Relational Operator:
%% Function: BlockOutputSignal ================================================= %% Abstract: %% Return an output expression. This function *may* %% be used by Simulink when optimizing the Block IO data structure. %% %function BlockOutputSignal(block,system,portIdx,ucv,lcv,idx,retType) void %switch retType %case "Signal" %assign logicOperator = ParamSettings.Operator %if ISEQUAL(logicOperator, "~=") %assign op = "!=" elseif ISEQUAL(logicOperator, "==") %assign op = "==" %else %assign op = logicOperator %endif %assign u0 = LibBlockInputSignal(0, ucv, lcv, idx) %assign u1 = LibBlockInputSignal(1, ucv, lcv, idx) %return "(%<u0> %<op> %<u1>)" %default %assign errTxt = "Unsupported return type: %<retType>" %<LibBlockReportError(block,errTxt)> %endswitch %endfunction
Когда блок имеет один вывод, функция Outputs
в файле блока TLC вызвана, только если выходной порт не является выражением. В противном случае функция BlockOutputSignal
вызвана.
Если блок имеет несколько выходных параметров, функция Outputs
вызвана, если какой-либо выходной порт не является выражением. Функция Outputs
должна принять меры против генерации кода для выходных портов, которые являются выражениями. Это достигается путем защиты разделов кода, соответствующего отдельным выходным портам с вызовами LibBlockOutputSignalIsExpr()
.
Например, рассмотрите S-функцию с двумя входными параметрами и двумя выходными параметрами, где
Первый вывод, y0, равен два раза первому входу.
Второй вывод, y1, равен четыре раза второму входу.
Outputs
и функции BlockOutputSignal
для S-функции показывают в этой выборке кода:
%% Function: BlockOutputSignal ================================================= %% Abstract: %% Return an output expression. This function *may* %% be used by Simulink when optimizing the Block IO data structure. %% %function BlockOutputSignal(block,system,portIdx,ucv,lcv,idx,retType) void %switch retType %case "Signal" %assign u = LibBlockInputSignal(portIdx, ucv, lcv, idx) %case "Signal" %if portIdx == 0 %return "(2 * %<u>)" %elseif portIdx == 1 %return "(4 * %<u>)" %endif %default %assign errTxt = "Unsupported return type: %<retType>" %<LibBlockReportError(block,errTxt)> %endswitch %endfunction %% %% Function: Outputs ================================================= %% Abstract: %% Compute output signals of block %% %function Outputs(block,system) Output %assign rollVars = ["U", "Y"] %roll sigIdx = RollRegions, lcv = RollThreshold, block, "Roller", rollVars %assign u0 = LibBlockInputSignal(0, "", lcv, sigIdx) %assign u1 = LibBlockInputSignal(1, "", lcv, sigIdx) %assign y0 = LibBlockOutputSignal(0, "", lcv, sigIdx) %assign y1 = LibBlockOutputSignal(1, "", lcv, sigIdx) %if !LibBlockOutputSignalIsExpr(0) %<y0> = 2 * %<u0>; %endif %if !LibBlockOutputSignalIsExpr(1) %<y1> = 4 * %<u1>; %endif %endroll %endfunction
В прошлом блоки предшествовали своему выходному коду с комментариями формы
/* %<Type> Block: %<Name> */
Когда блок является "выражением, сворачивающимся совместимый", начальная строка, показанная выше, сгенерирована автоматически. Не включайте комментарий как часть реализации блока TLC. Укажите дополнительную информацию при помощи функции LibCacheBlockComment
.
Функция LibCacheBlockComment
берет вектор символов в качестве входа, задавая тело комментария, за исключением вводного заголовка, итоговой новой строки одного или многострочного комментария и заключительного трейлера.
Следующий код TLC иллюстрирует регистрацию комментария блока. Отметьте использование функционального LibBlockParameterForComment
, который возвращает вектор символов, подходящий для комментария блока, задавая значение параметров блоков.
%openfile commentBuf $c(*) Gain value: %<LibBlockParameterForComment(Gain)> %closefile commentBuf %<LibCacheBlockComment(block, commentBuf)>