We create a composite system that consists of a plant, two controllers, and a switch that toggles between the controllers based on some criteria.

A = [0, 1; 0, 0];
B = [0; 1];
K0 = [-1, -1];
K1 = [ 2, -1];
input_dim = 1;
plant = hybrid.subsystems.LinearContinuousSubsystem(A, B);
controller_0 = hybrid.subsystems.MemorylessSubsystem(2, 1, @(~, z_plant) K0*z_plant);
controller_1 = hybrid.subsystems.MemorylessSubsystem(2, 1, @(~, z_plant) K1*z_plant);
switcher = hybrid.subsystems.SwitchSubsystem(input_dim);
sys = CompositeHybridSystem('plant', plant, ...
                             'kappa0', controller_0, ...
                             'kappa1', controller_1, ...
                             'switcher', switcher)
sys = 
CompositeHybridSystem:
├ Subsystem 1: 'plant' (hybrid.subsystems.LinearContinuousSubsystem)
│ 		  Flow input: @(~,~,~,~,~)zeros(1,1)
│ 		  Jump input: @(~,~,~,~,~)zeros(1,1)
│ 		      Output: y1=@(x)C*x
│ 		 Dimensions: State=2, Input=1, Output=2
├ Subsystem 2: 'kappa0' (hybrid.subsystems.MemorylessSubsystem)
│ 		  Flow input: @(~,~,~,~,~)zeros(2,1)
│ 		  Jump input: @(~,~,~,~,~)zeros(2,1)
│ 		      Output: y2=@(~,z_plant)K0*z_plant
│ 		 Dimensions: State=0, Input=2, Output=1
├ Subsystem 3: 'kappa1' (hybrid.subsystems.MemorylessSubsystem)
│ 		  Flow input: @(~,~,~,~,~)zeros(2,1)
│ 		  Jump input: @(~,~,~,~,~)zeros(2,1)
│ 		      Output: y3=@(~,z_plant)K1*z_plant
│ 		 Dimensions: State=0, Input=2, Output=1
└ Subsystem 4: 'switcher' (hybrid.subsystems.SwitchSubsystem)
  		  Flow input: @(~,~,~,~,~)zeros(4,1)
  		  Jump input: @(~,~,~,~,~)zeros(4,1)
  		      Output: y4=@(q,u)output_switch(q,u)
  		 Dimensions: State=1, Input=4, Output=1

The full state vector is passed as input to the controllers. We can ommit the '~'s from the argument list since we only use the first argument is used.

sys.setInput(controller_0, @(z_plant, ~, ~, ~) z_plant);  % '~'s included
sys.setInput(controller_1, @(z_plant) z_plant); % '~'s omitted

The current choice of controller is stored as state variable q in switcher , where controller_0 is passed through as the output of switcher whenever q = 0 and controller_1 is passed through when q = 1 . The plant state z_plant and output of the controllers, named u0 and u1 , are passed to the switcher. The SwitchSubsystem class provides a wrapInput method that handles the creation of the input vector from the given values. The third argument to wrapInput is the criteria for switching to to q = 0 and the fourth argument is the criteria for switching to q = 1 . If # q=0 and the third argument of wrapInput is zero, # q=1 and fourth argument of wrapInput is zero, or # the third and fourth arguments of wrapInput are zero, then q is held constant.

sys.setInput(switcher, @(z_plant, u0, u1) ...
             switcher.wrapInput(u0, u1, norm(z_plant) >= 3, norm(z_plant) <= 1));

The output of the switch is passed to the plant.

sys.setInput(plant, @(~, ~, ~, u_switched) u_switched);

Compute a solution. Note that the MemorylessSubsystems have no state, so empty arrays are given in x0 for the corresponding subsystems.

x0 = {[10; 0], [], [], 1};
config = HybridSolverConfig('Refine', 8); % 'Refine' option makes the plots smoother.
sol = sys.solve(x0, [0, 100], [0, 100], config)
sol = 
  CompositeHybridSolution with properties:

            subsys_count: 4
                      x0: [7×1 double]
                      xf: [7×1 double]
       termination_cause: T_REACHED_END_OF_TSPAN
                       t: [2007×1 double]
                       j: [2007×1 double]
                       x: [2007×7 double]
            flow_lengths: [39×1 double]
              jump_times: [38×1 double]
    shortest_flow_length: 0
       total_flow_length: 100
              jump_count: 38

Plot the solution, using different colors when \(q=0\) and \(q=1\) .

clf
hold on
q = sol('switcher').x;
hpb = HybridPlotBuilder().jumpMarker('none');

% Plot solution where q=0
hpb.filter(q == 0)...
    .legend('$q = 0$')...
    .plotPhase(sol('plant'));

% Plot solution where q=1
hpb.filter(q == 1)...
    .legend('$q = 1$')...
    .flowColor('green')...
    .plotPhase(sol('plant'));

% Configure plot appearance
axis equal
axis padded
set(gca(), 'XAxisLocation', 'origin');
set(gca(), 'YAxisLocation', 'origin');

Updated: