Example #1
0
def test_gain_class():
    system = System()
    gain_block = Gain(system, k=[[1, 2], [3, 4]])
    gain_in = constant(value=[3, 4])
    gain_block.input.connect(gain_in)

    npt.assert_almost_equal(gain_block.output(None), [11, 25])
Example #2
0
def test_rigidbody_defaults():
    mass = 1.5
    moment_of_inertia = np.diag([13.2e-3, 12.8e-3, 24.6e-3])

    system = System()
    rb_6dof = RigidBody6DOFFlatEarth(owner=system,
                                     mass=mass,
                                     moment_of_inertia=moment_of_inertia)
    dcm_to_euler = DirectCosineToEuler(system)
    thrust = constant(value=np.r_[0, 0, 0])
    moment = constant(value=moment_of_inertia @ np.r_[0, 0, math.pi / 30**2])

    thrust.connect(rb_6dof.forces_body)
    moment.connect(rb_6dof.moments_body)

    rb_6dof.dcm.connect(dcm_to_euler.dcm)

    rtol = 1e-12
    atol = 1e-12
    sim = Simulator(system, start_time=0, rtol=rtol, atol=atol)
    *_, last_item = sim.run_until(time_boundary=30.0, include_last=True)

    npt.assert_allclose(dcm_to_euler.yaw(last_item),
                        math.pi / 2,
                        rtol=rtol,
                        atol=atol)
    npt.assert_allclose(dcm_to_euler.pitch(last_item), 0, rtol=rtol, atol=atol)
    npt.assert_allclose(dcm_to_euler.roll(last_item), 0, rtol=rtol, atol=atol)
    npt.assert_allclose(rb_6dof.position_earth(last_item), [0, 0, 0],
                        rtol=rtol,
                        atol=atol)
Example #3
0
def damped_oscillator_with_events(
    mass=100.0,
    damping_coefficient=50.0,
    spring_coefficient=1.0,
    initial_value=10.0,
):
    system = System()
    lti = LTISystem(
        parent=system,
        system_matrix=[
            [0, 1],
            [-spring_coefficient / mass, -damping_coefficient / mass],
        ],
        input_matrix=[[-1 / mass], [0]],
        output_matrix=[[1, 0]],
        feed_through_matrix=np.zeros((1, 1)),
        initial_condition=[initial_value, 0],
    )
    ZeroCrossEventSource(owner=system,
                         event_function=(lambda data: lti.state(data)[1]))
    time_constant = 2 * mass / damping_coefficient

    src = InputSignal(system, shape=1)
    lti.input.connect(src)

    return system, lti, 3 * time_constant, [lti.output]
Example #4
0
def test_multiple_event_sources_error():
    """
    Test the detection of multiple conflicting event sources on connection.
    """
    system = System()

    clock_a = Clock(system, period=1.0)
    clock_b = Clock(system, period=1.0)

    port_a = EventPort(system)
    port_b = EventPort(system)
    port_c = EventPort(system)
    port_d = EventPort(system)

    port_a.connect(clock_a)
    port_d.connect(clock_b)

    port_b.connect(port_a)
    port_c.connect(port_d)

    assert port_b.source is clock_a
    assert port_c.source is clock_b

    with pytest.raises(MultipleEventSourcesError):
        port_c.connect(port_b)
Example #5
0
def pendulum(length=1):
    """Create a steady-state model for a pendulum"""

    system = System()

    g = 9.81  # Gravity

    def omega_dt(data):
        """Calculate the acceleration of the pendulum"""

        return np.sin(phi(data)) * g / length

    def phi_dt(data):
        """Calculate the velocity of the pendulum"""

        return omega(data)

    omega = State(system, derivative_function=omega_dt)
    phi = State(system, derivative_function=phi_dt)

    # Set up a steady-state configuration
    config = SteadyStateConfiguration(system)
    # Minimize the total energy
    config.objective = lambda data: (g * length * (1 - np.cos(phi(data))) +
                                     (length * omega(data))**2)
    # Constrain the angular velocity (no steady state)
    config.states[omega].steady_state = False
    # Constrain the angle
    config.states[phi].steady_state = False
    config.states[phi].lower_bounds = -np.pi
    config.states[phi].upper_bounds = np.pi

    return config
Example #6
0
def test_event_connection():
    """
    Test connecting event ports to events.
    """

    system = System()

    clock_a = Clock(system, period=1.0)

    port_a = EventPort(system)
    port_b = EventPort(system)
    port_c = EventPort(system)
    port_d = EventPort(system)

    port_b.connect(clock_a)
    port_d.connect(clock_a)

    port_a.connect(port_b)
    port_c.connect(port_d)
    port_c.connect(port_b)

    assert port_a.source == clock_a
    assert port_b.source == clock_a
    assert port_c.source == clock_a
    assert port_d.source == clock_a
Example #7
0
def test_deprecated_options():
    """Test if deprecated options lead to warnings"""

    system = System()
    with pytest.warns(DeprecationWarning):
        Simulator(system, start_time=0, event_xtol=1e-12)
    with pytest.warns(DeprecationWarning):
        Simulator(system, start_time=0, event_maxiter=1000)
Example #8
0
def test_port_not_connected_error():
    """Test the detection of unconnected ports"""

    system = System()
    port = Port()

    system_state = SystemState(time=0, system=system)
    with pytest.raises(PortNotConnectedError):
        port(system_state)
Example #9
0
def test_clock_handling():
    """Test the handling of clocks in the simulator."""

    time_constant = 1.0
    initial_value = 2.0
    system = System()

    input_signal = constant(value=0.0)
    lag = LTISystem(
        parent=system,
        system_matrix=-1 / time_constant,
        input_matrix=1,
        output_matrix=1,
        feed_through_matrix=0,
        initial_condition=[initial_value],
    )
    lag.input.connect(input_signal)

    clock1 = Clock(system, period=0.2)
    hold1 = zero_order_hold(
        system,
        input_port=lag.output,
        event_port=clock1,
        initial_condition=initial_value,
    )

    clock2 = Clock(system, period=0.25, end_time=2.0)
    hold2 = zero_order_hold(
        system,
        input_port=lag.output,
        event_port=clock2,
        initial_condition=initial_value,
    )

    # Clock 3 will not fire within the simulation time frame
    clock3 = Clock(system, period=0.25, start_time=-6.0, end_time=-1.0)
    hold3 = zero_order_hold(
        system,
        input_port=lag.output,
        event_port=clock3,
        initial_condition=initial_value,
    )

    simulator = Simulator(system, start_time=0.0)
    result = SimulationResult(system, simulator.run_until(time_boundary=5.0))

    time_floor1 = np.floor(result.time / clock1.period) * clock1.period
    time_floor2 = np.minimum(
        clock2.end_time,
        (np.floor(result.time / clock2.period) * clock2.period))
    reference1 = initial_value * np.exp(-time_floor1 / time_constant)
    reference2 = initial_value * np.exp(-time_floor2 / time_constant)

    npt.assert_almost_equal(hold1(result), reference1)
    npt.assert_almost_equal(hold2(result), reference2)
    npt.assert_almost_equal(hold3(result), initial_value)
Example #10
0
def test_without_goal():
    """Test the steady-state finding algorithm without objective function
    and with no steady states"""

    system = System()

    config = SteadyStateConfiguration(system)

    with pytest.raises(ValueError):
        find_steady_state(config)
Example #11
0
def test_invalid_objective():
    """Test the steady-state finding algorithm with an invalid objective"""

    system = System()

    config = SteadyStateConfiguration(system)
    config.objective = True

    with pytest.raises(ValueError):
        find_steady_state(config)
Example #12
0
def test_sum_signal(channel_weights, output_size, inputs, expected_output):
    system = System()
    input_signals = [
        InputSignal(system, shape=output_size, value=input_value)
        for input_value in inputs
    ]
    sum_result = sum_signal(input_signals, gains=channel_weights)

    system_state = SystemState(time=0, system=system)
    actual_output = sum_result(system_state)
    npt.assert_almost_equal(actual_output, expected_output)
Example #13
0
def test_integrator():
    """Test an integrator"""

    system = System()
    int_input = constant(1.0)
    int_output = integrator(system, int_input)

    simulator = Simulator(system, start_time=0.0)
    result = SimulationResult(system, simulator.run_until(time_boundary=10.0))

    npt.assert_almost_equal(int_output(result).ravel(), result.time)
Example #14
0
def test_tick_generator_stop_iteration():
    """Test whether the clock tick generator throws a ``StopIteration``
    exception when the current time is after the end time."""

    system = System()

    clock = Clock(system, period=1.0, start_time=0.0, end_time=2.0)

    tick_generator = clock.tick_generator(not_before=3.0)

    with pytest.raises(StopIteration):
        next(tick_generator)
Example #15
0
def first_order_lag_no_input(time_constant=1, initial_value=10):
    system = System()
    lti = LTISystem(
        parent=system,
        system_matrix=-1 / time_constant,
        input_matrix=np.empty(shape=(1, 0)),
        output_matrix=1,
        feed_through_matrix=np.empty(shape=(0, )),
        initial_condition=[initial_value],
    )

    return system, lti, 3 * time_constant, [lti.output]
Example #16
0
def test_aerodyn_blocks(thrust_coefficient, power_coefficient):
    system = System()
    propeller = Propeller(
        system,
        thrust_coefficient=thrust_coefficient,
        power_coefficient=power_coefficient,
        diameter=8 * 25.4e-3,
    )
    dcmotor = DCMotor(
        system,
        motor_constant=789.0e-6,
        resistance=43.3e-3,
        inductance=1.9e-3,
        moment_of_inertia=5.284e-6,
        initial_omega=1,
    )
    thruster = Thruster(system,
                        vector=np.c_[0, 0, -1],
                        arm=np.c_[1, 1, 0],
                        direction=1)
    density = constant(value=1.29)
    gravity = constant(value=[0, 0, 1.5 / 4 * 9.81])
    voltage = InputSignal(system)

    voltage.connect(dcmotor.voltage)
    density.connect(propeller.density)
    dcmotor.speed_rps.connect(propeller.speed_rps)
    propeller.torque.connect(dcmotor.external_torque)
    propeller.thrust.connect(thruster.scalar_thrust)
    dcmotor.torque.connect(thruster.scalar_torque)

    force_sum = sum_signal((thruster.thrust_vector, gravity))

    # Determine the steady state
    steady_state_config = SteadyStateConfiguration(system)
    # Enforce the sum of forces to be zero along the z-axis
    steady_state_config.ports[force_sum].lower_bounds[2] = 0
    steady_state_config.ports[force_sum].upper_bounds[2] = 0
    # Ensure that the input voltage is non-negative
    steady_state_config.inputs[voltage].lower_bounds = 0
    sol = find_steady_state(steady_state_config)
    assert sol.success

    npt.assert_almost_equal(sol.state, [856.5771575, 67.0169392])
    npt.assert_almost_equal(sol.inputs, [3.5776728])

    npt.assert_almost_equal(propeller.power(sol.system_state), 45.2926865)
    npt.assert_almost_equal(
        np.ravel(thruster.torque_vector(sol.system_state)),
        [-3.67875, 3.67875, -0.0528764],
    )
Example #17
0
def test_empty_system():
    """Test whether the linearization algorithm properly flags a system without
    states and inputs"""

    # Create a system and add a signal to it, so we can check whether the
    # algorithm is actually checking states and inputs instead of signals or
    # outputs
    system = System()
    output_signal = Signal()
    config = LinearizationConfiguration(system)
    OutputDescriptor(config, output_signal)

    with pytest.raises(ValueError):
        system_jacobian(config, single_matrix=False)
Example #18
0
def test_sum_block(channel_weights, output_size, inputs, expected_output):
    system = System()
    sum_block = Sum(system,
                    channel_weights=channel_weights,
                    output_size=output_size)
    for idx in range(len(inputs)):
        input_signal = InputSignal(system,
                                   shape=output_size,
                                   value=inputs[idx])
        sum_block.inputs[idx].connect(input_signal)

    system_state = SystemState(time=0, system=system)
    actual_output = sum_block.output(system_state)
    npt.assert_almost_equal(actual_output, expected_output)
Example #19
0
def lti_gain(gain):
    system = System()
    lti = LTISystem(
        parent=system,
        system_matrix=np.empty((0, 0)),
        input_matrix=np.empty((0, 1)),
        output_matrix=np.empty((1, 0)),
        feed_through_matrix=gain,
    )

    src = InputSignal(system)

    lti.input.connect(src)

    return system, lti, 10.0, [lti.output]
Example #20
0
def first_order_lag(time_constant=1, initial_value=10):
    system = System()
    lti = LTISystem(
        parent=system,
        system_matrix=-1 / time_constant,
        input_matrix=1,
        output_matrix=[1],
        feed_through_matrix=0,
        initial_condition=[initial_value],
    )

    src = InputSignal(system)

    lti.input.connect(src)

    return system, lti, 3 * time_constant, [lti.output]
Example #21
0
def test_saturation():
    system = System()
    Clock(system, period=0.01)

    @signal_function
    def _sine_source(system_state):
        return np.sin(2 * np.pi * system_state.time)

    saturated_out = saturation(_sine_source, lower_limit=-0.5, upper_limit=0.6)

    simulator = Simulator(system, start_time=0.0)
    result = SimulationResult(system, simulator.run_until(time_boundary=1.0))

    sine_data = _sine_source(result)
    saturated_data = saturated_out(result)
    saturated_exp = np.minimum(np.maximum(sine_data, -0.5), 0.6)
    npt.assert_almost_equal(saturated_data, saturated_exp)
Example #22
0
def test_tick_generator(start_time, end_time, run_before_start, expected):
    """Test the tick generator of a clock event"""

    system = System()

    clock = Clock(system,
                  period=1.0,
                  start_time=start_time,
                  end_time=end_time,
                  run_before_start=run_before_start)

    tick_generator = clock.tick_generator(not_before=0.0)

    # Fetch at most 4 ticks
    ticks = [tick for _idx, tick in zip(range(4), tick_generator)]

    npt.assert_almost_equal(ticks, expected)
Example #23
0
def test_state_access():
    """Test whether calling a ``State`` object calls the ``get_state_value`` and
    ``set_state_value`` methods of the provider object"""

    system = System()
    state = State(system)

    provider = Mock()

    # Check read access
    state(provider)
    provider.get_state_value.assert_called_with(state)

    # Check write access
    provider.reset_mock()
    state.set_value(provider, 10)
    provider.set_state_value.assert_called_with(state, 10)
Example #24
0
def test_rigidbody_movement():
    mass = 1.5
    omega = 2 * math.pi / 120
    r = 10.0
    vx = r * omega
    moment_of_inertia = np.diag([13.2e-3, 12.8e-3, 24.6e-3])

    system = System()
    rb_6dof = RigidBody6DOFFlatEarth(
        owner=system,
        mass=mass,
        initial_velocity_earth=[vx, 0, 0],
        initial_angular_rates_earth=[0, 0, omega],
        initial_position_earth=[0, 0, 0],
        initial_transformation=np.eye(3, 3),
        moment_of_inertia=moment_of_inertia,
    )
    dcm_to_euler = DirectCosineToEuler(system)
    thrust = constant(value=np.r_[0, mass * omega * vx, 0])
    moment = constant(value=np.r_[0, 0, 0])

    thrust.connect(rb_6dof.forces_body)
    moment.connect(rb_6dof.moments_body)

    rb_6dof.dcm.connect(dcm_to_euler.dcm)

    rtol = 1e-12
    atol = 1e-12
    sim = Simulator(system, start_time=0, rtol=rtol, atol=atol)
    *_, last_item = sim.run_until(time_boundary=30.0, include_last=True)

    npt.assert_allclose(dcm_to_euler.yaw(last_item),
                        math.pi / 2,
                        rtol=rtol,
                        atol=atol)
    npt.assert_allclose(dcm_to_euler.pitch(last_item), 0, rtol=rtol, atol=atol)
    npt.assert_allclose(dcm_to_euler.roll(last_item), 0, rtol=rtol, atol=atol)
    npt.assert_allclose(rb_6dof.position_earth(last_item), [r, r, 0],
                        rtol=rtol,
                        atol=atol)
    npt.assert_allclose(rb_6dof.velocity_body(last_item), [vx, 0, 0],
                        rtol=rtol,
                        atol=atol)
    npt.assert_allclose(rb_6dof.omega_body(last_item), [0, 0, omega],
                        rtol=rtol,
                        atol=atol)
Example #25
0
def test_invalid_lti_configurations(input_shape, system_shape, output_shape,
                                    feed_through_shape):
    """Test the detection of invalid LTI matrix configurations"""
    input_matrix = _make_array_or_scalar(shape=input_shape)
    system_matrix = _make_array_or_scalar(shape=system_shape)
    output_matrix = _make_array_or_scalar(shape=output_shape)
    feed_through_matrix = _make_array_or_scalar(shape=feed_through_shape)

    system = System()
    with pytest.raises(InvalidLTIException):
        LTISystem(
            parent=system,
            input_matrix=input_matrix,
            system_matrix=system_matrix,
            output_matrix=output_matrix,
            feed_through_matrix=feed_through_matrix,
        )
Example #26
0
def test_event_port_call():
    """Test the call method on EventPort objects"""

    mock_event_source = Mock()
    mock_event_source.configure_mock(source=mock_event_source,
                                     reference=mock_event_source)
    mock_event_source.signal.return_value = mock_event_source

    mock_data = Mock()

    system = System()
    port = EventPort(system)

    port.connect(mock_event_source)

    port(mock_data)

    mock_event_source.assert_called_with(mock_data)
Example #27
0
def test_input_constraint_access():
    """Test access to input constraint properties"""

    system = System()
    input_1 = InputSignal(system)
    input_2 = InputSignal(system)
    config = SteadyStateConfiguration(system)

    config.inputs[input_1].lower_bounds = 10
    config.inputs[input_2].lower_bounds = 20
    config.inputs[input_1].upper_bounds = 15
    config.inputs[input_2].upper_bounds = 25
    config.inputs[input_1].initial_guess = 100
    npt.assert_equal(config.inputs[input_1].lower_bounds, 10)
    npt.assert_equal(config.inputs[input_2].lower_bounds, 20)
    npt.assert_equal(config.inputs[input_1].upper_bounds, 15)
    npt.assert_equal(config.inputs[input_2].upper_bounds, 25)
    npt.assert_equal(config.inputs[input_1].initial_guess, 100)
Example #28
0
def water_tank_model(
    inflow_area=0.01,
    outflow_area=0.02,
    tank_area=0.2,
    target_height=5,
    initial_condition=None,
    initial_guess=None,
    max_inflow_velocity=None,
):
    """Create a steady-state configuration for a water tank"""

    g = 9.81  # Gravity

    # Create a new system
    system = System()

    # Model the inflow
    inflow_velocity = InputSignal(system)

    # Model the height state
    def height_derivative(data):
        """Calculate the time derivative of the height"""

        return (inflow_area * inflow_velocity(data) -
                outflow_area * np.sqrt(2 * g * height_state(data))) / tank_area

    height_state = State(system, derivative_function=height_derivative)

    # Set up the steady-state configuration
    config = SteadyStateConfiguration(system)
    # Enforce the inflow to be non-negative
    config.inputs[inflow_velocity].lower_bounds = 0
    if max_inflow_velocity is not None:
        config.inputs[inflow_velocity].upper_bounds = max_inflow_velocity
    # Define the target height
    config.states[height_state].lower_bounds = target_height
    config.states[height_state].upper_bounds = target_height

    if initial_condition is not None:
        config.states[height_state].initial_condition = initial_condition
    if initial_guess is not None:
        config.inputs[inflow_velocity].initial_guess = initial_guess

    return config
Example #29
0
def test_zero_crossing_event_detection():
    """Test the detection of zero-crossing events."""

    x0 = 0
    y0 = 10
    vx0 = 1
    vy0 = 0
    g = 9.81
    gamma = 0.7
    system = System()
    bouncing_ball = BouncingBall(parent=system, gravity=-g, gamma=gamma)

    initial_condition = np.empty(system.num_states)
    initial_condition[bouncing_ball.velocity.state_slice] = [vx0, vy0]
    initial_condition[bouncing_ball.position.state_slice] = [x0, y0]

    simulator = Simulator(
        system,
        start_time=0,
        initial_condition=initial_condition,
        max_step=0.05,
        event_detector_options={"max_subdiv": 10},
    )
    result = SimulationResult(system, simulator.run_until(time_boundary=8.0))

    # Determine the time of the first impact
    t_impact = (2 * vy0 + math.sqrt(4 * vy0**2 + 8 * g * y0)) / (2 * g)

    # Check that the y-component of velocity changes sign around time of impact
    t_tolerance = 0.1
    idx_start = bisect.bisect_left(result.time, t_impact - t_tolerance)
    idx_end = bisect.bisect_left(result.time, t_impact + t_tolerance)
    assert result.time[idx_start] < t_impact
    assert result.time[idx_end] >= t_impact
    vy = bouncing_ball.velocity(result)[1][idx_start:idx_end]
    sign_change = np.sign(vy[:-1]) != np.sign(vy[1:])
    assert any(sign_change)

    # Check detection of excessive event error
    with pytest.raises(ExcessiveEventError):
        for _ in simulator.run_until(time_boundary=10.0):
            pass
Example #30
0
def test_simulation_result_dictionary_access():
    """Test the deprecated dictionary access for simulation results"""

    system = System()
    state_a = State(system, initial_condition=10)
    state_b = State(system, shape=2, initial_condition=[11, 12])
    state_c = State(system,
                    shape=(2, 2),
                    initial_condition=[[13, 14], [15, 16]])

    system_state = SystemState(time=0, system=system)

    result = SimulationResult(system)
    result.append(system_state)

    npt.assert_equal(result[state_a], state_a(result))
    npt.assert_equal(result[state_b], state_b(result))
    npt.assert_equal(result[state_b, 0], state_b(result)[0])
    npt.assert_equal(result[state_b, 1], state_b(result)[1])
    npt.assert_equal(result[state_c, 0, 0], state_c(result)[0, 0])