Используйте выражение, сворачивающееся, чтобы увеличить КПД кода, сгенерированного вашими собственными встроенными Блоками 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:
передайте в TRUE, если порт генерирует выходные выражения.
Следующие макросы доступны для установки выхода быть постоянным, тривиальным, или типовым выражением:
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:
передайте в TRUE, если порт принимает входные выражения; в противном случае передайте в FALSE.
Макрос, доступный для определения, должен ли вход блока принять непостоянное выражение:
void ssSetInputPortAcceptExprInRTW(SimStruct *S, int portIdx, bool value)
Соответствующий макрос, доступный для запроса состояния, установленного любыми предшествующими вызовами ssSetInputPortAcceptExprInRTW
:
bool ssGetInputPortAcceptExprInRTW(SimStruct *S, int portIdx)
Даже после того, как определенный блок запрашивает, чтобы было позволено сгенерировать выходное выражение, что просьба может быть отклонена по типовым причинам. Эти причины включают, но не ограничиваются:
Выходное выражение нетривиально, и выход имеет несколько мест назначения.
Выходное выражение является непостоянным, и выход соединяется по крайней мере с одним местом назначения, которое не принимает выражения в его входном порту.
Выход является тестовой точкой.
Выход был присвоен внешний класс памяти.
Выход должен храниться с помощью глобальных данных (например, вход с блоком слияния или блоком с состояниями).
Выходной сигнал является комплексным.
Вы не должны рассматривать эти типовые факторы при решении, использовать ли выражение, сворачивающееся для конкретного блока. Однако эти правила могут быть полезными, когда вы исследуете сгенерированный код и анализируете случаи, где оптимизация сворачивания выражения подавлена.
Чтобы использовать в своих интересах сворачивание выражения, измените реализацию блока TLC встроенной S-функции, таким образом, что это сообщает механизму Simulink, генерирует ли это или принимает выражения в
Input port, как объяснено в 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
: запись для блока, для которого генерируется выходное выражение
system
: запись для системы, содержащей блок
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)>