Улучшите читаемость кода для Flow Графиков

Внешний вид сгенерированного кода для Flow Графиков

Если у вас есть Embedded Coder® и вы генерируете код для моделей, которые включают Stateflow® объекты, код из потока графика напоминает следующие выборки.

Применяются следующие характеристики:

  • По умолчанию сгенерированный код использует if-elseif-else операторы для представления switch шаблоны. Чтобы преобразовать код в используемый switch-case инструкции см. в разделе Преобразование кода if-Elseif-Else в операторы Switch-Case.

  • По умолчанию переменные, которые появляются в график потока, не сохраняют свои имена в сгенерированном коде. Измененные идентификаторы гарантируют отсутствие конфликтов по совпадению имен.

  • Комментарии трассируемости для переходов появляются между каждым набором /* и */ маркеры. Дополнительные сведения о трассируемости см. в разделе Трассировка элементов Stateflow в Сгенерированном коде.

Образец кода для логического шаблона принятия решения

if (modelname_U.In1 == 1.0) {
  /* Transition: '<S1>:11' */
  /* Transition: '<S1>:12' */
  modelname_Y.Out1 = 10.0;

  /* Transition: '<S1>:15' */
  /* Transition: '<S1>:16' */
} else {
  /* Transition: '<S1>:10' */
  if (modelname_U.In1 == 2.0) {
    /* Transition: '<S1>:13' */
    /* Transition: '<S1>:14' */
    modelname_Y.Out1 = 20.0;

    /* Transition: '<S1>:16' */
  } else {
    /* Transition: '<S1>:17' */
    modelname_Y.Out1 = 30.0;
  }
}

Пример кода для итерационного шаблона цикла

for (sf_i = 0; sf_i < 10; sf_i++) {
  /* Transition: '<S1>:40' */
  /* Transition: '<S1>:41' */
  modelname_B.y = modelname_B.y +
    modelname_U.In1;

  /* Transition: '<S1>:39' */
}

Пример кода для шаблона коммутатора

if (modelname_U.In1 == 1.0) {
  /* Transition: '<S1>:149' */
  /* Transition: '<S1>:150' */
  modelname_Y.Out1 = 1.0;

  /* Transition: '<S1>:151' */
  /* Transition: '<S1>:152' */
  /* Transition: '<S1>:158' */
  /* Transition: '<S1>:159' */
} else {
  /* Transition: '<S1>:156' */
  if (modelname_U.In1 == 2.0) {
    /* Transition: '<S1>:153' */
    /* Transition: '<S1>:154' */
    modelname_Y.Out1 = 2.0;

    /* Transition: '<S1>:155' */
    /* Transition: '<S1>:158' */
    /* Transition: '<S1>:159' */
  } else {
    /* Transition: '<S1>:161' */
    modelname_Y.Out1 = 3.0;
  }
}

Преобразование If-Elseif-Else Код для Switch-Case Операторы

Когда вы генерируете код для встроенных целей в реальном времени, можно выбрать преобразование if-elseif-else код для switch-case операторы. Это преобразование может улучшить читаемость кода. Для примера, когда график потока данных содержит длинный список условий, switch-case структура:

  • Уменьшает использование круглых скобок и скобок

  • Минимизирует повторение в сгенерированном коде

Как преобразовать If-Elseif-Else Код для Switch-Case Операторы

ШагЗадачаСсылка
1

Проверьте, что ваш график потока следует правилам преобразования.

Проверьте содержимое Графика потока
2

Включите преобразование и сгенерируйте код для вашей модели.

Включите преобразование
3

Диагностируйте сгенерированный код.

  • Если видите switch-case операторы для вашего графика потока, можно остановить.

  • Если видите if-elseif-else операторы для вашей блок-схемы, обновите график и повторите предыдущий шаг.

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

Правила преобразования

Чтобы преобразование произошло, следуйте этим рекомендациям. LHS и RHS относятся к левой и правой частям условия, соответственно.

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

Должно быть задано значение по умолчанию и два или более уникальных условий.

Для получения дополнительной информации см. Раздел «Повторяющиеся условия».

Каждое условие

Должен проверять только равенство.

Необходимо использовать ту же переменную или выражение для LHS. Можно сторнировать LHS и RHS.

Каждая LHS

Должно быть одной переменной или выражением.

Не может быть константой.

Должен иметь целое число или перечисленный тип данных.

Не может иметь никаких побочных эффектов на симуляции.

Например, LHS может считать, но не записывать в глобальные переменные.

Каждая RHS

Должен быть константой или параметром.

Должен иметь целое число или перечисленный тип данных.

Повторяющиеся условия

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

После удаления дубликатов должны существовать два или более уникальных условия. Если нет, преобразование не происходит, и код содержит все повторяющиеся условия.

Пример сгенерированного кодаКод после преобразования
if (x == 1) {
    block1
} else if (x == 2) {
    block2
} else if (x == 1) {  // duplicate
    block3
} else if (x == 3) {
    block4
} else if (x == 1) {  // duplicate
    block5
} else {
    block6
}
switch (x) {
    case 1:  
     block1; break;
    case 2:  
     block2; break;
    case 3:  
     block4; break;
    default: 
     block6; break;
}
if (x == 1) {
    block1
} else if (x == 1) {  // duplicate
    block2
} else {
    block3
}

Никаких изменений, потому что существует только одно уникальное условие

Пример преобразования кода в Switch-Case Операторы

Предположим, что эта модель содержит один график.

График содержит блок-схему и четыре MATLAB® функций.

Функции MATLAB на графике содержат код, указанный в таблице. В каждом случае Function Inline Option Auto. Дополнительные сведения о встраивании функции см. в разделе «Задание свойств графических функций (Stateflow)».

Функция MATLABКод
stop
function stop
%#codegen
coder.extrinsic('disp');
disp('Not moving.')

traffic_speed = 0;
slowdown
function slowdown
%#codegen
coder.extrinsic('disp')
disp('Slowing down.')

traffic_speed = 1;
accelerate
function accelerate
%#codegen
coder.extrinsic('disp');
disp('Moving along.')

traffic_speed = 2;
light
function color = light(x)
%#codegen
if (x < 20)
    color = TrafficLights.GREEN;
elseif (x >= 20 && x < 25)
    color = TrafficLights.YELLOW;
else
    color = TrafficLights.RED;
end

Область выхода color функции light использует перечисляемый тип TrafficLights. Определение перечисленного типа в TrafficLights.m является:

classdef TrafficLights < Simulink.IntEnumType
  enumeration
    RED(0)
    YELLOW(5)
    GREEN(10)
  end
end

Для получения дополнительной информации смотрите Задать перечисленные типы данных (Stateflow).

Проверьте содержимое Графика потока

Проверяйте, что графики потока на вашей диаграмме Stateflow следуют правилам в Rules of Conversion.

КонструкцияКак конструкция следует правилам
Блок- график

Существует условие по умолчанию и два уникальных условия:

  • [light(intersection) == RED]

  • [light(intersection) == YELLOW]

Каждое условие

Каждое условие:

  • Проверяет равенство

  • Использует тот же вызов функции light(intersection) для LHS

Каждая LHS

Каждая LHS:

  • Содержит одно выражение

  • Является выходным сигналом вызова функции, а не константой

  • Относится к перечисляемому типу TrafficLights, которые вы задаете в TrafficLights.m на пути MATLAB. См. «Определение перечисленных типов данных (Stateflow)».

  • Использует вызов функции, который не имеет побочных эффектов

Каждая RHS

Каждая RHS:

  • Является перечисленным значением и, следовательно, константой

  • Относится к перечисляемому типу TrafficLights

Включите преобразование

  1. Откройте диалоговое окно Параметры конфигурации модели (Model Configuration Parameters).

  2. На панели Code Generation выберите ert.tlc для System target file для целевого объекта на основе ERT для вашей модели.

  3. На панели Code Generation > Code Style установите флажок Convert if-elseif-else patterns to switch-case statements.

    Если установлен этот флажок, преобразование применяется к:

    • Поток графиков во всех графиках модели

    • Функции MATLAB во всех графиках модели

    • Все блоки MATLAB Function в этой модели

  4. В модели на вкладке C Code нажмите Build, чтобы сгенерировать исходный код из модели.

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

Сгенерированный код для графика потока появляется как этот код:

if (sf_color == RED) {
  /* Transition: '<S1>:11' */
  /* Transition: '<S1>:12' */
  /* MATLAB Function 'stop': '<S1>:23' */
  /* '<S1>:23:6' */
  rtb_traffic_speed = 0;

  /* Transition: '<S1>:15' */
  /* Transition: '<S1>:16' */
} else {
  /* Transition: '<S1>:10' */
  /* MATLAB Function 'light': '<S1>:19' */
  if (ifelse_using_enums_U.In1 < 20.0) {
    /* '<S1>:19:3' */
    /* '<S1>:19:4' */
    sf_color = GREEN;
  } else if ((ifelse_using_enums_U.In1 >= 20.0) && 
             (ifelse_using_enums_U.In1 < 25.0)) {
    /* '<S1>:19:5' */
    /* '<S1>:19:6' */
    sf_color = YELLOW;
  } else {
    /* '<S1>:19:8' */
    sf_color = RED;
  }

  if (sf_color == YELLOW) {
    /* Transition: '<S1>:13' */
    /* Transition: '<S1>:14' */
    /* MATLAB Function 'slowdown': '<S1>:24' */
    /* '<S1>:24:6' */
    rtb_traffic_speed = 1;

    /* Transition: '<S1>:16' */
  } else {
    /* Transition: '<S1>:17' */
    /* MATLAB Function 'accelerate': '<S1>:25' */
    /* '<S1>:25:6' */
    rtb_traffic_speed = 2;
  }
}

Потому что функция MATLAB light появляется встроенным, сравнения неравенства появляются в этих строках кода:

if (ifelse_using_enums_U.In1 < 20.0) {
....
} else if ((ifelse_using_enums_U.In1 >= 20.0) && 
             (ifelse_using_enums_U.In1 < 25.0)) {
....

Потому что неравенство появляется в теле if-elseif-else код для графика потока, преобразования в switch-case операторы не появляются. Выполните одно из следующих действий:

Измените свойство Inlining для функции.  Если вы не хотите изменять график потока, измените свойство inlining для функции light:

  1. Щелкните правой кнопкой мыши функциональное поле для light и выберите Properties.

  2. В диалоговом окне свойств для Function Inline Option выберите Function.

  3. Нажмите кнопку OK, чтобы закрыть диалоговое окно.

Примечание

Вы не должны изменять свойство inlining для других трех функций MATLAB на графике. Поскольку график потока не вызывает эти функции во время оценки условий, свойство inlining для этих функций может остаться Auto.

Когда вы регенерируете код для модели, код для графика потока теперь появляется как этот код:

switch (ifelse_using_enums_light(ifelse_using_enums_U.In1)) {
 case RED:
  /* Transition: '<S1>:11' */
  /* Transition: '<S1>:12' */
  /* MATLAB Function 'stop': '<S1>:23' */
  /* '<S1>:23:6' */
  ifelse_using_enums_Y.Out1 = 0.0;

  /* Transition: '<S1>:15' */
  /* Transition: '<S1>:16' */
  break;

 case YELLOW:
  /* Transition: '<S1>:10' */
  /* Transition: '<S1>:13' */
  /* Transition: '<S1>:14' */
  /* MATLAB Function 'slowdown': '<S1>:24' */
  /* '<S1>:24:6' */
  ifelse_using_enums_Y.Out1 = 1.0;

  /* Transition: '<S1>:16' */
  break;

 default:
  /* Transition: '<S1>:17' */
  /* MATLAB Function 'accelerate': '<S1>:25' */
  /* '<S1>:25:6' */
  ifelse_using_enums_Y.Out1 = 2.0;
  break;
}

Потому что функция MATLAB light больше не отображается встроенным, преобразование в switch-case имеют место операторы. Чтобы улучшить читаемость, switch-case операторы обеспечивают следующие преимущества:

  • Код сокращает использование круглых скобок и скобок.

  • Выражение LHS ifelse_using_enums_light(ifelse_using_enums_U.In1) появляется только один раз, минимизируя повторение в коде.

Измените График потока, чтобы убедиться, что операторы Switch-Case.  Если вы не хотите изменять свойство inlining для функции light, измените свой поток графику:

  1. Добавьте локальные данные графики color_out с перечисленным типом TrafficLights.

  2. Замените каждый образец light(intersection) с color_out.

  3. Добавьте действие {color_out = light(intersection)} к переходу по умолчанию график потока.

Теперь график выглядит аналогично этому графику:

Когда вы регенерируете код для модели, код для графика потока операций использует switch-case операторы.

Похожие темы