| name | simulink-baseline-test |
| description | Create a MATLAB baseline regression test class for a Simulink model. Use when asked to create a baseline test, golden-reference test, or regression test for a Simulink model. |
Simulink Baseline Test Creation
Creates a MATLAB test class that captures and validates Simulink model outputs against a saved baseline.
Workflow
Step 1: Analyze the Model
Resolve the model name and explore its structure to select 2–5 signals representative of the model's key behavior.
modelName = bdroot(gcs);
% List top-level subsystems
opts = Simulink.FindOptions;
opts.SearchDepth = 1;
topBlocks = getfullname(Simulink.findBlocks(modelName, opts));
for i = 1:numel(topBlocks)
bt = get_param(topBlocks{i}, 'BlockType');
fprintf(' [%s] %s\n', bt, topBlocks{i});
end
Explore subsystem ports, bus selectors, scopes, and outports to understand signal flow. Look for signals that best represent the model's overall behavior — plant outputs, actuator commands, sensor readings, or any other meaningful quantities.
Step 2: Configure Signal Logging
Enable logging on selected output ports:
ph = get_param('<block path>', 'PortHandles');
set(ph.Outport(1), 'DataLogging', 'on');
set(ph.Outport(1), 'Name', '<signalName>');
Never use To Workspace blocks for signal capture.
Step 3: Capture Baseline
Simulate and save the full logsout Dataset — not individual timeseries:
in = Simulink.SimulationInput(modelName);
out = sim(in);
baselineLogsout = out.logsout;
save(fullfile(modelDir, 'baselineData.mat'), 'baselineLogsout');
Step 4: Write the Test Class
Follow these mandatory conventions:
Inherit from sltest.TestCase
classdef MyModelBaselineTest < sltest.TestCase
Not matlab.unittest.TestCase. This gives access to verifySignalsMatch.
Single simulation, single comparison
Simulate the model once. Compare all signals in one call using verifySignalsMatch:
testCase.verifySignalsMatch(out.logsout, S.baselineLogsout, ...
'RelTol', testCase.RelTol, ...
'AbsTol', testCase.AbsTol);
Never loop through individual signals. Never simulate once per signal.
Use RelTol and AbsTol directly
Pass 'RelTol' and 'AbsTol' as name-value arguments. MATLAB applies RelTol element-wise per sample; AbsTol acts as a floor for values near zero. Never manually scale tolerances (e.g., max(abs(data)) * relTol).
Smart model teardown with bdIsLoaded
Only close the model if it was not already loaded before the test:
wasLoaded = bdIsLoaded(testCase.ModelName);
load_system(testCase.ModelName);
if ~wasLoaded
testCase.addTeardown(@()close_system(testCase.ModelName, 0));
end
Do NOT manually run PreLoadFcn
load_system automatically triggers the model's PreLoadFcn callback. Never call evalin('base', get_param(model, 'PreLoadFcn')).
Include a static generateBaseline() method
For easy re-baselining after intentional changes:
methods (Static)
function generateBaseline()
modelName = MyModelBaselineTest.ModelName;
load_system(modelName);
in = Simulink.SimulationInput(modelName);
out = sim(in);
baselineLogsout = out.logsout; %#ok<NASGU>
save(MyModelBaselineTest.BaselineFile, 'baselineLogsout');
close_system(modelName, 0);
end
end
Step 5: Run and Verify
Execute the test and confirm all signals match:
results = runtests('MyModelBaselineTest');
Complete Test Class Template
classdef MyModelBaselineTest < sltest.TestCase
properties (Constant)
ModelName = 'MyModel'
BaselineFile = fullfile(fileparts(mfilename('fullpath')), 'baselineData.mat')
RelTol = 1e-6
AbsTol = 1e-8
end
methods (TestClassSetup)
function loadModelAndBaseline(testCase)
wasLoaded = bdIsLoaded(testCase.ModelName);
load_system(testCase.ModelName);
if ~wasLoaded
testCase.addTeardown(@()close_system(testCase.ModelName, 0));
end
testCase.assertTrue(isfile(testCase.BaselineFile), ...
sprintf('Baseline not found: %s\nRun %s.generateBaseline() first.', ...
testCase.BaselineFile, mfilename('class')));
end
end
methods (Test)
function testAllSignalsMatchBaseline(testCase)
in = Simulink.SimulationInput(testCase.ModelName);
out = sim(in);
S = load(testCase.BaselineFile, 'baselineLogsout');
testCase.verifySignalsMatch(out.logsout, S.baselineLogsout, ...
'RelTol', testCase.RelTol, ...
'AbsTol', testCase.AbsTol);
end
end
methods (Static)
function generateBaseline()
modelName = MyModelBaselineTest.ModelName;
load_system(modelName);
in = Simulink.SimulationInput(modelName);
out = sim(in);
baselineLogsout = out.logsout; %#ok<NASGU>
save(MyModelBaselineTest.BaselineFile, 'baselineLogsout');
fprintf('Baseline saved to: %s\n', MyModelBaselineTest.BaselineFile);
close_system(modelName, 0);
end
end
end
Anti-Patterns — Do NOT
- Simulate once per signal (parameterized tests calling
sim each time)
- Loop through signals to verify individually — use
verifySignalsMatch
- Manually scale tolerances (
max(abs(data)) * relTol) — use 'RelTol' directly
- Save individual timeseries — save the full
logsout Dataset
- Unconditionally close the model — check
bdIsLoaded first
- Manually call
PreLoadFcn — load_system handles it
- Use
matlab.unittest.TestCase — use sltest.TestCase for verifySignalsMatch