Esempio n. 1
0
def test_events():
    # use bouncing ball to test events work

    # simulate in block diagram
    int_opts = block_diagram.DEFAULT_INTEGRATOR_OPTIONS.copy()
    int_opts['rtol'] = 1E-12
    int_opts['atol'] = 1E-15
    int_opts['nsteps'] = 1000
    int_opts['max_step'] = 2**-3
    x = x1, x2 = Array(dynamicsymbols('x_1:3'))
    mu, g = sp.symbols('mu g')
    constants = {mu: 0.8, g: 9.81}
    ic = np.r_[10, 15]
    sys = SwitchedSystem(
        x1, Array([0]),
        state_equations=r_[x2, -g],
        state_update_equation=r_[sp.Abs(x1), -mu*x2],
        state=x,
        constants_values=constants,
        initial_condition=ic
    )
    bd = BlockDiagram(sys)
    res = bd.simulate(5, integrator_options=int_opts)

    # compute actual impact time
    tvar = dynamicsymbols._t
    impact_eq = (x2*tvar - g*tvar**2/2 + x1).subs(
        {x1: ic[0], x2: ic[1], g: 9.81}
    )
    t_impact = sp.solve(impact_eq, tvar)[-1]

    # make sure simulation actually changes velocity sign around impact
    abs_diff_impact = np.abs(res.t - t_impact)
    impact_idx = np.where(abs_diff_impact == np.min(abs_diff_impact))[0]
    assert np.sign(res.x[impact_idx-1, 1]) != np.sign(res.x[impact_idx+1, 1])
Esempio n. 2
0
 def input(self, input_):
     if input_ is None:  # or other checks?
         input_ = empty_array()
     if isinstance(input_, sp.Expr):  # check it's a single dynamicsymbol?
         input_ = Array([input_])
     self.dim_input = len(input_)
     self._inputs = input_
Esempio n. 3
0
 def state(self, state):
     if state is None:  # or other checks?
         state = empty_array()
     if isinstance(state, sp.Expr):
         state = Array([state])
     self.dim_state = len(state)
     self._state = state
Esempio n. 4
0
def augment_input(system, input_=[], update_outputs=True):
    """
    Augment input, useful to construct control-affine systems.

    Parameters
    ----------
    system : DynamicalSystem
        The sytsem to augment the input of
    input_ : array_like of symbols, optional
        The input to augment. Use to augment only a subset of input components.
    update_outputs : boolean
        If true and the system provides full state output, will also add the
        augmented inputs to the output.
    """
    # accept list, etc of symbols to augment
    augmented_system = system.copy()
    if input_ == []:
        # augment all
        input_ = system.input

    augmented_system.state = r_[system.state, input_]
    augmented_system.input = Array([
        dynamicsymbols(str(input_var.func) + 'prime') for input_var in input_
    ])
    augmented_system.state_equation = r_[system.state_equation,
                                         augmented_system.input]

    if update_outputs and system.output_equation == system.state:
        augmented_system.output_equation = augmented_system.state

    return augmented_system
Esempio n. 5
0
    def output_equation(self, output_equation):
        if isinstance(output_equation, sp.Expr):
            output_equation = Array([output_equation])
        if output_equation is None and self.dim_state == 0:
            output_equation = empty_array()
        else:
            if output_equation is None:
                output_equation = self.state

            assert output_equation.atoms(
                sp.Symbol) <= (set(self.constants_values.keys())
                               | set([dynamicsymbols._t]))

            if self.dim_state:
                assert find_dynamicsymbols(output_equation) <= set(self.state)
            else:
                assert find_dynamicsymbols(output_equation) <= set(self.input)

        self.dim_output = len(output_equation)

        self._output_equation = output_equation
        self.update_output_equation_function()
Esempio n. 6
0
BlockDiagram = block_diagram.BlockDiagram
int_opts = block_diagram.DEFAULT_INTEGRATOR_OPTIONS.copy()
find_opts = block_diagram.DEFAULT_EVENT_FIND_OPTIONS.copy()

int_opts['rtol'] = 1E-12
int_opts['atol'] = 1E-15
int_opts['nsteps'] = 1000

find_opts['xtol'] = 1E-12
find_opts['maxiter'] = int(1E3)

# This example shows how to implement a simple saturation block

# create an oscillator to generate the sinusoid
x = Array([dynamicsymbols('x')])  # placeholder output symbol
tvar = dynamicsymbols._t  # use this symbol for time
sin = DynamicalSystem(Array([sp.cos(tvar)]), x)  # define the oscillator,

llim = -0.75
ulim = 0.75
saturation_limit = r_[llim, ulim]
saturation_output = r_['0,2', llim, x[0], ulim]
sat = SwitchedOutput(x[0],
                     saturation_limit,
                     output_equations=saturation_output,
                     input_=x)

sat_bd = BlockDiagram(sin, sat)
sat_bd.connect(sin, sat)
Esempio n. 7
0
This example shows how to use a SwitchedSystem to model a bouncing ball. The
event detection accurately finds the point of impact, and the simulation
is generally accurate when the ball has sufficient energy. However, due to
numerical error, the simulation does show the ball chattering after all
the energy should have been dissipated.
"""

int_opts['rtol'] = 1E-12
int_opts['atol'] = 1E-15
int_opts['nsteps'] = 1000
int_opts['max_step'] = 2**-3

find_opts['xtol'] = 1E-12
find_opts['maxiter'] = int(1E3)

x = x1, x2 = Array(dynamicsymbols('x_1:3'))
mu, g = sp.symbols('mu g')
constants = {mu: 0.8, g: 9.81}
ic = np.r_[10, 15]
sys = SwitchedSystem(x1,
                     Array([0]),
                     state_equations=r_[x2, -g],
                     state_update_equation=r_[sp.Abs(x1), -mu * x2],
                     state=x,
                     constants_values=constants,
                     initial_condition=ic)
bd = BlockDiagram(sys)
res = bd.simulate(25,
                  integrator_options=int_opts,
                  event_find_options=find_opts)
Esempio n. 8
0
import numpy as np
import sympy as sp
import matplotlib.pyplot as plt
from simupy.systems.symbolic import DynamicalSystem, dynamicsymbols
from simupy.block_diagram import BlockDiagram
from simupy.array import Array, r_

plt.ion()

# This example simulates the Van der Pol oscillator.

x = x1, x2 = Array(dynamicsymbols('x1:3'))

mu = sp.symbols('mu')

state_equation = r_[x2, -x1 + mu * (1 - x1**2) * x2]
output_equation = r_[x1**2 + x2**2, sp.atan2(x2, x1)]

sys = DynamicalSystem(state_equation,
                      x,
                      output_equation=output_equation,
                      constants_values={mu: 5})

sys.initial_condition = np.array([1, 1]).T

BD = BlockDiagram(sys)
res = BD.simulate(30)

plt.figure()
plt.plot(res.t, res.x)
plt.legend([sp.latex(s, mode='inline') for s in sys.state])
Esempio n. 9
0
import numpy as np
import sympy as sp
import matplotlib.pyplot as plt
from simupy.systems.symbolic import DynamicalSystem, dynamicsymbols
from simupy.block_diagram import BlockDiagram
from simupy.array import Array, r_
from simupy.discontinuities import SwitchedOutput

plt.ion()

# This example shows how to implement a simple saturation block

llim = -0.75
ulim = 0.75

x = Array([dynamicsymbols('x')])
tvar = dynamicsymbols._t
sin = DynamicalSystem(Array([sp.cos(tvar)]), x)

sin_bd = BlockDiagram(sin)
sin_res = sin_bd.simulate(2 * np.pi)

plt.figure()
plt.plot(sin_res.t, sin_res.x)

limit = r_[llim, ulim]
saturation_output = r_['0,2', llim, x[0], ulim]

sat = SwitchedOutput(x[0], limit, output_equations=saturation_output, input_=x)
sat_bd = BlockDiagram(sin, sat)
sat_bd.connect(sin, sat)