timesN
Objective:, который показывает Этот пример, как можно влиять на поведение цикличного выполнения сгенерированного кода.
Folder: (открытый)
matlabroot/toolbox/rtw/rtwdemos/tlctutorial/timesN
Работа с моделью sfun_xN
в tlctutorial/timesN
. Это имеет один источник (блок генератора Синусоиды), времена N блок усиления, блок Out и блок Scope.
Пример проводит вас по следующим шагам:
Начало работы Настройте осуществление и запустите модель
Modify the Model — Измените вход width и смотрите результаты
Change the Loop Rolling Threshold — Измените порог и смотрите результаты
More About TLC Loop Rolling — Параметризуйте поведение цикла
Сделайте tlctutorial/timesN
вашей текущей папкой, так, чтобы можно было использовать обеспеченные файлы.
Необходимо использовать или создать рабочую папку за пределами
для моделей Simulink®, которые вы делаете. Вы не можете создать модели в исходных папках.matlabroot
В Командном окне MATLAB® создайте файл MEX для S-функции:
mex timesN.c
Это старается не брать версию, поставленную с Simulink.
Ошибка может произойти, если вы ранее не запустили mex -setup
.
Откройте образцовый файл sfun_xN
.
Просмотрите ранее сгенерированный код в sfun_xN_grt_rtw/sfun_xN.c
. Обратите внимание на то, что никакие циклы не существуют в коде. Это вызвано тем, что сигналы ввода и вывода являются скаляром.
Замените блок Sine Wave на блок Constant.
Установите параметр для блока Constant к 1:4 и измените главную метку, model: sfun_xN
, к model: sfun_vec
.
Сохраните отредактированную модель как sfun_vec
(в tlctutorial/timesN
). Модель теперь выглядит так.
Поскольку блок Constant генерирует вектор значений, это - векторизованная модель. Сгенерируйте код для модели и просмотрите раздел /*Model output function */
sfun_vec.c
в вашем редакторе, чтобы наблюдать, как обработаны переменные и циклы for
. Эта функция появляется можно следующим образом:
/* Model output function */ static void sfun_vec_output(int_T tid) { /* S-Function Block: <Root>/S-Function */ /* Multiply input by 3.0 */ sfun_vec_B.timesN_output[0] = sfun_vec_P.Constant_Value[0] * 3.0; sfun_vec_B.timesN_output[1] = sfun_vec_P.Constant_Value[1] * 3.0; sfun_vec_B.timesN_output[2] = sfun_vec_P.Constant_Value[2] * 3.0; sfun_vec_B.timesN_output[3] = sfun_vec_P.Constant_Value[3] * 3.0; /* Outport: '<Root>/Out' */ sfun_vec_Y.Out[0] = sfun_vec_B.timesN_output[0]; sfun_vec_Y.Out[1] = sfun_vec_B.timesN_output[1]; sfun_vec_Y.Out[2] = sfun_vec_B.timesN_output[2]; sfun_vec_Y.Out[3] = sfun_vec_B.timesN_output[3]; UNUSED_PARAMETER(tid); }
Заметьте, что существует четыре экземпляра кода, который генерирует образцовые выходные параметры, соответствуя четырем итерациям.
Установите параметр для блока Constant к 1:10 и сохраните модель.
Сгенерируйте код для модели и просмотрите раздел /*Model output function */
sfun_vec.c
в вашем редакторе, чтобы наблюдать, как обработаны переменные и циклы for
. Эта функция появляется можно следующим образом:
/* Model output function */ static void sfun_vec_output(int_T tid) { /* S-Function Block: <Root>/S-Function */ /* Multiply input by 3.0 */ { int_T i1; const real_T *u0 = &sfun_vec_P.Constant_Value[0]; real_T *y0 = sfun_vec_B.timesN_output; for (i1=0; i1 < 10; i1++) { y0[i1] = u0[i1] * 3.0; } } { int32_T i; for (i = 0; i < 10; i++) { /* Outport: '<Root>/Out' */ sfun_vec_Y.Out[i] = sfun_vec_B.timesN_output[i]; } } UNUSED_PARAMETER(tid); }
Заметьте что:
Код, который генерирует образцовые выходные параметры, “прокручивается” в цикл. Это происходит по умолчанию, когда количество итераций превышает 5.
Индекс цикла i1
запускается от 0 до 9.
Указатель *y0
используется и инициализируется к массиву выходного сигнала.
Генератор кода создает итерации или циклы в зависимости от текущего значения параметра Loop unrolling threshold.
Значением по умолчанию Loop unrolling threshold является 5
. Изменить поведение цикличного выполнения для блоков в модели:
На панели Optimization диалогового окна Configuration Parameters, набор Loop unrolling threshold к 12
и нажимают Apply
.
Параметром RollThreshold
является теперь 12
. Циклы будут сгенерированы только, когда ширина сигналов, проходящих через блок, превысит 12.
Вы не можете изменить RollThreshold
для определенных блоков от диалогового окна Configuration Parameters.
Нажмите Ctrl+B, чтобы регенерировать вывод.
Осмотрите sfun_vec.c
. Это будет выглядеть так:
/* Model output function */ static void sfun_vec_output(int_T tid) { /* S-Function Block: <Root>/S-Function */ /* Multiply input by 3.0 */ sfun_vec_B.timesN_output[0] = sfun_vec_P.Constant_Value[0] * 3.0; sfun_vec_B.timesN_output[1] = sfun_vec_P.Constant_Value[1] * 3.0; sfun_vec_B.timesN_output[2] = sfun_vec_P.Constant_Value[2] * 3.0; sfun_vec_B.timesN_output[3] = sfun_vec_P.Constant_Value[3] * 3.0; sfun_vec_B.timesN_output[4] = sfun_vec_P.Constant_Value[4] * 3.0; sfun_vec_B.timesN_output[5] = sfun_vec_P.Constant_Value[5] * 3.0; sfun_vec_B.timesN_output[6] = sfun_vec_P.Constant_Value[6] * 3.0; sfun_vec_B.timesN_output[7] = sfun_vec_P.Constant_Value[7] * 3.0; sfun_vec_B.timesN_output[8] = sfun_vec_P.Constant_Value[8] * 3.0; sfun_vec_B.timesN_output[9] = sfun_vec_P.Constant_Value[9] * 3.0; /* Outport: '<Root>/Out' */ sfun_vec_Y.Out[0] = sfun_vec_B.timesN_output[0]; sfun_vec_Y.Out[1] = sfun_vec_B.timesN_output[1]; sfun_vec_Y.Out[2] = sfun_vec_B.timesN_output[2]; sfun_vec_Y.Out[3] = sfun_vec_B.timesN_output[3]; sfun_vec_Y.Out[4] = sfun_vec_B.timesN_output[4]; sfun_vec_Y.Out[5] = sfun_vec_B.timesN_output[5]; sfun_vec_Y.Out[6] = sfun_vec_B.timesN_output[6]; sfun_vec_Y.Out[7] = sfun_vec_B.timesN_output[7]; sfun_vec_Y.Out[8] = sfun_vec_B.timesN_output[8]; sfun_vec_Y.Out[9] = sfun_vec_B.timesN_output[9]; UNUSED_PARAMETER(tid); }
Чтобы активировать цикл, прокручивающийся снова, измените Loop unrolling threshold на 10 (или меньше) на панели Optimization.
Прокрутка цикла является важной возможностью TLC оптимизации сгенерированного кода. Не торопитесь, чтобы изучить и исследовать его последствия прежде, чем сгенерировать код для производственных требований.
Следующий код %roll
TLC является функцией Outputs
timesN.tlc
:
%function Outputs(block, system) Output /* %<Type> Block: %<Name> */ %% /* Multiply input by %<gain> */ %assign rollVars = ["U", "Y"] %roll idx = RollRegions, lcv = RollThreshold, block, "Roller", rollVars %<LibBlockOutputSignal(0, "", lcv, idx)> = \ %<LibBlockInputSignal(0, "", lcv, idx)> * %<gain>; %endroll %endfunction %% Outputs
%roll
Строки между %roll
и %endroll
могут быть или повторены или циклично выполнены. Ключ к пониманию директивы %roll
находится в ее аргументах:
%roll sigIdx = RollRegions, lcv = RollThreshold, block, "Roller", rollVars
Аргумент | Описание |
---|---|
sigIdx | Задайте индекс в вектор (сигнала), который используется в сгенерированном коде. Если сигнал является скаляром, анализируя тот блок |
lcv | Контрольная переменная обычно задана в директиве |
block | Это говорит TLC, что он работает с объектами блока. Код TLC для S-функций использует этот аргумент. |
"Roller" | Это, заданное в |
rollVars | Говорит TLC, какие типы элементов должны быть прокручены: входные сигналы, выходные сигналы и/или параметры. Вы не должны использовать всех их. В предыдущей строке %assign rollVars = ["U", "Y"] U ) и выходные сигналы (Y ). В случаях, где блоки задают массив параметров вместо скалярного параметра, rollvars задан как%assign rollVars = ["U", "Y", "P"] |
Посмотрите на строки, которые появляются между %roll
и %endroll
:
%<LibBlockOutputSignal(0, "", lcv, idx)> = \ %<LibBlockInputSignal (0, "", lcv, idx)> * 2.0;
LibBlockInputSignal
библиотечных функций TLC и LibBlockOutputSignal
расширяются, чтобы произвести скалярные или векторные идентификаторы, которые называют и индексируют. LibBlockInputSignal
, LibBlockOutputSignal
, и много имели отношение, функции TLC передаются четыре канонических аргумента:
Аргумент | Описание |
---|---|
первый аргумент — | Соответствует индексу входного порта для данного блока. Первый входной порт имеет индекс 0. Второй входной порт имеет индекс 1 и так далее. |
второй аргумент — | Индексная переменная зарезервирована для усовершенствованного использования. На данный момент задайте второй аргумент как пустую строку. В усовершенствованных приложениях можно задать собственное имя переменной, которое будет использоваться в качестве индекса с |
третий аргумент — | Как описано ранее, |
четвертый аргумент — | Позволяет TLC обработать особые случаи. Если |