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

timesN Руководство по циклам

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

<reservedrangesplaceholder1> <reservedrangesplaceholder0> / toolbox/rtw/rtwdemos/tlctutorial/timesN (открыто)

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

Учебное руководство поможет вам выполнить следующие шаги:

  1. Getting Started - настройте упражнение и запустите модель

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

  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 панели диалогового окна Параметров конфигурации задайте 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 код является 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. Поэтому всякий раз, когда блок содержит более пяти смежных и прокатываемых переменных, TLC сворачивает линии, вложенные между %roll и %endroll в цикл. Если существует менее пяти смежных качающихся переменных, %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 цикл и использует индексную переменную для доступа к входам, выходам и параметрам в цикле.

Похожие темы