Skip to content

relay_integrator

Relay-controlled integrator benchmark.

relay_integrator(rate=1.0, lower=-1.0, upper=1.0, initial_state=None)

Create a relay integrator with hysteresis.

Parameters:

Name Type Description Default
rate float

Magnitude of the integrator rate.

1.0
lower float

Lower switching threshold.

-1.0
upper float

Upper switching threshold.

1.0
initial_state ndarray | None

Optional initial scalar state.

None

Returns:

Type Description
HybridSystem

HybridSystem configured with relay dynamics.

Source code in src/flowcean/hybrid/benchmarks/relay_integrator.py
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
def relay_integrator(
    rate: float = 1.0,
    lower: float = -1.0,
    upper: float = 1.0,
    initial_state: np.ndarray | None = None,
) -> HybridSystem:
    """Create a relay integrator with hysteresis.

    Args:
        rate: Magnitude of the integrator rate.
        lower: Lower switching threshold.
        upper: Upper switching threshold.
        initial_state: Optional initial scalar state.

    Returns:
        HybridSystem configured with relay dynamics.
    """

    def flow_up(
        _t: float,
        _state: np.ndarray,
        params: Parameters,
        _input_stream: InputStream,
    ) -> np.ndarray:
        return np.array([params["rate"]], dtype=float)

    def flow_down(
        _t: float,
        _state: np.ndarray,
        params: Parameters,
        _input_stream: InputStream,
    ) -> np.ndarray:
        return np.array([-params["rate"]], dtype=float)

    def event_surface_upper(
        _t: float,
        state: np.ndarray,
        params: Parameters,
        _input_stream: InputStream,
    ) -> float:
        return state[0] - params["upper"]

    def event_surface_lower(
        _t: float,
        state: np.ndarray,
        params: Parameters,
        _input_stream: InputStream,
    ) -> float:
        return state[0] - params["lower"]

    up_dynamics = ContinuousDynamics(flow_up, label="up")
    down_dynamics = ContinuousDynamics(flow_down, label="down")
    up = Location(up_dynamics, label="up")
    down = Location(down_dynamics, label="down")

    to_down = Transition(
        source=up,
        target=down,
        event=EventSurface(
            event_surface_upper,
            direction=CrossingDirection.RISING,
            label="hit_upper",
        ),
    )
    to_up = Transition(
        source=down,
        target=up,
        event=EventSurface(
            event_surface_lower,
            direction=CrossingDirection.FALLING,
            label="hit_lower",
        ),
    )

    if initial_state is None:
        initial_state = np.array([0.0], dtype=float)

    return HybridSystem(
        locations=[up, down],
        transitions=[to_down, to_up],
        initial_location=up,
        initial_state=initial_state,
        parameters={"rate": rate, "lower": lower, "upper": upper},
    )