コード例 #1
0
 def __init__(
     self,
     parent,
     gravity=-9.81,
     gamma=0.7,
     initial_velocity=None,
     initial_position=None,
 ):
     Block.__init__(self, parent)
     self.position = State(
         self,
         shape=2,
         derivative_function=self.position_derivative,
         initial_condition=initial_position,
     )
     self.velocity = State(
         self,
         shape=2,
         derivative_function=self.velocity_derivative,
         initial_condition=initial_velocity,
     )
     self.ground = ZeroCrossEventSource(self,
                                        event_function=self.ground_event,
                                        direction=-1)
     self.ground.register_listener(self.on_ground_event)
     self.gravity = gravity
     self.gamma = gamma
コード例 #2
0
    def __init__(
        self,
        parent,
        motor_constant,
        resistance,
        inductance,
        moment_of_inertia,
        initial_speed=None,
        initial_current=None,
    ):
        Block.__init__(self, parent)
        self.motor_constant = motor_constant
        self.resistance = resistance
        self.inductance = inductance
        self.moment_of_inertia = moment_of_inertia

        # Create the velocity and current state
        # These can also be used as signals which export the exact value of
        # the respective state.
        self.omega = State(
            self,
            derivative_function=self.omega_dt,
            initial_condition=initial_speed,
        )
        self.current = State(
            self,
            derivative_function=self.current_dt,
            initial_condition=initial_current,
        )

        # Create (input) ports for voltage and external torque load
        self.voltage = Port()
        self.external_torque = Port()
コード例 #3
0
    def __init__(
        self,
        parent,
        motor_constant,
        resistance,
        inductance,
        moment_of_inertia,
        initial_omega=0,
        initial_current=0,
    ):
        Block.__init__(self, parent)

        self.motor_constant = motor_constant
        self.resistance = resistance
        self.inductance = inductance
        self.moment_of_inertia = moment_of_inertia

        self.voltage = Port()
        self.external_torque = Port()

        self.omega = State(
            self,
            derivative_function=self.omega_dot,
            initial_condition=initial_omega,
        )
        self.current = State(
            self,
            derivative_function=self.current_dot,
            initial_condition=initial_current,
        )
コード例 #4
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
コード例 #5
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)))
コード例 #6
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
コード例 #7
0
def test_system_state_dictionary_access():
    """Test the deprecated dictionary access for system states"""

    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)

    npt.assert_equal(system_state[state_a], state_a(system_state))
    npt.assert_equal(system_state[state_b], state_b(system_state))
    npt.assert_equal(system_state[state_b, 0], state_b(system_state)[0])
    npt.assert_equal(system_state[state_b, 1], state_b(system_state)[1])
    npt.assert_equal(system_state[state_c, 0, 0], state_c(system_state)[0, 0])
コード例 #8
0
    def __init__(
        self,
        owner,
        mass,
        moment_of_inertia,
        initial_velocity_earth=None,
        initial_position_earth=None,
        initial_transformation=None,
        initial_angular_rates_earth=None,
    ):
        Block.__init__(self, owner)
        self.mass = mass
        self.moment_of_inertia = moment_of_inertia

        self.forces_body = Port(shape=3)
        self.moments_body = Port(shape=3)

        if initial_transformation is None:
            initial_transformation = np.eye(3)

        self.velocity_earth = State(
            self,
            shape=3,
            derivative_function=self.velocity_earth_dot,
            initial_condition=initial_velocity_earth,
        )
        self.position_earth = State(
            self,
            shape=3,
            derivative_function=self.position_earth_dot,
            initial_condition=initial_position_earth,
        )
        self.omega_earth = State(
            self,
            shape=3,
            derivative_function=self.omega_earth_dot,
            initial_condition=initial_angular_rates_earth,
        )
        self.dcm = State(
            self,
            shape=(3, 3),
            derivative_function=self.dcm_dot,
            initial_condition=initial_transformation,
        )
コード例 #9
0
ファイル: test_simulation.py プロジェクト: ralfgerlich/modypy
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])
コード例 #10
0
def test_state_constraint_access():
    """Test access to state constraint properties"""

    system = System()
    state_1 = State(system)
    state_2 = State(system)
    config = SteadyStateConfiguration(system)

    config.states[state_1].lower_bounds = 10
    config.states[state_2].lower_bounds = 20
    config.states[state_1].upper_bounds = 15
    config.states[state_2].upper_bounds = 25
    config.states[state_2].steady_state = False
    config.states[state_1].initial_condition = 100
    npt.assert_equal(config.states[state_1].lower_bounds, 10)
    npt.assert_equal(config.states[state_2].lower_bounds, 20)
    npt.assert_equal(config.states[state_1].upper_bounds, 15)
    npt.assert_equal(config.states[state_2].upper_bounds, 25)
    assert not config.states[state_2].steady_state
    npt.assert_equal(config.states[state_1].initial_condition, 100)
コード例 #11
0
def test_state():
    """Test the ``State`` class"""

    system = System()
    state_a = State(system, derivative_function=(lambda data: 0))
    state_b = State(system,
                    shape=3,
                    derivative_function=(lambda data: np.zeros(3)))
    state_c = State(system,
                    shape=(3, 3),
                    derivative_function=(lambda data: np.zeros(3, 3)))
    state_d = State(system,
                    derivative_function=(lambda data: 0),
                    initial_condition=1)

    # Check the sizes
    assert state_a.size == 1
    assert state_b.size == 3
    assert state_c.size == 9
    assert state_d.size == 1

    # Test the slice property
    assert state_c.state_slice == slice(state_c.state_index,
                                        state_c.state_index + state_c.size)
コード例 #12
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)
コード例 #13
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
コード例 #14
0
ファイル: discrete.py プロジェクト: ralfgerlich/modypy
    def __init__(self, owner, shape=1, initial_condition=None):
        """
        Constructor for ``ZeroOrderHold``

        Args:
            owner: The owner of the block (system or block)
            shape: The shape of the input and output signal
            initial_condition: The initial state of the sampling output
                (before the first tick of the block)
        """
        Block.__init__(self, owner)

        self.event_input = EventPort(self)
        self.event_input.register_listener(self.update_state)
        self.input = Port(shape=shape)
        self.output = State(
            self,
            shape=shape,
            initial_condition=initial_condition,
            derivative_function=None,
        )
コード例 #15
0
ファイル: test_simulation.py プロジェクト: ralfgerlich/modypy
def test_system_state_updater_dictionary_access():
    """Test the deprecated dictionary access for simulation results"""

    system = System()
    counter = State(system, shape=(2, 2))

    clock = Clock(system, 1.0)

    def _update_counter(system_state):
        old_val = counter(system_state).copy()
        system_state[counter] += 1
        system_state[counter, 0] += 1
        system_state[counter, 0, 0] += 1
        new_val = counter(system_state)
        npt.assert_almost_equal(old_val + [[3, 2], [1, 1]], new_val)

    clock.register_listener(_update_counter)

    simulator = Simulator(system, start_time=0)
    for _ in simulator.run_until(time_boundary=10):
        pass
コード例 #16
0
ファイル: test_simulation.py プロジェクト: ralfgerlich/modypy
def test_excessive_events_second_level():
    """Test the detection of excessive events when it is introduced by
    toggling the same event over and over."""

    system = System()
    state = State(system,
                  derivative_function=(lambda data: -1),
                  initial_condition=5)
    event = ZeroCrossEventSource(system, event_function=state)

    def event_handler(data):
        """Event handler for the zero-crossing event"""
        state.set_value(data, -state(data))

    event.register_listener(event_handler)

    simulator = Simulator(system, start_time=0)

    with pytest.raises(ExcessiveEventError):
        for _ in simulator.run_until(6):
            pass
コード例 #17
0
ファイル: test_simulation.py プロジェクト: ralfgerlich/modypy
def test_discrete_only():
    """Test a system with only discrete-time states."""

    system = System()
    clock = Clock(system, period=1.0)
    counter = State(system)

    def increase_counter(data):
        """Increase the counter whenever a clock event occurs"""
        counter.set_value(data, counter(data) + 1)

    clock.register_listener(increase_counter)

    simulator = Simulator(system, start_time=0.0)
    result = SimulationResult(system)
    result.collect_from(simulator.run_until(5.5, include_last=False))
    result.collect_from(simulator.run_until(10))

    npt.assert_almost_equal(result.time,
                            [0, 1, 2, 3, 4, 5, 5.5, 6, 7, 8, 9, 10])
    npt.assert_almost_equal(counter(result),
                            [1, 2, 3, 4, 5, 6, 6, 7, 8, 9, 10, 11])
コード例 #18
0
ファイル: linear.py プロジェクト: ralfgerlich/modypy
def integrator(owner, input_signal, initial_condition=None):
    """
    Create a state that provides the integrated value of the input
    callable.

    The resulting signal will have the same shape as the input callable.

    Args:
        owner: The owner of the integrator
        input_signal: A callable accepting an object implementing the system
            object access protocol and providing the value of the derivative
        initial_condition: The initial condition of the integrator
            (default: ``None``)

    Returns:
        A state that provides the integrated value of the input signal
    """

    return State(
        owner,
        shape=input_signal.shape,
        derivative_function=input_signal,
        initial_condition=initial_condition,
    )
コード例 #19
0
ファイル: 03_planet_orbit.py プロジェクト: ralfgerlich/modypy
# Create the system
system = System()


# Define the derivatives
def velocity_dt(system_state):
    """Calculate the derivative of the velocity"""
    pos = position(system_state)
    distance = linalg.norm(pos, axis=0)
    return -G * SUN_MASS / (distance**3) * pos


# Create the states
velocity = State(
    owner=system,
    shape=2,
    derivative_function=velocity_dt,
    initial_condition=V_0,
)
position = State(owner=system,
                 shape=2,
                 derivative_function=velocity,
                 initial_condition=X_0)

# Run a simulation
simulator = Simulator(system, start_time=0.0, max_step=24 * 60 * 60)
result = SimulationResult(system,
                          simulator.run_until(time_boundary=ROTATION_TIME))

# Plot the result
trajectory = position(result)
plt.plot(trajectory[0], trajectory[1])
コード例 #20
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)
コード例 #21
0
    moment_of_inertia=MOMENT_OF_INERTIA,
    thrust_coefficient=THRUST_COEFFICIENT,
    power_coefficient=POWER_COEFFICIENT,
    diameter=DIAMETER,
)

# Provide constant signals for the voltage and the air density
voltage = constant(value=3.5)
density = constant(value=1.29)

# Connect them to the corresponding inputs of the engine
engine.voltage.connect(voltage)
engine.density.connect(density)

# Set up the state for keeping the sampled value.
sample_state = State(system)

# Create a clock for sampling at 100Hz
sample_clock = Clock(system, period=0.01)


# Define the function for updating the state
def update_sample(system_state):
    """Update the state of the sampler"""
    sample_state.set_value(system_state, engine.thrust(system_state))


# Register it as event handler on the clock
sample_clock.register_listener(update_sample)

# Create the simulator and run it
コード例 #22
0
ファイル: 01_integrator.py プロジェクト: ralfgerlich/modypy
from matplotlib import pyplot as plt
from modypy.model import State, System, signal_function
from modypy.simulation import SimulationResult, Simulator

# Create a new system
system = System()


# Define the cosine signal
@signal_function
def cosine_input(system_state):
    """Calculate the value of the input signal"""
    return np.cos(system_state.time)


integrator_state = State(system, derivative_function=cosine_input)

# Set up a simulation
simulator = Simulator(system, start_time=0.0, max_step=0.1)

# Run the simulation for 10s and capture the result
result = SimulationResult(system, simulator.run_until(time_boundary=10.0))

# Plot the result
input_line, integrator_line = plt.plot(
    result.time,
    cosine_input(result),
    "r",
    result.time,
    integrator_state(result),
    "g",
コード例 #23
0
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
コード例 #24
0
# 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
steady_state_config.states[height_state].lower_bounds = TARGET_HEIGHT
steady_state_config.states[height_state].upper_bounds = TARGET_HEIGHT
# Enforce the inflow to be non-negative
steady_state_config.inputs[inflow_velocity].lower_bounds = 0

# Find the steady state
result = find_steady_state(steady_state_config)
print("Target height: %f" % TARGET_HEIGHT)
print("Steady state height: %f" % height_state(result.system_state))
print("Steady state inflow: %f" % inflow_velocity(result.system_state))
print("Steady state height derivative: %f" %
コード例 #25
0
ファイル: linear.py プロジェクト: ralfgerlich/modypy
    def __init__(
        self,
        parent,
        system_matrix,
        input_matrix,
        output_matrix,
        feed_through_matrix,
        initial_condition=None,
    ):
        Block.__init__(self, parent)

        # Determine the number of states and the shape of the state
        if np.isscalar(system_matrix):
            self.state_shape = ()
            num_states = 1
        else:
            system_matrix = np.asarray(system_matrix)
            if (system_matrix.ndim == 2 and system_matrix.shape[0] > 0
                    and system_matrix.shape[0] == system_matrix.shape[1]):
                self.state_shape = system_matrix.shape[0]
                num_states = self.state_shape
            else:
                raise InvalidLTIException("The system matrix must be a scalar "
                                          "or a non-empty square matrix")

        # Determine the number of inputs and the shape of the input signal
        if np.isscalar(input_matrix):
            if num_states > 1:
                raise InvalidLTIException("There is more than one state, but "
                                          "the input matrix is neither empty, "
                                          "nor a vector or a matrix")
            num_inputs = 1
            self.input_shape = ()
        else:
            input_matrix = np.asarray(input_matrix)
            if input_matrix.ndim == 1:
                # The input matrix is a column vector => one input
                if num_states != input_matrix.shape[0]:
                    raise InvalidLTIException(
                        "The height of the input matrix "
                        "must match the number of states")
                num_inputs = 1
            elif input_matrix.ndim == 2:
                # The input matrix is a matrix
                if num_states != input_matrix.shape[0]:
                    raise InvalidLTIException("The height of the input matrix "
                                              "does not match the number of "
                                              "states")
                num_inputs = input_matrix.shape[1]
            else:
                raise InvalidLTIException("The input matrix must be empty,"
                                          "a scalar, a vector or a matrix")
            self.input_shape = num_inputs

        # Determine the number of outputs and the shape of the output array
        if np.isscalar(output_matrix):
            if num_states > 1:
                raise InvalidLTIException("There is more than one state, but "
                                          "the output matrix is neither an "
                                          "empty, a vector nor a matrix")
            num_outputs = 1
            self.output_shape = ()
        else:
            output_matrix = np.asarray(output_matrix)
            if output_matrix.ndim == 1:
                # The output matrix is a row vector => one output
                if num_states != output_matrix.shape[0]:
                    raise InvalidLTIException("The width of the output matrix "
                                              "does not match the number of "
                                              "states")
                num_outputs = 1
            elif output_matrix.ndim == 2:
                # The output matrix is a matrix
                if num_states != output_matrix.shape[1]:
                    raise InvalidLTIException("The width of the output matrix "
                                              "does not match the number of "
                                              "states")
                num_outputs = output_matrix.shape[0]
            else:
                raise InvalidLTIException("The output matrix must be empty, a"
                                          "scalar, a vector or a matrix")
            self.output_shape = num_outputs

        if np.isscalar(feed_through_matrix):
            if not (num_inputs == 1 and num_outputs == 1):
                raise InvalidLTIException("A scalar feed-through matrix is "
                                          "only allowed for systems with "
                                          "exactly one input and one output")
        else:
            feed_through_matrix = np.asarray(feed_through_matrix)
            if feed_through_matrix.ndim == 1:
                # A vector feed_through_matrix is interpreted as row vector,
                # so there must be exactly one output.
                if num_outputs == 0:
                    raise InvalidLTIException("The feed-through matrix for a "
                                              "system without outputs must be"
                                              "empty")
                elif num_outputs > 1:
                    raise InvalidLTIException("The feed-through matrix for a "
                                              "system with more than one "
                                              "output must be a matrix")
                if feed_through_matrix.shape[0] != num_inputs:
                    raise InvalidLTIException(
                        "The width of the feed-through "
                        "matrix must match the number of "
                        "inputs")
            elif feed_through_matrix.ndim == 2:
                if feed_through_matrix.shape[0] != num_outputs:
                    raise InvalidLTIException(
                        "The height of the feed-through "
                        "matrix must match the number of "
                        "outputs")
                if feed_through_matrix.shape[1] != num_inputs:
                    raise InvalidLTIException(
                        "The width of the feed-through "
                        "matrix must match the number of "
                        "inputs")
            else:
                raise InvalidLTIException("The feed-through matrix must be "
                                          "empty, a scalar, a vector or a "
                                          "matrix")

        self.system_matrix = system_matrix
        self.input_matrix = input_matrix
        self.output_matrix = output_matrix
        self.feed_through_matrix = feed_through_matrix

        self.input = Port(shape=self.input_shape)
        self.state = State(
            self,
            shape=self.state_shape,
            derivative_function=self.state_derivative,
            initial_condition=initial_condition,
        )
        self.output = Signal(shape=self.output_shape,
                             value=self.output_function)
コード例 #26
0
# The initial conditions
INITIAL_HEIGHT = 10.0
INITIAL_VELOCITY = 0.0

# The system
system = System()


# The system states
def velocity_dt(_system_state):
    """Calculate the derivative of the vertical speed"""
    return -G


velocity = State(system,
                 derivative_function=velocity_dt,
                 initial_condition=INITIAL_VELOCITY)
height = integrator(system,
                    input_signal=velocity,
                    initial_condition=INITIAL_HEIGHT)

# Run a simulation without event handler
simulator = Simulator(system=system, start_time=0, max_step=0.1)
result = SimulationResult(system=system)
result.collect_from(simulator.run_until(time_boundary=2))

# Plot the simulation result
plt.plot(result.time, height(result))
plt.xlabel("Time (s)")
plt.ylabel("Height (m)")
plt.title("Falling Ball")