Пример по верификации командной строки

Этот пример создает три теста для ограничителя регулируемой процентной ставки и анализирует получившееся покрытие модели с помощью API командной строки Инструмента model coverage.

Переместите текущую директорию MATLAB® в местоположение, которое содержит файлы в качестве примера.

openExample('slcoverage/CommandLineVerificationExample');

Модель Simulink® для ограничителя регулируемой процентной ставки

Ограничитель Регулируемой процентной ставки подсистемы Simulink® является ограничителем уровня в модели 'slvnvdemo_ratelim_harness'. Это использует три блока switch, чтобы управлять, когда выход должен быть ограничен и тип предела, чтобы применяться.

Входные параметры производятся с Из блоков Рабочей области 'усиление', 'возрастающий предел', и 'падающий предел', которые генерируют кусочные линейные сигналы. Значения входных параметров заданы с шестью переменными, заданными в рабочей области MATLAB®: t_gain, u_gain, t_pos, u_pos, t_neg, и u_neg.

Откройте модель и подсистему Ограничителя Регулируемой процентной ставки.

modelName = 'slvnvdemo_ratelim_harness';
open_system(modelName);
open_system([modelName,'/Adjustable Rate Limiter']);

Создание первого теста

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

t_gain = (0:0.02:2.0)';
u_gain = sin(2*pi*t_gain);

Вычислите минимальное и максимальное изменение входа варьирования времени с помощью функции diff MATLAB.

max_change = max(diff(u_gain))
min_change = min(diff(u_gain))
max_change =

    0.1253


min_change =

   -0.1253

Поскольку изменения сигнала очень меньше 1 и намного больше, чем-1, установите ограничения скорости для 1 и-1. Переменные все хранятся в файле MAT 'within_lim.mat', который загружается перед симуляцией.

t_pos = [0;2];
u_pos = [1;1];
t_neg = [0;2];
u_neg = [-1;-1];

save('within_lim.mat','t_gain','u_gain','t_pos','u_pos','t_neg','u_neg');

Дополнительные тесты

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

t_gain = [0;2];
u_gain = [0;4];
t_pos = [0;1;1;2];
u_pos = [1;1;5;5]*0.02;
t_neg = [0;2];
u_neg = [0;0];

save('rising_gain.mat','t_gain','u_gain','t_pos','u_pos','t_neg','u_neg');

Третий тест является зеркальным отображением второго с возрастающим усилением, замененным падающим усилением.

t_gain = [0;2];
u_gain = [-0.02;-4.02];
t_pos = [0;2];
u_pos = [0;0];
t_neg = [0;1;1;2];
u_neg = [-1;-1;-5;-5]*0.02;

save('falling_gain.mat','t_gain','u_gain','t_pos','u_pos','t_neg','u_neg');

Определение тестов покрытия

Тесты организованы и выполнили использование sim.

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

covSet = Simulink.SimulationInput(modelName);
covSet = setModelParameter(covSet,'CovEnable','on');
covSet = setModelParameter(covSet,'CovMetricStructuralLevel','Decision');
covSet = setModelParameter(covSet,'CovSaveSingleToWorkspaceVar','on');
covSet = setModelParameter(covSet,'CovScope','Subsystem');
covSet = setModelParameter(covSet,'CovPath','/Adjustable Rate Limiter');
covSet = setModelParameter(covSet,'StartTime','0.0');
covSet = setModelParameter(covSet,'StopTime','2.0');

Выполнение тестов покрытия

Загрузите данные для первого теста, определите имя переменной покрытия и выполните модель с помощью sim.

load within_lim.mat
covSet = setModelParameter(covSet,'CovSaveName','dataObj1');
simOut1 = sim(covSet);
dataObj1
dataObj1 = ... cvdata
            version: (R2020b)
                 id: 1170
               type: TEST_DATA
               test: cvtest object
             rootID: 1172
           checksum: [1x1 struct]
          modelinfo: [1x1 struct]
          startTime: 30-Jul-2020 03:38:03
           stopTime: 30-Jul-2020 03:38:03
  intervalStartTime: 0
   intervalStopTime: 0
simulationStartTime: 0
 simulationStopTime: 2
            metrics: [1x1 struct]
             filter: 
            simMode: Normal

Проверьте первый тест путем проверки, что выход совпадает с входом.

subplot(211)
plot(simOut1.tout,simOut1.yout(:,1),simOut1.tout,simOut1.yout(:,4))
xlabel('Time (sec)'), ylabel('Value'),
title('Gain input and output');
subplot(212)
plot(simOut1.tout,simOut1.yout(:,1)-simOut1.yout(:,4))
xlabel('Time (sec)'),ylabel('Difference'),
title('Difference between the gain input and output');

Выполните и постройте результаты для второго теста таким же образом.

Заметьте, что, если ограниченный выход отличался от входа, который он может только восстановить на максимальной скорости нарастания. Поэтому график имеет необычную петлю. Однажды соответствие ввода и вывода, эти два изменяются вместе.

load rising_gain.mat
covSet = setModelParameter(covSet,'CovSaveName','dataObj2');
simOut2 = sim(covSet);
dataObj2

subplot(211)
plot(simOut2.tout,simOut2.yout(:,1),simOut2.tout,simOut2.yout(:,4))
xlabel('Time (sec)'), ylabel('Value'),
title('Gain input and output');
subplot(212)
plot(simOut2.tout,simOut2.yout(:,1)-simOut2.yout(:,4))
xlabel('Time (sec)'), ylabel('Difference'),
title('Difference between the gain input and output');
dataObj2 = ... cvdata
            version: (R2020b)
                 id: 1286
               type: TEST_DATA
               test: cvtest object
             rootID: 1172
           checksum: [1x1 struct]
          modelinfo: [1x1 struct]
          startTime: 30-Jul-2020 03:38:06
           stopTime: 30-Jul-2020 03:38:06
  intervalStartTime: 0
   intervalStopTime: 0
simulationStartTime: 0
 simulationStopTime: 2
            metrics: [1x1 struct]
             filter: 
            simMode: Normal

Выполните и постройте результаты для третьего теста.

load falling_gain.mat
covSet = setModelParameter(covSet,'CovSaveName','dataObj3');
simOut3 = sim(covSet);
dataObj3

subplot(211)
plot(simOut3.tout,simOut3.yout(:,1),simOut3.tout,simOut3.yout(:,4))
xlabel('Time (sec)'), ylabel('Value'),
title('Gain input and output');
subplot(212)
plot(simOut3.tout,simOut3.yout(:,1)-simOut3.yout(:,4))
xlabel('Time (sec)'), ylabel('Difference'),
title('Difference between the gain input and output');
dataObj3 = ... cvdata
            version: (R2020b)
                 id: 1401
               type: TEST_DATA
               test: cvtest object
             rootID: 1172
           checksum: [1x1 struct]
          modelinfo: [1x1 struct]
          startTime: 30-Jul-2020 03:38:08
           stopTime: 30-Jul-2020 03:38:08
  intervalStartTime: 0
   intervalStopTime: 0
simulationStartTime: 0
 simulationStopTime: 2
            metrics: [1x1 struct]
             filter: 
            simMode: Normal

Генерация отчета покрытия

При предположении, что все тесты передали, представьте объединенный отчет от всех тестов, чтобы проверить достижение 100%-го покрытия. Проценты покрытия для каждого теста отображены под направляющейся "Иерархией модели". Несмотря на то, что ни один из тестов индивидуально не достиг 100%-го покрытия в агрегате, они достигают полного обзора.

cvhtml('combined_ratelim',dataObj1,dataObj2,dataObj3);

Сохранение данных о покрытии

Сохраните собранные данные о покрытии в файле "ratelim_testdata.cvt" при помощи cvsave.

cvsave('ratelim_testdata',dataObj1,dataObj2,dataObj3);

Закройте модель и выйдите из среды покрытия

close_system('slvnvdemo_ratelim_harness',0);
clear dataObj*

Загрузка данных о покрытии

Восстановите сохраненные тесты покрытия из файла "ratelim_testdata.cvt" после открытия модели при помощи cvload. Данные и тесты получены в массиве ячеек.

open_system('slvnvdemo_ratelim_harness');
[SavedTests,SavedData] = cvload('ratelim_testdata')
SavedTests =

  1x3 cell array

    {1x1 cvtest}    {1x1 cvtest}    {1x1 cvtest}


SavedData =

  1x3 cell array

    {1x1 cvdata}    {1x1 cvdata}    {1x1 cvdata}

Управление объектами данных покрытия

Управляйте объектами cvdata с помощью перегруженных операторов: +, - и *. Оператор * используется, чтобы найти пересечение двух объектов данных покрытия, которое приводит к другому объекту cvdata. Например, следующая команда производит отчет HTML общего покрытия от всех трех тестов.

common = SavedData{1} * SavedData{2} * SavedData{3}
cvhtml('intersection',common)
common = ... cvdata
            version: (R2020b)
                 id: 0
               type: DERIVED_DATA
               test: []
             rootID: 1519
           checksum: [1x1 struct]
          modelinfo: [1x1 struct]
          startTime: 30-Jul-2020 03:38:03
           stopTime: 30-Jul-2020 03:38:08
  intervalStartTime: 0
   intervalStopTime: 0
            metrics: [1x1 struct]
             filter: 
            simMode: Normal

Извлечение информации от объектов данных покрытия

Получите информацию о Decision Coverage из блока path или указателя блока при помощи decisioninfo. Выход является вектором с достигнутыми и общими результатами для одного объекта модели, соответственно.

cov = decisioninfo(SavedData{1} + SavedData{2} + SavedData{3}, ...
                   'slvnvdemo_ratelim_harness/Adjustable Rate Limiter')
cov =

     6     6

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

percentCov = 100 * (cov(1)/cov(2))
percentCov =

   100

Когда два выходных аргумента используются, decisioninfo возвращает структуру, которая получает решения и результаты в объекте Stateflow® или блоке Simulink.

[blockCov,desc] = decisioninfo(common, ...
         'slvnvdemo_ratelim_harness/Adjustable Rate Limiter/Delta sign')
descDecision = desc.decision
outcome1 = desc.decision.outcome(1)
outcome2 = desc.decision.outcome(2)
blockCov =

     0     2


desc = 

  struct with fields:

           isFiltered: 0
    justifiedCoverage: 0
          isJustified: 0
      filterRationale: ''
             decision: [1x1 struct]


descDecision = 

  struct with fields:

               text: 'Switch trigger'
    filterRationale: ''
         isFiltered: 0
        isJustified: 0
            outcome: [1x2 struct]


outcome1 = 

  struct with fields:

               text: 'false (out = in3)'
     executionCount: 0
         executedIn: []
         isFiltered: 0
        isJustified: 0
    filterRationale: ''


outcome2 = 

  struct with fields:

               text: 'true (out = in1)'
     executionCount: 0
         executedIn: []
         isFiltered: 0
        isJustified: 0
    filterRationale: ''