This example uses the
slvnvdemo_powerwindow model to show how to verify a component in the
context of the model that contains that component. As you work through this example,
you use the Simulink®
Design Verifier™ component verification functions to create test cases and measure
coverage for a referenced model. In addition, you can execute the referenced model
in both simulation mode and Software-in-the-Loop (SIL) mode using the Code
Generation Verification (CGV) API.
You must have the following product licenses to run this example:
The component that you verify is a Model block named
control. This component resides inside the
power_window_control_system subsystem in the top level of the
slvnvdemo_powerwindow model. The
power_window_control_system subsystem is shown below.
Model block references the
The referenced model contains a Stateflow chart
control, which implements the logic for the
power window controller.
To verify the referenced model
create a harness model that contains the input signals that simulate
the controller in the plant model:
model and the referenced model:
in the example model.
The Model block named
power_window_control_system subsystem references
the component that you verify during this example,
Simulate the Model block that references
slvnvdemo_powerwindow_controller model and
log the input signals to the Model block:
loggedSignalsPlant = sldvlogsignals( ... 'slvnvdemo_powerwindow/power_window_control_system/control');
sldvlogsignals stores the logged signals
Generate a harness model with the logged signals:
harnessModelFilePath = sldvmakeharness( ... 'slvnvdemo_powerwindow_controller', loggedSignalsPlant);
sldvmakeharness creates and opens a harness
The Signal Builder block contains one test case containing
the logged signals.
For more information about harness models, see Simulink Design Verifier Harness Models.
For use later in this example, save the name of the harness model:
[~, harnessModel] = fileparts(harnessModelFilePath);
Leave all windows open for the next part of this example.
Next, you will record coverage for the
Model coverage is a measure of how thoroughly a test case tests
a model, and the percentage of pathways that a test case exercises.
To record coverage for the
Create a default options object, required by the
runOpts = sldvruntestopts;
Specify to simulate the model, and record coverage:
runOpts.coverageEnabled = true;
Simulate the referenced model and record coverage:
[~, covDataFromLoggedSignals] = sldvruntest( ... 'slvnvdemo_powerwindow_controller', loggedSignalsPlant, runOpts);
Display the HTML coverage report:
cvhtml('Coverage with Test Cases', covDataFromLoggedSignals);
Decision coverage: 40%
Condition coverage: 35%
MCDC coverage: 10%
For more information about decision coverage, condition coverage, and MCDC coverage, see Types of Model Coverage (Simulink Coverage).
Because you did not achieve 100% coverage for the
next, you will analyze the model to record additional coverage and
create additional test cases.
You can use Simulink
Design Verifier to analyze the
and collect coverage. You can specify that the analysis ignore any
previously satisfied objectives and record additional coverage.
To record additional coverage for the model:
Save the coverage data that you recorded for the logged signals in a file:
Create a default options object for the analysis:
opts = sldvoptions;
Specify that the analysis generate test cases to record decision, condition, and modified condition/decision coverage:
opts.ModelCoverageObjectives = 'MCDC';
Specify that the analysis ignore objectives that you satisfied when you logged the signals to the Model block:
opts.IgnoreCovSatisfied = 'on';
Specify the name of the file that contains the satisfied objectives data:
opts.CoverageDataFile = 'existingCovFromLoggedSignal.cvt';
Specify that the analysis create long test cases that satisfy several objectives:
opts.TestSuiteOptimization = 'LongTestcases';
Creating a smaller number of test cases each of which satisfies multiple test objectives saves time when you execute the generated code in the next section.
Specify to create a harness model that references the component using a Model block:
opts.saveHarnessModel = 'on'; opts.ModelReferenceHarness = 'on';
The harness model that you created from the logged signals in Prepare the Component for Verification uses
a Model block that references the
The harness model that the analysis creates must also use a Model block
You can append the test case data to the first harness model, creating
a single test suite.
Analyze the model using Simulink Design Verifier:
[status, fileNames] = sldvrun('slvnvdemo_powerwindow_controller', ... opts, true);
The analysis creates and opens a harness model
The Signal Builder block contains one long test case
that satisfies 74 test objectives.
You can combine this test case with the test case that you created
in Prepare the Component for Verification, to record additional
coverage for the
Save the name of the new harness model and open it:
[~, newHarnessModel] = fileparts(fileNames.HarnessModel); open_system(newHarnessModel);
Next, you will combine the two harness models to create a single test suite.
You created two harness models when you:
Logged the signals to the control Model block
that references the
If you combine the test cases in both harness models, you can record coverage that gets you closer to achieving 100% coverage:
Combine the harness models by appending the most recent test cases to the test cases for the logged signals:
The Signal Builder block in the
now contains both test cases.
Log the signals to the harness model:
loggedSignalsMergedHarness = sldvlogsignals(harnessModel);
Use the combined test cases to record coverage for
First, configure the options object for
runOpts = sldvruntestopts; runOpts.coverageEnabled = true;
Simulate the model and record and display the coverage data:
[~, covDataFromMergedSignals] = sldvruntest( ... 'slvnvdemo_powerwindow_controller', loggedSignalsMergedHarness, ... runOpts); cvhtml('Coverage with Merged Test Cases', covDataFromMergedSignals);
Decision coverage: 100%
Condition coverage: 80%
MCDC coverage: 60%
To verify that the generated code for the model produces the same results as simulating the model, use the Code Generation Verification (CGV) API methods.
To execute a model in different modes of execution, use the CGV API to verify the numerical equivalence of results. For more information about the CGV API, see Programmatic Code Generation Verification (Embedded Coder).
When you perform this procedure, the simulation compiles and executes the model code using both test cases.
Create a default options object for
runcgvopts = sldvruntestopts('cgv');
Specify to execute the model in simulation mode:
runcgvopts.cgvConn = 'sim';
using the two test cases and the
cgvSim = sldvruncgvtest('slvnvdemo_powerwindow_controller', ... loggedSignalsMergedHarness, runcgvopts);
These steps save the results in the workspace variable
Next, you will execute the same model with the same test cases in Software-in-the-Loop (SIL) mode and compare the results from both simulations.
For more information about Normal simulation mode, see Execute the Model (Embedded Coder).
When you execute a model in Software-in-the-Loop (SIL) mode, the simulation compiles and executes the generated code on your host computer.
In this section, you execute the
in SIL mode and compare the results to the previous section, when
you executed the model in simulation mode.
Specify to execute the model in SIL mode:
runcgvopts.cgvConn = 'sil';
using the two test cases and the
cgvSil = sldvruncgvtest('slvnvdemo_powerwindow_controller', ... loggedSignalsMergedHarness, runcgvopts);
The workspace variable
cgvSil contains the
results of the SIL mode execution.
Compare the results in
the results in
cgvSim, created from the simulation
mode execution. Use the
method to compare the results
from the two simulations:
compare (Embedded Coder)
for i=1:length(loggedSignalsMergedHarness.TestCases) simout = cgvSim.getOutputData(i); silout = cgvSil.getOutputData(i); [matchNames, ~, mismatchNames, ~ ] = ... cgv.CGV.compare(simout, silout); end
Display the results of the comparison in the MATLAB® Command Window:
fprintf(['\nTest Case(%d):%d Signals match, %d Signals mismatch\r'],... i, length(matchNames), length(mismatchNames));
As expected, the results of the two simulations match.
For more information about Software-in-the-Loop (SIL) simulations, see What Are SIL and PIL Simulations? (Embedded Coder).