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

Этот пример создает три тестов для регулируемого ограничителя скорости и анализирует полученное покрытие модели с помощью API командной строки инструмента Model Coverage.

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

Simulink ® Subsystem Adjustable Rate Limiter является ограничителем скорости в модели 'slvnvdemo _ ratelim _ обвязка. Он использует три блока switch, чтобы управлять, когда выход должен быть ограничен и тип предела для применения.

Входы генерируются с блоками From Workspace 'gain', 'ring limit' и 'ring limit', которые генерируют кусочно-линейные сигналы. Значения входов определены с шестью переменными, определенными в рабочей области 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);

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

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: (R2021a)
                 id: 1684
               type: TEST_DATA
               test: cvtest object
             rootID: 1686
           checksum: [1x1 struct]
          modelinfo: [1x1 struct]
          startTime: 27-Jan-2021 07:27:10
           stopTime: 27-Jan-2021 07:27:10
  intervalStartTime: 0
   intervalStopTime: 0
simulationStartTime: 0
 simulationStopTime: 2
             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: (R2021a)
                 id: 1800
               type: TEST_DATA
               test: cvtest object
             rootID: 1686
           checksum: [1x1 struct]
          modelinfo: [1x1 struct]
          startTime: 27-Jan-2021 07:27:12
           stopTime: 27-Jan-2021 07:27:12
  intervalStartTime: 0
   intervalStopTime: 0
simulationStartTime: 0
 simulationStopTime: 2
             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: (R2021a)
                 id: 1915
               type: TEST_DATA
               test: cvtest object
             rootID: 1686
           checksum: [1x1 struct]
          modelinfo: [1x1 struct]
          startTime: 27-Jan-2021 07:27:13
           stopTime: 27-Jan-2021 07:27:13
  intervalStartTime: 0
   intervalStopTime: 0
simulationStartTime: 0
 simulationStopTime: 2
             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: (R2021a)
                 id: 0
               type: DERIVED_DATA
               test: []
             rootID: 219
           checksum: [1x1 struct]
          modelinfo: [1x1 struct]
          startTime: 27-Jan-2021 07:27:10
           stopTime: 27-Jan-2021 07:27:13
  intervalStartTime: 0
   intervalStopTime: 0
             filter: 
            simMode: Normal

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

Извлеките информацию о Decision Coverage из пути блока или указателя на блок при помощи 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 возвращает структуру, которая захватывает решения и результаты в блоке Simulink или объекте Stateflow ®.

[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: ''