S-функции могут использоваться в моделях с несколькими скоростями выборки и развертываться в многозадачных целевых средах. Аналогично, сами S-функции могут иметь несколько скоростей, с которыми они работают. Генератор кода создает код для многоскоростных многозадачных моделей, используя подход, называемый группировкой скоростей. В коде, сгенерированном для целей на основе ERT, группировка тарифов создает отдельные model_step функции для задачи базовой скорости и каждой подскоростной задачи в модели. Несмотря на то, что группировка тарифов является функцией генерации кодов, найденной только в целях ERT, 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-функции должны соблюдать для входов:
Входной сигнал должен считываться только со скоростью, связанной с временем выборки входного порта.
Как правило, входные данные записываются в 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;}