Skip to content

Hybrid Systems Gallery

These examples illustrate switching, hysteresis, and resets in hybrid systems, from a bouncing ball to a controlled wind turbine.

What the Examples Illustrate

Example Behavior
Thermostat Hysteresis around a moving target
Bouncing ball Velocity resets at impact
Hybrid oscillator Side-dependent damping
Switched linear State-triggered switching of linear dynamics
Relay integrator Relay control with hysteresis
Time-varying event surface Switching at an externally driven boundary
Time-forced switch Periodic switching after a fixed dwell time
Piecewise affine Affine dynamics and a linear event surface
Impact oscillator Forced oscillation with impact resets
PID-controlled plant Actuator saturation and integral control
Tank valves Valve switching and gravity-driven drainage
Location cycle Repeated timed visits to linear locations
Buck converter Hysteretic switching and diode blocking
Wind turbine Torque regimes and pitch control
Delayed valve closure Fixed latency between detection and switching

Thermostat

A heater switches on and off around a target temperature. Heat loss to the surroundings continues in both locations. The input moves the switching thresholds; it does not directly change the heating or cooling dynamics.

For temperature \(T\), ambient temperature \(T_a\), heat-loss coefficient \(k\), and heating contribution \(P\),

\[ \dot{T} = \begin{cases} -k(T - T_a) + P, & \text{heating}, \\ -k(T - T_a), & \text{cooling}. \end{cases} \]

For target temperature \(r(t)\) and hysteresis half-width \(b\), a rising zero crossing of \(T-(r+b)\) switches to cooling; a falling zero crossing of \(T-(r-b)\) switches back to heating. Neither transition resets the temperature.

Thermostat: heating switches to cooling at the upper target-band boundary, and cooling switches back at the lower boundary.
The incoming arrow marks the initial heating location. The separate switching boundaries create hysteresis.

The illustrated run uses a varying target temperature:

Temperature, moving target, and switching thresholds, with heating and cooling intervals shaded.
Temperature remains continuous at each switch. The hysteresis band allows it to move around the target rather than track it exactly. Location colors match the diagram.

See the thermostat factory for parameter options and the simulation guide for a runnable example.

Bouncing Ball

A hybrid system can jump without changing its location. This ball has only one location, flight; impact applies a velocity reset and returns to that same location.

The state is height and vertical velocity, \([h,v]\). Between impacts,

\[ \dot{h}=v, \qquad \dot{v}=-g. \]

A falling zero crossing of \(h\) detects ground impact. The reset leaves height unchanged and maps velocity to \(v^+=-e v^-\), where \(e\) is the restitution coefficient. There is no resting location in this model.

Bouncing ball: a single flight location with a ground-impact self-loop that resets velocity.
The self-loop changes the continuous state without introducing another location.

The illustrated ball is dropped from rest and loses energy at each bounce. Height is interpreted in metres and time in seconds.

Bouncing-ball height decreases with successive bounces, while velocity jumps instantaneously at each impact.
Dashed lines join the velocities immediately before and after each impact at the same physical time. They represent resets, not continuous motion through those values.

See the bouncing_ball factory for gravity, restitution, and initial-state options.

Hybrid Oscillator

An oscillator changes its damping when position crosses the origin. The left and right locations use different damping coefficients but share the same restoring law. Neither position nor velocity is reset at a switch.

Hybrid oscillator: a rising position-zero crossing selects right-side damping, and a falling crossing selects left-side damping.
Crossing the origin changes the damping law; it is not an impact.
Oscillator position and velocity decay over time, with left and right locations distinguished by shading.
The location changes at each position-zero crossing while both state coordinates remain continuous.

See the hybrid_oscillator factory for parameters.

Switched Linear

This system selects between two linear flows, \(\dot{x}=A_qx\), where \(q\) is the active location. A downward crossing of the first coordinate through a threshold selects off; an upward crossing selects on. These are names for the two dynamics, not an external control input.

Switched linear system: on switches to off at a downward threshold crossing of the first coordinate, and off switches back at an upward crossing.
Both directions use the same threshold, rather than a hysteresis band.
Two state coordinates under switching linear dynamics, with the shared threshold marked on the first coordinate.
The threshold crossings select the active matrix. Switching changes the dynamics without resetting the state.

See the switched_linear factory for matrix and threshold options.

Relay Integrator

An integrator alternates between positive and negative constant rates. A rising crossing of the upper bound switches from up to down; a falling crossing of the lower bound switches back. The separated bounds create hysteresis.

Relay integrator: the upper bound switches increasing motion to decreasing motion, and the lower bound switches it back.
Switching reverses the direction of evolution, not the value of the integrated state.
Triangular integrated-state trace between the upper and lower switching bounds.
Constant-rate segments meet at the switching bounds without state jumps.

See the relay_integrator factory for slope and bound options.

Time-Varying Event Surface

An input signal moves the switching boundaries around the first state coordinate. The locations apply opposing drift terms and shared damping; the input changes the event surfaces, not the flow laws. The second coordinate decays independently.

Time-varying event surface: moving upper and lower boundaries switch between locations with opposing drift terms.
Crossing direction is measured relative to the moving boundary, not from the direction of state motion alone.
The first state coordinate and moving input threshold, with the upper and lower switching boundaries and active locations.
The moving band changes when switching occurs. The plotted coordinate remains continuous as the active drift changes.

See the time_varying_event_surface factory for its threshold input and parameters.

Time-Forced Switch

Each visit lasts for a fixed dwell time, measured by location residence time. A rising crossing of location_time - dwell_time alternates between fast and slow. The two continuous-state coordinates approach zero more quickly in fast than in slow; neither resets at a transition. The factory's period spans a complete fast-slow cycle.

Time-forced switch: fast and slow alternate when residence time reaches the dwell time, without resetting the continuous state.
Both transitions use the same residence-time condition. Each new visit starts at age zero while the decaying coordinates remain continuous.
Two continuously decaying state coordinates above residence time, which ramps and restarts at every fast-slow switch.
Dashed vertical segments show residence time restarting at zero, not a jump in the continuous state. Physical simulation time continues forward along the horizontal axis.

See the time_forced_switch factory for period and initial-state options.

Piecewise Affine

Each location \(q\) defines an affine flow,

\[ \dot{x}=A_qx+b_q, \]

with a matrix \(A_q\) and an offset \(b_q\). Crossing a threshold with the first coordinate selects left or right. The threshold is shared by both directions; switching does not reset the state.

Piecewise affine system: an upward threshold crossing selects the right flow, and a downward crossing selects the left flow.
Each location can supply both a linear state term and a constant offset.
Two continuous state coordinates under piecewise affine dynamics, with switching at the first coordinate's threshold.
The displayed configuration is the linear special case, with both offsets zero. The trajectories remain continuous across switches.

See the piecewise_affine factory for matrices, offsets, and threshold options.

Impact Oscillator

A damped oscillator is driven by a time-varying force and collides with a stop. Position and velocity evolve continuously between impacts. A falling position-zero crossing applies the reset \(v^+=-e v^-\), leaving position unchanged and remaining in the same oscillate location.

Impact oscillator: one forced-oscillation location with a stop-impact self-loop that reverses and scales velocity.
The input force acts between impacts; the reset acts at the stop. Neither introduces another location.
Applied force, oscillator position, and velocity, with exact-time velocity jumps at impacts.
Dashed segments mark instantaneous velocity resets. Forcing can replenish energy between impacts, so successive excursions need not shrink monotonically.

See the impact_oscillator factory for the force input and model parameters.

PID-Controlled Plant

A PID controller drives a second-order plant. Its state contains position, velocity, and the integral of tracking error. The input supplies a reference and its time derivative.

The active location determines whether actuation follows the raw PID command or is clamped at an upper or lower limit. Crossing a limit switches between linear and saturated operation without resetting the state.

PID-controlled plant: linear operation connects in both directions to upper and lower saturation, according to crossings of the raw command's limits.
Transition conditions use the unclamped command, even while the applied actuation is limited.
Plant position with its reference, velocity, and integral error, shaded by linear and saturated controller locations.
The integral continues evolving during saturation. This benchmark does not freeze the integrator or provide an anti-windup correction.

See the pid_controlled_plant factory for gains, actuation limits, and input requirements.

Tank Valves

A pump feeds the first tank while an outlet drains the second. A valve between them opens and closes according to the first tank's level. When open, it permits one-way transfer driven by the level difference.

Closed operation distinguishes a wet second tank from an empty one. When that tank drains to zero, a reset sets its level exactly to zero and the closed_dry location holds it there until the valve opens.

Tank-valve control: closed wet can open or become closed dry; either closed location opens at the upper tank-1 level, and open closes at the lower level.
Either closed location can open the valve. Opening permits transfer but does not guarantee that tank 2 fills faster than it drains.
Tank levels in metres over time, with tank-1 switching levels and wet, dry, and open intervals.
In this run, tank 2 empties before every valve opening. Its zero-level plateaus belong to the closed-dry location.

See the tank_valves factory for tank geometry, flow parameters, and switching levels.

Location Cycle

Locations form a cyclic sequence, each applying a different linear flow to the continuous state. When location residence time reaches the dwell time, the system enters the next location at age zero without resetting the state. The factory can vary both the number of locations and the state dimension; the illustrated dimension=3 run has three continuous-state coordinates and no clock coordinate.

Location cycle: m0 through m5 form a closed loop, with a residence-time event on every edge and no continuous-state resets.
The final location returns to the first. All continuous-state coordinates are carried through every transition unchanged.
Three continuous-state coordinates and location residence time, with the repeating location sequence shown by shading.
Separate scales reveal the smaller coordinate excursions. Residence time restarts at each location change, independently of the continuous-state trajectories.

See the location_cycle factory for location count, state dimension, and dwell-time options.

Buck Converter

A buck converter alternates between connecting the supply and letting inductor current freewheel through a diode. Voltage hysteresis determines when the switch opens and closes; there is no fixed-frequency clock.

When the freewheeling current reaches zero, the diode blocks reverse current. The capacitor then supplies the load until output voltage falls to the lower switching threshold.

Buck converter: voltage thresholds switch between on and off, while current reaching zero enters diode blocking before the next on interval.
The off location can return directly to on or pass through zero-current operation first.
Inductor current in amperes and output voltage in volts, showing switching thresholds and zero-current intervals.
Here, each cycle includes a zero-current interval. Voltage can continue rising after switch-off as stored inductor energy feeds the output: the thresholds are switching commands, not hard voltage bounds.

See the buck_converter factory for circuit parameters, conduction laws, and threshold options.

Wind Turbine

This already-running turbine couples rotor motion, tower motion, and blade-pitch control. Its controller switches between generator torque laws without resetting the continuous state.

The state captures rotor speed, tower displacement and velocity, blade pitch and pitch rate, and the pitch controller's integral contribution. The input is wind speed. Generator speed determines the active torque regime; pitch control operates across all regimes.

Wind-turbine controller: a bidirectional chain from no generation through gradual, below-rated, and approaching-rated generation to rated power.
Rising generator speed moves the controller toward rated power; falling speed moves it back toward no generation. Separate thresholds in each direction provide hysteresis.

In the illustrated run, wind speed rises and then falls. The plots show how the rotor, pitch controller, and tower respond:

Wind speed, rotor speed, blade pitch, tower displacement, and generator mechanical power during a wind cycle, with controller locations distinguished by shading.
The dashed line marks rated generator-shaft power. This is mechanical power, not electrical output, and the reference is not a hard instantaneous cap in other modes. Location colors match the diagram.

The model assumes quasi-steady, head-on aerodynamics and a running rotor. It does not model startup, shutdown, or emergency braking. Aerodynamic-domain violations stop simulation rather than extrapolating the fitted coefficients. To compute generator-shaft power, pass rotor angular speeds in rad/s, matching location labels, and the turbine's parameters to wind_turbine_power(rotor_speeds, location_labels, parameters=system.parameters). The location selects the torque law even when hysteresis makes speed ambiguous. See the wind-turbine reference for equations, controller parameters, and operating limits.

Run the standalone example to print location changes and save a plot:

uv run --directory ./examples/hybrid_systems python wind_turbine.py

Its output is examples/hybrid_systems/outputs/wind_turbine.png.

Delayed Valve Closure

The valve_closure benchmark fills a tank at a constant rate. When the water reaches the closing threshold, the inlet valve closes after the configured delay. Filling continues during the delay, so the final water height exceeds the threshold.

The trajectory records threshold detection in event.detection_time and valve closure in event.time. The delayed-closure scenario appears at the end of the gallery.

Run every configured example and save a combined plot to examples/hybrid_systems/outputs/benchmarks.png:

uv run --directory ./examples/hybrid_systems python run.py

The model configurations and input signals are in scenarios.py.

To work with an installed Flowcean package rather than the repository scripts, start with the simulation example. The identification walkthrough shows how to learn a hybrid model from simulated traces.

Export Automaton Diagrams

To inspect the implemented models, export every example's declared automaton without simulating it:

uv run --directory ./examples/hybrid_systems python export_graphs.py

This writes one DOT file per example under examples/hybrid_systems/outputs/automata/. Add --svg to render SVG files; this requires Graphviz's dot executable on PATH.

For programmatic export and label options, see build_hybrid_system_dot and render_dot_svg.