Улучшите удобочитаемость кода для блок-схем

Внешний вид сгенерированного кода для блок-схем

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

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

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

  • По умолчанию переменные, которые появляются в блок-схеме, не сохраняют свои имена в сгенерированном коде. Модифицированные идентификаторы убеждаются, что никакие конфликты по совпадению имен не происходят.

  • Комментарии трассируемости для переходов появляются между каждым набором /* и */ маркеры. Чтобы узнать больше о трассируемости, смотрите Трассировку Элементы 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;
  }
}

Convert If-Elseif-Else Код к Switch-Case Операторы

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

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

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

Как к Convert 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. Для получения дополнительной информации о функциональном встраивании, смотрите Specify Graphical Function Properties (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 следует правилам в Правилах Преобразования.

СоздатьКак построение следует правилам
Блок-схема

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

  • [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 операторы не происходят. Выполнить одно из следующих действий:

Измените Свойство Встраивания для Функции.  Если вы не хотите изменять свою блок-схему, изменять свойство встраивания для функционального light:

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

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

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

Примечание

Вы не должны изменять свойство встраивания для других трех функций MATLAB в графике. Поскольку блок-схема не вызывает те функции во время оценки условий, свойство встраивания для тех функций может остаться 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) появляется только однажды, минимизируя повторение в коде.

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

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

  2. Замените каждый экземпляр light(intersection) с color_out.

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

График теперь выглядит похожим на этот график:

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

Похожие темы