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

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

Если у вас есть лицензия 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;
  }
}

Преобразуйте код If-Elseif-Else в операторов case оператора switch

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

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

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

Как преобразовать код If-Elseif-Else в операторов case оператора switch

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

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

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

Проверьте содержимое блок-схемы
2

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

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

Сгенерируйте код для своей модели.

Сгенерируйте код для своей модели
4

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

  • Если вы видите операторы 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
}

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

Пример преобразования кода к операторам case оператора switch

Предположим, что у вас есть следующая модель с сингл чартом.

График содержит блок-схему и четыре функции 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).

Проверьте содержимое блок-схемы

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

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

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

  • [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 в той модели

Сгенерируйте код для своей модели

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

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

Сгенерированный код для блок-схемы появляется что-то вроде этого:

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.