Zero-Crossing Detection with Fixed-Step Simulation
Models with both continuous states and discontinuous signals may require a small fixed-step size to obtain accurate simulation results near discontinuities. With fixed-step zero crossing enabled, Simulink® can automatically detect and locate discontinuities and correct the continuous states in the model. This functionality allows you to use a larger step size and enables faster simulation times without affecting simulation accuracy.
You may find fixed-step zero-crossing detection useful if your model contains:
Continuous states
Blocks with zero-crossings driven by signals with continuous sample time
Frequent switching or other events that limit solver step-size
Effects of Zero-Crossing Detection in Fixed-Step
Consider a self-resetting integrator that can be used to generate a sawtooth wave where the state is reset to 1/3 each time it reaches a value of 1. Simulating in variable-step with zero-crossing detection shows the expected results, or baseline, for this model.
model = 'mSelfResetIntegrator'; open_system(model); set_param(model, 'Solver', 'ode23'); simoutVS = sim(model); figure(); plot(simoutVS.tout, simoutVS.xout); legend('Variable-Step (baseline)',... 'Location', 'southeast');
The sawtooth wave generated using variable-step simulation is used as a baseline.
Simulate in Fixed-Step Without Zero-Crossing Detection
You can use a fixed-step solver like ode3
to simulate this model
with default fixed-step size equal to 0.2. However, the simulation results are not very
accurate for this step size. The fixed-step size must be decreased to about 0.001 for
the simulation results that align with the expected result.
set_param(model, 'Solver', 'ode3', ... 'FixedStep', '0.2'); simoutFS = sim(model); plot(simoutVS.tout, simoutVS.xout, ... simoutFS.tout, simoutFS.xout, '-x'); title('Fixed-step size = 0.2'); legend('Variable-Step (baseline)', 'Fixed-step (Zero-Crossing Disabled)',... 'Location', 'southeast');
set_param(model, 'FixedStep', '.001'); simoutFS2 = sim(model); plot(simoutVS.tout, simoutVS.xout, ... simoutFS2.tout, simoutFS2.xout, '-x'); title('Fixed-step size = 0.001'); legend('Variable-Step (baseline)', 'Fixed-step (Zero-Crossing Disabled)',... 'Location', 'southeast');
Enable Fixed-Step Zero-Crossing Detection
Zero-crossing detection can be enabled for this model by selecting Enable zero-crossing detection for fixed-step simulation. You can also set the step size back to 0.2 and simulate. Note that despite this substantial increase in step size, each state value in this simulation coincides with the expected result. Thus, zero-crossing detection for fixed-step simulation results in faster simulation times for this model.
set_param(model, 'FixedStep', '0.2', ... 'EnableFixedStepZeroCrossing', 'on'); simoutFSZC = sim(model); plot(simoutVS.tout, simoutVS.xout, ... simoutFSZC.tout, simoutFSZC.xout, '-x'); title('Fixed-step size = 0.2'); legend('Variable-Step (baseline)', 'Fixed-step (Zero-Crossing Enabled)',... 'Location', 'southeast');
Set Parameters for Zero-Crossing Detection
You use two main parameters to control zero crossing for fixed-step simulation. These parameters help ensure that the detection and location of zero-crossing events is fixed-cost. Go to the Solver Details > Zero-crossing options section of the configuration parameters to access the parameters.
Maximum Number of Bracketing Iterations
The Maximum number of bracketing iterations parameter limits the number of search iterations used by Simulink for locating a zero-crossing event once the event has been detected. In general, a higher number of bracketing iterations will provide a more accurate event location, but this option is computationally costly.
Consider this model with a sine wave driving a Hit Crossing block. Zero-crossings are detected when the Hit Crossing block detects that its input signal has crossed zero, which should occur at multiples of pi. The scope displays this result.
model = 'mFixedStepZcParameters'; open_system(model); set_param(model, 'Solver', 'VariableStepAuto'); sim(model);
Too few bracketing iterations results in locating zero crossings with less accuracy. To see the number of bracketing iterations simulation results, enable fixed-step zero-crossing, change to a fixed-step solver, and set the Maximum number of zero-crossings per step parameter to 2. Use a fixed-step size of 0.5.
set_param(model, 'EnableFixedStepZeroCrossing', 'on',... 'MaxZcBracketingIterations', '2',... 'SolverName', 'ode3',... 'FixedStep', '0.5');
Increasing the number of bracketing iterations to 4 results in more accurate location of the events in this model. The zero crossing is located closer to the expected value of pi.
set_param(model, 'MaxZcBracketingIterations', '4');
Maximum Number of Zero-Crossings per Step
Use Maximum number of
zero-crossings per step parameter to limit the maximum number of zero
crossings that Simulink will locate in one simulation time step. Once this maximum number is reached
in a step, any additional zero-crossings that occur within that step are ignored. To see how
this can affect simulation results, consider the following example. Set the Sine
Wave block to output two sine waves that are slightly offset by using scalar
expansion on the 'Bias'
parameter of the sine wave block. Two zero
crossing events should be located near pi.
sineWaveBlock = [model '/Sine Wave']; set_param(sineWaveBlock, 'Bias', '[0.0 0.1]'); set_param(model, 'Solver', 'ode45'); simoutVS = sim(model);
Setting the maximum number of zero-crossings to locate per step to 1 will restrict Simulink to only locating the first zero crossing that occurs within a single time step. In this example, Simulink only locates the first zero-crossing in the step at pi in the step from t = 3 to t = 3.5. As a result, the second state of the Integrator block is less accurate due to the missed zero crossing.
set_param(model, 'Solver', 'ode3',... 'EnableFixedStepZeroCrossing', 'on',... 'MaxZcPerStep', '1'); simoutFS_1ZC = sim(model); f = figure(); tiledlayout(f,'flow','TileSpacing','compact','Padding','compact'); nexttile; plot(simoutVS.tout, simoutVS.xout.signals(1).values(:, 1),... simoutFS_1ZC.tout,simoutFS_1ZC.xout.signals(1).values(:,1), '-x'); title('State 1') nexttile; plot(simoutVS.tout, simoutVS.xout.signals(1).values(:,2),... simoutFS_1ZC.tout,simoutFS_1ZC.xout.signals(1).values(:,2), '-x'); title('State 2') legend('Variable-Step (Expected Result)', 'Fixed-Step with One Zc Per Step',... 'Location', 'northwest');
Since you know to expect a maximum of two zero crossings to be located within the fixed-step size of 0.5, setting the Maximum number of zero-crossings per step parameter to 2 should yield more accurate simulation results. This plot shows that both continuous states of the Integrator block match the expected result.
set_param(model, 'MaxZcPerStep', '2') simoutFS_2ZC = sim(model); f = figure(); tiledlayout(f,'flow','TileSpacing','compact','Padding','compact'); nexttile; plot(simoutVS.tout, simoutVS.xout.signals(1).values(:, 1),... simoutFS_2ZC.tout,simoutFS_2ZC.xout.signals(1).values(:,1), '-x'); title('State 1') nexttile; plot(simoutVS.tout, simoutVS.xout.signals(1).values(:,2),... simoutFS_2ZC.tout,simoutFS_2ZC.xout.signals(1).values(:,2), '-x'); title('State 2') legend('Variable-Step (Expected Result)', 'Fixed-Step with Two Zc Per Step',... 'Location', 'northwest');
See Also
Maximum number of bracketing iterations | Enable zero-crossing detection for fixed-step simulation | Maximum number of zero-crossings per step | Zero-Crossing Detection | Zero-Crossing Algorithms