Этот пример создает три теста для ограничителя регулируемой процентной ставки и анализирует получившееся покрытие модели с помощью API командной строки Инструмента model coverage.
Ограничитель Регулируемой процентной ставки подсистемы 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: (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 из блока 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: ''