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

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

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

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

Работа с моделью sfun_xN в tlctutorial/timesN. Это имеет один источник (блок генератора Синусоиды), времена 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;

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

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

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

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

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

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

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

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

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

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

Похожие темы