Exemple #1
0
def test_multi_time_system_state():
    """Test the system state with multiple time instances"""

    system = System()
    state_1 = State(owner=system)
    state_2 = State(owner=system, shape=2)
    input_1 = InputSignal(owner=system)
    input_2 = InputSignal(owner=system, shape=2)

    times = np.r_[0.0, 1.0, 2.0]
    states = np.empty(shape=(system.num_states, times.shape[0]))
    inputs = np.empty(shape=(system.num_inputs, times.shape[0]))

    states[state_1.state_slice] = (1.0, 2.0, 3.0)
    states[state_2.state_slice] = ((1.0, 2.0, 3.0), (4.0, 5.0, 6.0))
    inputs[input_1.input_slice] = (1.0, 2.0, 3.0)
    inputs[input_2.input_slice] = ((1.0, 2.0, 3.0), (4.0, 5.0, 6.0))

    system_state = SystemState(system=system,
                               time=times,
                               state=states,
                               inputs=inputs)

    npt.assert_equal(system_state[state_1], (1.0, 2.0, 3.0))
    npt.assert_equal(system_state[state_2], ((1.0, 2.0, 3.0), (4.0, 5.0, 6.0)))

    npt.assert_equal(system_state[input_1], (1.0, 2.0, 3.0))
    npt.assert_equal(system_state[input_2], ((1.0, 2.0, 3.0), (4.0, 5.0, 6.0)))
Exemple #2
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],
    )
Exemple #3
0
def test_system():
    """Test the ``System`` class"""

    system = System()
    state_a = State(
        system,
        shape=(3, 3),
        initial_condition=[[1, 2, 3], [4, 5, 6], [7, 8, 9]],
        derivative_function=None,
    )
    state_b = State(
        system,
        shape=3,
        initial_condition=[10, 11, 12],
        derivative_function=None,
    )
    input_c = InputSignal(system, value=1)
    input_d = InputSignal(system, shape=2, value=[2, 3])
    event_a = ZeroCrossEventSource(system, event_function=None)
    event_b = ZeroCrossEventSource(system, event_function=None)

    # Check the counts
    assert system.num_inputs == input_c.size + input_d.size
    assert system.num_states == state_a.size + state_b.size
    assert system.num_events == 2

    # Check the initial condition
    # This also checks that state indices are disjoint.
    initial_condition = system.initial_condition
    npt.assert_almost_equal(
        initial_condition[state_a.state_slice],
        state_a.initial_condition.ravel(),
    )
    npt.assert_almost_equal(
        initial_condition[state_b.state_slice],
        state_b.initial_condition.ravel(),
    )

    # Check the initial inputs
    # This also checks that input indices are disjoint.
    initial_input = system.initial_input
    npt.assert_almost_equal(initial_input[input_c.input_slice],
                            np.atleast_1d(input_c.value).ravel())
    npt.assert_almost_equal(initial_input[input_d.input_slice],
                            np.atleast_1d(input_d.value).ravel())

    # Check that event indices are disjoint
    assert event_a.event_index != event_b.event_index
Exemple #4
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]
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)
Exemple #6
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)
Exemple #7
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)
Exemple #8
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]
Exemple #9
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]
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
Exemple #11
0
def damped_oscillator(
    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],
    )
    time_constant = 2 * mass / damping_coefficient

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

    return system, lti, 3 * time_constant, [lti.output]
Exemple #12
0
    OutputDescriptor,
)
from modypy.steady_state import SteadyStateConfiguration, find_steady_state

# Constants
G = 9.81  # Gravity
A1 = 0.01  # Inflow cross section
A2 = 0.02  # Outflow cross section
At = 0.2  # Tank cross section
TARGET_HEIGHT = 5

# 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 (A1 * inflow_velocity(data) -
            A2 * np.sqrt(2 * G * height_state(data))) / At


height_state = State(system, derivative_function=height_derivative)

# Configure for steady-state determination
steady_state_config = SteadyStateConfiguration(system)
# Enforce the height to equal the target height
def propeller_model(
    thrust_coefficient=0.09,
    power_coefficient=0.04,
    density=1.29,
    diameter=8 * 25.4e-3,
    moment_of_inertia=5.284e-6,
    target_thrust=1.5 * 9.81 / 4,
    maximum_torque=None,
):
    """Create a steady-state configuration for two propellers"""

    system = System()

    torque_1 = InputSignal(system)
    torque_2 = InputSignal(system)

    density_signal = constant(density)

    propeller_1 = Propeller(
        system,
        thrust_coefficient=thrust_coefficient,
        power_coefficient=power_coefficient,
        diameter=diameter,
    )
    propeller_2 = Propeller(
        system,
        thrust_coefficient=thrust_coefficient,
        power_coefficient=power_coefficient,
        diameter=diameter,
    )

    def speed_1_dt(data):
        """Derivative of the speed of the first propeller"""
        tot_torque = torque_1(data) - propeller_1.torque(data)
        return tot_torque / (2 * np.pi * moment_of_inertia)

    def speed_2_dt(data):
        """Derivative of the speed of the second propeller"""
        tot_torque = torque_2(data) - propeller_2.torque(data)
        return tot_torque / (2 * np.pi * moment_of_inertia)

    speed_1 = State(system, derivative_function=speed_1_dt)
    speed_2 = State(system, derivative_function=speed_2_dt)

    propeller_1.density.connect(density_signal)
    propeller_2.density.connect(density_signal)
    propeller_1.speed_rps.connect(speed_1)
    propeller_2.speed_rps.connect(speed_2)

    total_thrust = sum_signal((propeller_1.thrust, propeller_2.thrust))
    total_power = sum_signal((propeller_1.power, propeller_2.power))

    # Set up steady-state configuration
    config = SteadyStateConfiguration(system)
    # Minimize the total power
    config.objective = total_power
    # Constrain the speed to be positive
    config.states[speed_1].lower_bounds = 0
    config.states[speed_2].lower_bounds = 0
    # Constrain the torques to be positive
    config.inputs[torque_1].lower_bounds = 0
    config.inputs[torque_2].lower_bounds = 0
    npt.assert_equal(config.inputs[torque_1].lower_bounds, 0)
    npt.assert_equal(config.inputs[torque_2].lower_bounds, 0)
    if maximum_torque is not None:
        config.inputs[torque_1].upper_bounds = maximum_torque
        config.inputs[torque_2].upper_bounds = maximum_torque

    # Constrain the total thrust
    config.ports[total_thrust].lower_bounds = target_thrust
    config.ports[total_thrust].upper_bounds = target_thrust

    return config
Exemple #14
0
           direction=1,
           **parameters),
    Engine(system,
           vector=np.c_[0, 0, -1],
           arm=np.c_[+POSITION_X, -POSITION_Y, 0],
           direction=-1,
           **parameters),
]

# Create input and output signals.
# The steady-state determination will try to vary the input signals and states
# such that the state derivatives and the output signals are zero.

# Create individual input signals for the voltages of the four engines
voltages = [
    InputSignal(system, value=0),
    InputSignal(system, value=0),
    InputSignal(system, value=0),
    InputSignal(system, value=0),
]

# Provide the air density as input
density = constant(value=1.29)

# Connect the engines
for idx, engine in zip(itertools.count(), engines):
    # Provide voltage and density to the engine
    voltages[idx].connect(engine.voltage)
    density.connect(engine.density)

# We consider gravity and a possible counter torque that need to be compensated
Exemple #15
0
def test_system_state():
    """Test the ``SystemState`` class"""

    system = System()

    input_a = InputSignal(system, shape=(3, 3), value=np.eye(3))
    input_c = InputSignal(system, value=1)
    input_d = InputSignal(system, shape=2, value=[2, 3])
    state_a = State(
        system,
        shape=(3, 3),
        initial_condition=[[1, 2, 3], [4, 5, 6], [7, 8, 9]],
        derivative_function=input_a,
    )
    state_a_dep = State(
        system,
        shape=(3, 3),
        initial_condition=[[1, 2, 3], [4, 5, 6], [7, 8, 9]],
        derivative_function=input_a,
    )
    state_b = State(
        system,
        shape=3,
        initial_condition=[10, 11, 12],
        derivative_function=(lambda data: np.r_[13, 14, 15]),
    )
    state_b1 = State(system, shape=3, derivative_function=state_b)
    state_b2 = State(system, shape=3, derivative_function=None)
    signal_c = constant(value=16)
    event_a = ZeroCrossEventSource(system, event_function=(lambda data: 23))

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

    # Check the initial state
    npt.assert_almost_equal(
        system_state.state[state_a.state_slice],
        state_a.initial_condition.ravel(),
    )
    npt.assert_almost_equal(
        system_state.state[state_a_dep.state_slice],
        state_a_dep.initial_condition.ravel(),
    )
    npt.assert_almost_equal(
        system_state.state[state_b.state_slice],
        state_b.initial_condition.ravel(),
    )
    npt.assert_almost_equal(
        system_state.state[state_b1.state_slice],
        state_b1.initial_condition.ravel(),
    )
    npt.assert_almost_equal(system_state.state[state_b2.state_slice],
                            np.zeros(state_b2.size))

    # Check the inputs property
    npt.assert_almost_equal(system_state.inputs[input_a.input_slice],
                            np.ravel(input_a.value))
    npt.assert_almost_equal(system_state.inputs[input_c.input_slice],
                            np.ravel(input_c.value))
    npt.assert_almost_equal(system_state.inputs[input_d.input_slice],
                            np.ravel(input_d.value))

    # Check the get_state_value function
    npt.assert_almost_equal(system_state.get_state_value(state_a),
                            state_a.initial_condition)
    npt.assert_almost_equal(system_state.get_state_value(state_a_dep),
                            state_a_dep.initial_condition)
    npt.assert_almost_equal(system_state.get_state_value(state_b),
                            state_b.initial_condition)

    # Check the function access
    npt.assert_equal(event_a(system_state),
                     event_a.event_function(system_state))
    npt.assert_equal(state_a(system_state), state_a.initial_condition)
    npt.assert_equal(input_a(system_state), input_a.value)
    npt.assert_equal(signal_c(system_state), signal_c.value)