exponenta event banner

Учебное пособие по проверке командной строки

В этом примере создаются три тестовых случая для регулируемого ограничителя скорости и анализируется результирующий охват модели с помощью API командной строки инструмента «Покрытие модели».

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

Регулируемый ограничитель скорости подсистемы Simulink ® является ограничителем скорости в модели slvnvdemo _ ratelim _ harness. Он использует три блока переключения для управления тем, когда выход должен быть ограничен, и типом применяемого предела.

Входные сигналы создаются блоками From Workspace «усиление», «возрастающий предел» и «падающий предел», которые генерируют кусочно-линейные сигналы. Значения входных данных задаются с помощью шести переменных, определенных в рабочей области 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

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

Получение информации о покрытии решений из пути блока или дескриптора блока с помощью 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: ''