В этом примере создаются три тестовых случая для регулируемого ограничителя скорости и анализируется результирующий охват модели с помощью API командной строки инструмента «Покрытие модели».
Регулируемый ограничитель скорости подсистемы 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: ''