exponenta event banner

S-функции для многоскоростных многозадачных сред

Сведения о S-функциях для многозадачных сред

S-функции могут использоваться в моделях с несколькими скоростями выборки и развертываться в многозадачных целевых средах. Аналогично, сами S-функции могут иметь несколько скоростей, с которыми они работают. Генератор кода создает код для многоскоростных многозадачных моделей, используя подход, называемый группировкой скоростей. В коде, сгенерированном для целей на основе ERT, группировка тарифов создает отдельные model_step функции для задачи базовой скорости и каждой подскоростной задачи в модели. Несмотря на то, что группировка тарифов является функцией генерации кодов, найденной только в целях ERT, S-функции могут использовать ее в других контекстах при кодировании, как описано ниже.

Поддержка группировки тарифов в S-функциях

Чтобы воспользоваться преимуществами группировки тарифов, необходимо встроить многоскоростные S-функции, если это не было сделано. Для использования группировки скоростей необходимо следовать определенным протоколам компилятора целевого языка. Кодирование TLC для использования группировки тарифов не препятствует правильному функционированию встроенных S-функций в GRT. Аналогично, встроенные S-функции по-прежнему будут генерировать действительный код ERT, даже если они не соответствуют группировке тарифов. Однако в этом случае для многоскоростных моделей будет создан более эффективный код.

Инструкции и примеры кода компилятора целевого языка, иллюстрирующие создание и обновление S-функций для создания кода, совместимого с группировкой скоростей, см. в разделе Проблемы соответствия группировке скоростей и совместимости (встроенный кодер).

Для каждой многоскоростной S-функции, не совместимой с группировкой скоростей, генератор кода выдает следующее предупреждение при построении:

Warning:  Simulink Coder: Code of output function for multirate block
'<Root>/S-Function' is guarded by sample hit checks rather than being rate
grouped. This will generate the same code for all rates used by the block,
possibly generating dead code. To avoid dead code, you must update the TLC
file for the block.

В коде, сгенерированном для каждой несоответствующей S-функции, также можно найти следующий комментарий:

/* Because the output function of multirate block
   <Root>/S-Function is not rate grouped,
   the following code might contain unreachable blocks of code.
   To avoid this, you must update your block TLC file. */

В этих предупреждениях слова «функция обновления» заменяются словами «функция вывода».

Создание многозадачных, многоскоростных, основанных на портах выборочных временных S-функций

Следующие инструкции показывают, как поддерживать детерминизм данных и целостность данных в многоскоростных S-функциях. Они не охватывают случаи, когда нет детерминизма или целостности. Поддержка обработки кадров не влияет на требования.

Примечание

Медленные скорости должны быть кратны самой быстрой скорости. Инструкции не применяются, когда две скорости, которые соединяются, не являются кратными или когда скорости не являются периодическими.

Правила правильной обработки быстрых-медленных переходов

Правила, которые многоскоростные S-функции должны соблюдать для входов:

  • Входной сигнал должен считываться только со скоростью, связанной с временем выборки входного порта.

  • Как правило, входные данные записываются в DWork, и DWork затем можно получить доступ на более медленной (нисходящей) скорости.

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

Правила, которые многоточечные S-функции должны соблюдать для выходов:

  • Выходные данные не должны записываться с помощью скорости, отличной от скорости, назначенной выходному порту, за исключением оптимизированного случая, описанного ниже.

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

При выполнении этих условий блок S-Function может указать, что порт ввода и порт вывода могут быть как локальными, так и повторно используемыми.

Можно включить оптимизацию, если обработка данных практически не требуется. В таких случаях код входной скорости может непосредственно записываться на выход (вместо использования DWork) при наличии специального попадания выборки. Однако при этом необходимо объявить порт экспорта глобальным и не подлежащим повторному использованию. Эта оптимизация приводит к одному меньшему memcpy но вводит неуниформные требования к обработке с более высокой скоростью.

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

Примеры быстрого-медленного перехода на псевдокод

Псевдокод ниже абстрагирует, как следует писать код C MEX для обработки быстрых-медленных переходов, иллюстрируя скорость ввода 0,1 секунды, приводя к скорости вывода в одну секунду. Аналогичный подход может быть использован при встраивании кода. Блок имеет следующие характеристики:

  • Файл: sfun_multirate_zoh.c, Уравнение: y = u(tslow)

  • Входные данные: локальные и многократно используемые

  • Выходные данные: локальные и многократно используемые

  • DirectFeedthrough: да

    OutputFcn
    if (ssIsSampleHit(".1")) {
        if (ssIsSepcialSampleHit("1")) {
            DWork = u;
        }
    }
    if (ssIsSampleHit("1")) {
        y = DWork;
    }

Альтернативный, немного оптимизированный подход для простых алгоритмов:

  • Входные данные: локальные и многократно используемые

  • Вывод: глобальный и не может быть использован повторно, потому что он должен сохраняться между специальными попаданиями образцов

  • DirectFeedthrough: да

    OutputFcn
    if (ssIsSampleHit(".1")) {
        if (ssIsSpecialSampleHit("1")) {
            y = u;
        }
    }

Пример добавления простого алгоритма:

  • Файл: sfun_multirate_avg.c; Уравнение: y = average(u)

  • Входные данные: локальные и многократно используемые

  • Выходные данные: локальные и многократно используемые

  • DirectFeedthrough: да

    (Предположим, DWork[0:10] и DWork[mycounter] инициализированы как ноль)

    OutputFcn
    if (ssIsSampleHit(".1")) {
        /* In general, processing on 'u' could be done here,
            it runs on every hit of the fast rate. */
        DWork[DWork[mycounter]++] = u;
        if (ssIsSpecialSampleHit("1")) {
        /* In general, processing on DWork[0:10] can be done 
           here, but it does cause the faster rate to have 
           nonuniform processing requirements (every 10th hit, 
           more code needs to be run).*/
            DWork[10] = sum(DWork[0:9])/10;
            DWork[mycounter] = 0;
        }
    }
    if (ssIsSampleHit("1")) {
        /* Processing on DWork[10] can be done here before
           outputing. This code runs on every hit of the 
           slower task. */
        y = DWork[10];
    }

Правила правильной обработки медленно-быстрых переходов

Если скорость на выходе выше скорости на входе, скорость на входе должна считываться только со скоростью, связанной с временем выборки входного порта, при соблюдении следующих правил:

  • Всегда считывать входные данные из функции обновления.

  • Не используйте специальные выборочные проверки при чтении входных данных.

  • Запишите входные данные в DWork.

  • При наличии специального совпадения выборки между скоростями скопируйте DWork во второй DWork в функции вывода.

  • Запишите второй DWork в выходной сигнал при каждом совпадении с частотой выборки выходного сигнала.

Блок может запросить сделать входной порт локальным, но его нельзя использовать повторно. Выходной порт может быть установлен на локальный и повторно используемый.

Как и в случае быстрого-медленного перехода, входной сигнал не должен считываться с помощью скорости, отличной от той, которая назначена входному порту. Аналогично, выходные данные не должны записываться со скоростью, отличной от скорости, назначенной выходному порту.

Оптимизация может быть выполнена, когда реализуемый алгоритм требуется только для выполнения с медленной скоростью. В таких случаях используется только один DWork. Входные данные по-прежнему записываются в DWork в функции обновления. При наличии специального совпадения выборки между скоростями функция вывода копирует тот же DWork непосредственно на выход. В этом случае порт вывода должен быть глобальным и не использоваться повторно. Эта оптимизация приводит к одному меньшему memcpy операция на специальное попадание образца.

В любом случае данные, над которыми работают вычисления быстрой скорости, всегда задерживаются, то есть данные поступают с предыдущего этапа медленного кода скорости.

Псевдокод Примеры медленного-быстрого перехода скорости

Псевдокод ниже абстрагирует то, что должна сделать ваша S-функция для обработки медленно-быстрых переходов, иллюстрируя входную скорость в одну секунду, приводя к выходной скорости в 0,1 секунды. Блок имеет следующие характеристики:

  • Файл: sfun_multirate_delay.c, Уравнение: y = u(tslow-1)

  • Вход: Установлено на локальный, будет локальным, если выход/обновление объединены (ERT) в противном случае будет глобальным. Значение не используется повторно, так как ввод должен быть сохранен до запуска функции обновления.

  • Выходные данные: локальные и многократно используемые

  • DirectFeedthrough: нет

    OutputFcn
    if (ssIsSampleHit(".1") {
        if (ssIsSpecialSampleHit("1") {
            DWork[1] = DWork[0];
        }
        y = DWork[1];
    }
    UpdateFcn
    if (ssIsSampleHit("1")) {
        DWork[0] = u;
    }

Альтернативный оптимизированный подход может быть использован некоторыми алгоритмами:

  • Вход: Установлено на локальный, будет локальным, если выход/обновление объединены (ERT) в противном случае будет глобальным. Значение не используется повторно, так как ввод должен быть сохранен до запуска функции обновления.

  • Вывод: глобальный и не может быть использован повторно, потому что он должен сохраняться между специальными попаданиями образцов.

  • DirectFeedthrough: нет

    OutputFcn
    if (ssIsSampleHit(".1") {
        if (ssIsSpecialSampleHit("1") {
            y = DWork;
        }
    }
    UpdateFcn
    if (ssIsSampleHit("1")) {
        DWork = u;
    }

Пример добавления простого алгоритма:

  • Файл: sfun_multirate_modulate.c, Уравнение: y = sin(tfast) + u(tslow-1)

  • Ввод: Установлено на локальный, будет локальным, если вывод/обновление объединены (функция ERT), в противном случае будет глобальным. Значение не используется повторно, так как ввод должен быть сохранен до запуска функции обновления.

  • Выходные данные: локальные и многократно используемые

  • DirectFeedthrough: нет

    OutputFcn
    if (ssIsSampleHit(".1") {
        if (ssIsSpecialSampleHit("1") {
        /* Processing not likely to be done here. It causes 
         * the faster rate to have nonuniform processing 
         * requirements (every 10th hit, more code needs to 
         * be run).*/
            DWork[1] = DWork[0];
        }
        /* Processing done at fast rate */
        y = sin(ssGetTaskTime(".1")) + DWork[1];
    }
    UpdateFcn
    if (ssIsSampleHit("1")) {
        /* Processing on 'u' can be done here. There is a delay of
           one slow rate period before the fast rate sees it.*/
        DWork[0] = u;}