Введение в Simulink Code Inspector

В этом примере показано, как использовать Simulink Code Inspector, чтобы проверить, что код, сгенерированный из моделей, удовлетворяет целям исходного кода от DO - 178C, Факторы программного обеспечения в Бортовых Системах и Сертификации оборудования. Во-первых, код для иерархии модели автоматически сгенерирован Embedded Coder. Затем сгенерированный код независимо проверяется Simulink Code Inspector. Наконец, ошибка намеренно вводится в сгенерированный код и затем смотрится для отказа.

Настройте Временную Папку для Сгенерированных Файлов

Создайте временную папку (во временной папке вашей системы) для сборки и инспекционного процесса. Локально скопируйте модель slcidemo_roll_orig в sldemo_roll так, чтобы можно было изменить его.

currentDir = pwd;
[tempDir, cgDir] = slcidemodir();
load_system('slcidemo_roll_orig')
save_system('slcidemo_roll_orig', 'slcidemo_roll');

О модели

Эта модель представляет основной автопилот продольной оси с двумя рабочими режимами: прокрутитесь отношение содержат, и заголовок содержат. Логика режима для этих режимов является внешней к этой модели. Архитектура модели представляет заголовок, содержат режим и основную функцию отношения списка как модели, на которые ссылаются.

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

Рисунок 1 показывает верхний уровень модели Simulink.

open_system('slcidemo_roll');

Рисунок 1: схема верхнего уровня для модели автопилота продольной оси

Рисунок 2 показывает основное вычисление ссылки угла вращения, реализованное как виртуальную подсистему RollAngleReference. Embedded Coder встроит это вычисление непосредственно в основную функцию для slcidemo_roll.

open_system('slcidemo_roll/RollAngleReference');

Рисунок 2: Виртуальная подсистема RollAngleReference, реализующий ссылку угла вращения

Рисунок 3 показывает содержимое модели HeadingMode, которая вычисляет команду списка, чтобы отследить желаемый заголовок. Это - отдельная модель, на которую ссылается slcidemo_roll.

close_system('slcidemo_roll/RollAngleReference');
open_system('slcidemo_heading');

Рисунок 3: HeadingMode Модели, который вычисляет команду списка, чтобы отследить желаемый заголовок.

Рисунок 4 показывает содержимое модели BasicRollMode, которая вычисляет функцию управления ориентацией списком. Это - отдельная модель, на которую ссылается slcidemo_roll.

close_system('slcidemo_heading');
open_system('slcidemo_attitude');

Рисунок 4: Модель BasicRollMode, реализующий функцию управления ориентацией списком (ПИД)

Подготовьте модель к генерации кода и контролю

Simulink Code Inspector поддерживает ограниченный набор моделирования семантики и оптимизации кода. Можно использовать его программу контроля совместимости, чтобы определить, выполняет ли модель тот ограниченный набор. Проверка совместимости и инспекция кода могут быть вызваны в интерактивном режиме от основного графического интерфейса пользователя Simulink Code Inspector. Этот пример иллюстрирует, как программно автоматизировать полный процесс генерации кода и контроль.

Включить инспекцию кода, параметр модели AdvancedOptControl должен быть установлен в значение '-SLCI' на модели верхнего уровня, slcidemo_roll, который ограничивает набор оптимизации, которую использует Embedded Coder.

set_param('slcidemo_roll','AdvancedOptControl','-SLCI');

fprintf('\nInvoking compatibility checker ...\n');

config = slci.Configuration('slcidemo_roll');
result = config.checkCompatibility('DisplayResults','None');

for i = 1:numel(result)
    fprintf('\nModel ''%s'' passed %d checks with %d issues.',...
        result{i}.system,...
        result{i}.numPass, result{i}.numWarn + result{i}.numFail)
end
Invoking compatibility checker ...

Model 'slcidemo_roll' passed 46 checks with 0 issues.

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

Модель предварительно сконфигурирована, чтобы сгенерировать код с помощью Embedded Coder. Можно сгенерировать код неявно как часть инспекции кода, однако этот пример иллюстрирует, как разделить генерацию кода и инспекцию кода в отдельные шаги. Используйте метод setGenerateCode указывать, что Simulink Code Inspector генерирует код до контроля.

rtwbuild('slcidemo_roll');
### Model reference code generation target (slcidemo_attitude.c) for model slcidemo_attitude is out of date because slcidemo_attitude.c does not exist.
### Starting build procedure for model: slcidemo_attitude
### Successful completion of code generation for model: slcidemo_attitude
### Model reference code generation target (slcidemo_heading.c) for model slcidemo_heading is out of date because slcidemo_heading.c does not exist.
### Starting build procedure for model: slcidemo_heading
### Successful completion of code generation for model: slcidemo_heading
### Starting build procedure for model: slcidemo_roll
### Successful completion of code generation for model: slcidemo_roll

Просмотрите сгенерированный код в подробном отчете HTML с двусторонней отслеживаемостью между моделью и кодом.

web(fullfile(cgDir,'slcidemo_roll_ert_rtw','html','slcidemo_roll_codegen_rpt.html'))

Инспекция кода независима от генерации кода. Теперь сконфигурируйте модель, чтобы не регенерировать код для эталонных моделей.

set_param('slcidemo_roll','UpdateModelReferenceTargets','AssumeUpToDate');
save_system('slcidemo_roll')

Смотрите сгенерированный код

Смотрите сгенерированный код. По умолчанию Simulink Code Inspector принимает, что код был предварительно сгенерирован в папки по умолчанию, где Embedded Coder записывает свои файлы. Если вы хотите задать альтернативное местоположение, используйте методы setCodePlacement и setCodeFolder.

В этом примере используйте метод setReportFolder поместить отчеты инспекции кода в локальную папку отчета. Метод setShowReport задает, запускается ли отчет автоматически. Кроме того, укажите, что slcidemo_roll является моделью верхнего уровня.

config.setTopModel(true);
config.setReportFolder(fullfile('.','report'));
result = config.inspect('DisplayResults','None');
fprintf('Model %s status: %s\n',result.ModelName, result.Status);
 recording macro in il 
 recording macro in il 
Model slcidemo_roll status: PASSED

Этот пример приводит к переданному результату, как ожидалось, который разрабатывается в подробном отчете верификации.

web(fullfile('.', 'report','slcidemo_roll_report.html'));

Введите намеренную ошибку в код

Чтобы показать не пройдено результат, введите намеренную ошибку в сгенерированном коде. В этом примере измените блок Logical Operator в подсистеме RollAngleReference, рисунке 5, в сгенерированном коде от операции OR () к операции И (&&). Используйте функцию slcidemo_modifycode.

% Highlight the block for which the code will be modified
hilite_system('slcidemo_roll/RollAngleReference/Or');

% Modify the generated code using a helper function (change || to &&)
cfile = fullfile(cgDir,'slcidemo_roll_ert_rtw','slcidemo_roll.c');
slcidemo_modifycode(cfile,'<S1>/Or','||','&&')
Modified line 52 of file /tmp/slcidemo/slcidemo_roll_ert_rtw/slcidemo_roll.c.
Before:     if ((rtU_Phi >= 6.0F) || (rtU_Phi <= -6.0F)) {
After :     if ((rtU_Phi >= 6.0F) && (rtU_Phi <= -6.0F)) {

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

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

result = config.inspect('DisplayResults','None');
fprintf('Model %s status: %s\n',result.ModelName, result.Status);
 recording macro in il 
 recording macro in il 
Model slcidemo_roll status: FAILED

Отказ ожидается. См. подробный отчет верификации.

[~,h,~]=web(fullfile('.','report','slcidemo_roll_report.html'));

Самоведомое осуществление

Попробуйте подобное осуществление путем изменения модели или других аспектов сгенерированного кода.

Очистите Папки В качестве примера и Файлы

Закройте модели и удалите временные директории и файлы.

close_system('slcidemo_roll_orig',0)
close_system('slcidemo_roll',0)
close_system('slcidemo_attitude',0)
close_system('slcidemo_heading',0)
close(h)

cd(currentDir); rmdir(tempDir,'s');