Исследуйте прокрутка цикла и имена переменных

timesN Обзор примера по цикличному выполнению

Objective: В этом примере показано, как можно влиять на поведение цикличного выполнения сгенерированного кода.

Folder: matlabroot/toolbox/rtw/rtwdemos/tlctutorial/timesN открытый

Работа с моделью sfun_xN в tlctutorial/timesN. Это имеет один источник (блок генератора Sine Wave), блок усиления times N, блок Out и блок Scope.

Пример проводит вас по следующим шагам:

  1. Начало работы Настройте осуществление и запустите модель

  2. Modify the Model — Измените вход width и смотрите результаты

  3. Change the Loop Rolling Threshold — Измените порог и смотрите результаты

  4. More About TLC Loop Rolling — Параметрируйте поведение цикла

Начало работы

  1. Сделайте tlctutorial/timesN ваша текущая папка, так, чтобы можно было использовать обеспеченные файлы.

    Примечание

    Необходимо использовать или создать рабочую папку за пределами matlabroot для моделей Simulink® вы делаете. Вы не можете создать модели в исходных папках.

  2. В Командном окне MATLAB® создайте файл MEX для S-функции:

    mex timesN.c

    Это старается не брать версию, поставленную с Simulink.

    Примечание

    Ошибка может произойти, если вы ранее не запустили mex -setup.

  3. Откройте файл модели sfun_xN.

  4. Просмотрите ранее сгенерированный код в sfun_xN_grt_rtw/sfun_xN.c. Обратите внимание на то, что никакие циклы не существуют в коде. Это вызвано тем, что сигналы ввода и вывода являются скаляром.

Измените модель

  1. Замените блок Sine Wave на блок Constant.

  2. Установите параметр для блока Constant к 1:4 и измените главную метку, model: sfun_xN, к model: sfun_vec.

  3. Сохраните отредактированную модель как sfun_vectlctutorial/timesN). Модель теперь выглядит так.

  4. Поскольку блок 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);
    }

    Заметьте, что существует четыре экземпляра кода, который генерирует выходные параметры модели, соответствуя четырем итерациям.

  5. Установите параметр для блока Constant к 1:10 и сохраните модель.

  6. Сгенерируйте код для модели и просмотрите /*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. Изменить поведение цикличного выполнения для блоков в модели:

  1. На панели Optimization диалогового окна Configuration Parameters, набор Loop unrolling threshold к 12 и нажмите Apply.

    Параметр RollThreshold теперь 12. Циклы будут сгенерированы только, когда ширина сигналов, проходящих через блок, превысит 12.

    Примечание

    Вы не можете изменить RollThreshold для определенных блоков из диалогового окна Configuration Parameters.

  2. Нажмите Ctrl+B, чтобы регенерировать выход.

  3. Смотрите 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);
    }
  4. Чтобы активировать цикл, прокручивающийся снова, измените Loop unrolling threshold в 10 (или меньше) на панели Optimization.

Прокрутка цикла является важной возможностью TLC оптимизации сгенерированного кода. Не торопитесь, чтобы изучить и исследовать его последствия прежде, чем сгенерировать код для производственных требований.

Больше о прокрутке цикла 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

Задайте индекс в вектор (сигнала), который используется в сгенерированном коде. Если сигнал является скаляром при анализе того блока model.rtw файл, TLC решает, что только одна строка кода требуется. В этом случае это устанавливает sigIdx к 0 чтобы получить доступ только к первому элементу вектора, и никакой цикл не создается.

lcv

Контрольная переменная обычно задана в %roll директива как lcv = RollThreshold. RollThreshold глобальный порог (всей модели) со значением по умолчанию 5. Поэтому каждый раз, когда блок содержит больше чем пять непрерывных и rollable переменных, TLC сворачивает линии, вложенные между %roll и %endroll в цикл. Если меньше чем пять непрерывных rollable переменных существуют, %roll не создает цикл и вместо этого производит отдельные строки кода.

block

Это говорит TLC, что он работает с объектами блока. Код TLC для S-функций использует этот аргумент.

"Roller"

Это, заданное в rtw/c/tlc/roller.tlc, форматирует цикл. Обычно вы передаете это, как, но другие построения управления циклом возможны для усовершенствованного использования (см. LibBlockInputSignal в функциях входного сигнала).

rollVars

Говорит TLC, какие типы элементов должны быть прокручены: входные сигналы, выходные сигналы и/или параметры. Вы не должны использовать всех их. В предыдущей линии, rollVars задан с помощью %assign.

%assign rollVars = ["U", "Y"]
Этот список говорит TLC, что это прокручивается через входные сигналы (U) и выходные сигналы (Y). В случаях, где блоки задают массив параметров вместо скалярного параметра, rollvars задан как
%assign rollVars = ["U", "Y", "P"]

Входные сигналы, выходные сигналы и параметры

Посмотрите на линии, которые появляются между %roll и %endroll:

%<LibBlockOutputSignal(0, "", lcv, idx)> = \
%<LibBlockInputSignal (0, "", lcv, idx)> * 2.0;

Библиотечные функции TLC LibBlockInputSignal и LibBlockOutputSignal расширьтесь, чтобы произвести скалярные или векторные идентификаторы, которые называют и индексируют. LibBlockInputSignal, LibBlockOutputSignal, и много имели отношение, функции TLC передаются четыре канонических аргумента:

АргументОписание

первый аргумент — 0

Соответствует индексу входного порта для данного блока. Первый входной порт имеет индекс 0. Второй входной порт имеет индекс 1 и так далее.

второй аргумент — " "

Индексная переменная зарезервирована для усовершенствованного использования. На данный момент задайте второй аргумент как пустую строку. В усовершенствованных приложениях можно задать собственное имя переменной, которое будет использоваться в качестве индекса с %roll. В таком случае TLC объявляет эту переменную как целое число в месте в сгенерированном коде.

третий аргумент — lcv

Аналогичный описанному ранее, lcv = RollThreshold установлен в %roll указать что цикл быть созданным каждый раз, когда RollThreshold (значение по умолчанию 5), превышен.

четвертый аргумент — sigIdx

Позволяет TLC обработать особые случаи. Если RollThreshold не превышен (например, если блок только соединяется со скалярным входным сигналом), TLC не прокручивает его в цикл. Вместо этого TLC вводит целочисленное значение для индексной переменной в соответствующей линии “встроенного” кода. Каждый раз, когда RollThreshold превышен, TLC создает for цикл и использование индексная переменная, чтобы получить доступ к входным параметрам, выходным параметрам и параметрам в цикле.

Похожие темы