def testConvertMIMO(self):
        """Test state space to transfer function conversion.

        Do a MIMO conversion and make sure that it is processed
        correctly both with and without slycot

        Example from issue gh-120, jgoppert
        """

        # Set up a 1x3 transfer function (should always work)
        tsys = tf([[[-235, 1.146e4],
                    [-235, 1.146E4],
                    [-235, 1.146E4, 0]]],
                  [[[1, 48.78, 0],
                    [1, 48.78, 0, 0],
                    [0.008, 1.39, 48.78]]])

        # Convert to state space and look for an error
        if (not slycot_check()):
            with pytest.raises(TypeError):
                tf2ss(tsys)
        else:
            ssys = tf2ss(tsys)
            assert ssys.B.shape[1] == 3
            assert ssys.C.shape[0] == 1
示例#2
0
def test_xferfcn_ndarray_precedence(op, tf, arr):
    # Apply the operator to the transfer function and array
    ss = ct.tf2ss(tf)
    result = op(ss, arr)
    assert isinstance(result, ct.StateSpace)

    # Apply the operator to the array and transfer function
    ss = ct.tf2ss(tf)
    result = op(arr, ss)
    assert isinstance(result, ct.StateSpace)
def ActuatorModel(bw, delay=(0, 1)):
    # Inputs: ['cmd']
    # Outputs: ['pos']

    sysNom = control.tf2ss(control.tf(1, [1 / bw, 1]))

    delayPade = control.pade(delay[0], n=delay[1])
    sysDelay = control.tf2ss(control.tf(delayPade[0], delayPade[1]))

    sys = sysDelay * sysNom

    return sys
    def test_tf2ss_nonproper(self):
        """Unit tests for non-proper transfer functions"""
        # Easy case: input 2 to output 1 is 's'
        num =  [ [[0], [1, 0]],  [[1],   [0]] ]
        den1 = [ [[1], [1]],     [[1,4], [1]] ]
        with pytest.raises(ValueError):
            tf2ss(tf(num, den1))

        # Trickier case (make sure that leading zeros in den are handled)
        num =  [ [[0], [1, 0]],  [[1],   [0]] ]
        den1 = [ [[1], [0, 1]],  [[1,4], [1]] ]
        with pytest.raises(ValueError):
            tf2ss(tf(num, den1))
示例#5
0
    def from_TF(tf: _ctrl.TransferFunction) -> "Plant":
        """
        Creates an instance of `Plant` from transfer function. Note
        that `C2` becomes 0 .

        Parameters
        ----------
        tf : control.TransferFunction
            Transfer function from input u to output z.

        Returns
        -------
        Plant

        Notes
        -----
        An instance of `Plant` represents a plant
        P given by

            P : { x(t+1) =  A x(t) + B u(t)
                {  z(t)  = C1 x(t)
                {  y(t)  = C2 x(t)

        But if you use this method, `C2` becomes `0`.
        """
        ss = _ctrl.tf2ss(tf)
        ret = Plant(
            A=matrix(ss.A),
            B=matrix(ss.B),
            C1=matrix(ss.C),
            C2=matrix(zeros(ss.C.shape)),
        )
        ret.tf1 = tf
        ret.tf2 = tf*0
        return ret
示例#6
0
    def make_statespace(self):
        jm = self.parameters["DC-Motor"]["Jm"]
        bm = self.parameters["DC-Motor"]["Bm"]
        kme = self.parameters["DC-Motor"]["Kme"]
        kmt = self.parameters["DC-Motor"]["Kmt"]
        rm = self.parameters["DC-Motor"]["Rm"]
        lm = self.parameters["DC-Motor"]["Lm"]

        kdm = self.parameters["DC-Motor"]["Kdm"]
        kpm = self.parameters["DC-Motor"]["Kpm"]
        kim = self.parameters["DC-Motor"]["Kim"]
        nm = self.parameters["DC-Motor"]["Nm"]

        dc = control.TransferFunction(
            [0, kmt], [jm * lm, bm * lm + jm * rm, bm * rm + kme * kmt])
        pidm = control.TransferFunction(
            [kpm + kdm * nm, kpm * nm + kim, kim * nm], [1, nm, 0])

        ii = control.TransferFunction([1], [1, 0, 0])

        agv = ii * control.feedback(dc * pidm, sign=-1)

        # Laplace --> Z
        agvz = control.sample_system(agv, lib.pt, method='zoh')

        # Transferfunction --> StateSpace
        ss = control.tf2ss(agvz)

        lib.set_statespace(ss)
示例#7
0
def cssBlk(pin, pout, sys, X0=[]):
    """ 

    Continous state space block

    Call: cssBlk(pin,pout, sys,X0)

    Parameters
    ----------
        pin : connected input ports
        pout: connected output ports
        sys: Discrete system in SS form
        X0: Initial conditions

    Returns
    -------
        blk  : RCPblk

    """
    if isinstance(sys, TransferFunction):
        sys = tf2ss(sys)

    nin = size(pin)
    ni = shape(sys.B)[1]
    if (nin != ni):
        raise ValueError("Block Robi have %i inputs: received %i input ports" %
                         (nin, ni))

    no = shape(sys.C)[0]
    nout = size(pout)
    if (no != nout):
        raise ValueError("Block have %i outputs: received %i output ports" %
                         (nout, no))

    a = reshape(sys.A, (1, size(sys.A)), 'C')
    b = reshape(sys.B, (1, size(sys.B)), 'C')
    c = reshape(sys.C, (1, size(sys.C)), 'C')
    d = reshape(sys.D, (1, size(sys.D)), 'C')
    nx = shape(sys.A)[0]

    if (size(X0) == nx):
        X0 = reshape(X0, (1, size(X0)), 'C')
    else:
        X0 = mat(zeros((1, nx)))

    indA = 1
    indB = indA + nx * nx
    indC = indB + nx * ni
    indD = indC + nx * no
    indX = indD + ni * no
    intPar = [nx, ni, no, indA, indB, indC, indD, indX]
    realPar = hstack((mat([0.0]), a, b, c, d, X0))

    if d.any() == True:
        uy = 1
    else:
        uy = 0

    blk = RCPblk('css', pin, pout, [nx, 0], uy, realPar, intPar)
    return blk
示例#8
0
def sim_setup_theta():
    num = num_theta()
    den = den_long()
    sys = tf2ss(tf(num, den))
    n_axis = 1
    task = [5, 1, 2]
    return sys, n_axis, task
示例#9
0
    def myfunc(variant: int):
        """Generate test systems. """
        A = np.array((0, 0, 0, 1, 0, -0.9215, 0, 1, -0.738)).reshape((3, 3))
        B = np.array((1 + 0.1 * variant, 0, 0)).reshape((3, 1))
        C = np.array((0, 0.151, -0.6732)).reshape((1, 3))
        D = np.zeros((1, 1))

        sys1 = StateSpace(A, B, C, D)

        sys2 = tf2ss(ss2tf(sys1))

        As, Z = schur(A)
        Bs = Z.T @ B
        Cs = C @ Z
        Ds = D
        # print(Bs)
        sys3 = StateSpace(As, Bs, Cs, Ds)

        Ds[0, 0] = 0.3
        sys4 = StateSpace(As, Bs, Cs, Ds)
        Ds[0, 0] = 0

        Ab = np.zeros((4, 4))
        Ab[:3, :3] = A
        Bb = np.zeros((4, 1))
        Bb[:3, :] = B
        Cb = np.zeros((1, 4))
        Cb[:, :3] = C
        sys5 = StateSpace(Ab, Bb, Cb, D)
        # sys5.A = Ab
        # sys5.B = Bb
        # sys5.C = Cb
        return locals()
 def testTf2ssStaticSiso(self):
     """Regression: tf2ss for SISO static gain"""
     gsiso = tf2ss(tf(23, 46))
     assert 0 == gsiso.nstates
     assert 1 == gsiso.ninputs
     assert 1 == gsiso.noutputs
     np.testing.assert_allclose([[0.5]], gsiso.D)
示例#11
0
 def __init__(self, H, dt):
     sys = control.tf2ss(control.c2d(H, dt))
     self.x = np.zeros((sys.A.shape[0], 1))
     self.A = sys.A
     self.B = sys.B
     self.C = sys.C
     self.D = sys.D
     self.dt = sys.dt
示例#12
0
def LQRControl(plant, Q, R):

    plantStateSpace = control.tf2ss(plant)
    A, B, C, D = control.ssdata(plantStateSpace)
    print(A, B, C, D)
    K, P, E = control.lqr(plantStateSpace, Q, R)
    output = control.ss(A - B * K, B * K, C, D)
    return control.step_response(output, T)
示例#13
0
def sim_setup_phi():
    num = num_phi()
    den = den_lat_dir()
    sys = tf2ss(tf(num, den))
    n_axis = 0
    task = [5, 2, 4]
    t_task = [2, 5, 7, 10, 15]  # start_1, end_1, start_2, end_2, finish
    return sys, n_axis, task, t_task
示例#14
0
def sim_setup_theta():
    num = num_theta()
    den = den_long()
    sys = tf2ss(tf(num, den))
    n_axis = 1
    task = [5, 1, 2]
    t_task = [2, 5, 7, 10, 15]  # start_1, end_1, start_2, end_2, finish
    return sys, n_axis, task, t_task
    def test_tf2ss_robustness(self):
        """Unit test to make sure that tf2ss is working correctly. gh-240"""
        num =  [ [[0], [1]],           [[1],   [0]] ]
        den1 = [ [[1], [1,1]],         [[1,4], [1]] ]
        sys1tf = tf(num, den1)
        sys1ss = tf2ss(sys1tf)

        # slight perturbation
        den2 = [ [[1], [1e-10, 1, 1]], [[1,4], [1]] ]
        sys2tf = tf(num, den2)
        sys2ss = tf2ss(sys2tf)

        # Make sure that the poles match for StateSpace and TransferFunction
        np.testing.assert_array_almost_equal(np.sort(sys1tf.pole()),
                                             np.sort(sys1ss.pole()))
        np.testing.assert_array_almost_equal(np.sort(sys2tf.pole()),
                                             np.sort(sys2ss.pole()))
示例#16
0
 def testTf2ssStaticSiso(self):
     """Regression: tf2ss for SISO static gain"""
     import control
     gsiso = control.tf2ss(control.tf(23, 46))
     self.assertEqual(0, gsiso.states)
     self.assertEqual(1, gsiso.inputs)
     self.assertEqual(1, gsiso.outputs)
     # in all cases ratios are exactly representable, so assert_array_equal is fine
     np.testing.assert_array_equal([[0.5]], gsiso.D)
示例#17
0
 def myfunc3(variant: int):
     s = TransferFunction.s
     tf = (1 + 0.5 * s) / (s**3 + 3 * s**2 + 2 * s + 17)
     sysx = tf2ss(tf)
     A = str(sysx.A.tolist())
     B = str(sysx.B.tolist())
     C = str(sysx.C.tolist())
     D = str(sysx.D.tolist())
     return locals()
示例#18
0
 def testTf2ssStaticSiso(self):
     """Regression: tf2ss for SISO static gain"""
     import control
     gsiso = control.tf2ss(control.tf(23, 46))
     self.assertEqual(0, gsiso.states)
     self.assertEqual(1, gsiso.inputs)
     self.assertEqual(1, gsiso.outputs)
     # in all cases ratios are exactly representable, so assert_array_equal is fine
     np.testing.assert_array_equal([[0.5]], gsiso.D)
def SensorModel(bw, delay=(0, 1)):
    # Inputs: ['meas', 'dist']
    # Outputs: ['sens']

    sysNom = control.tf2ss(control.tf(1, [1 / bw, 1]))

    delayPade = control.pade(delay[0], n=delay[1])
    sysDelay = control.tf2ss(control.tf(delayPade[0], delayPade[1]))

    sysDist = control.tf2ss(control.tf(1, 1))

    sys = control.append(sysDelay * sysNom, sysDist)
    sys.C = sys.C[0, :] + sys.C[1, :]
    sys.D = sys.D[0, :] + sys.D[1, :]

    sys.outputs = 1

    return sys
示例#20
0
 def testTf2ssStaticSiso(self):
     """Regression: tf2ss for SISO static gain"""
     gsiso = tf2ss(tf(23, 46))
     assert 0 == gsiso.nstates
     assert 1 == gsiso.ninputs
     assert 1 == gsiso.noutputs
     # in all cases ratios are exactly representable, so assert_array_equal
     # is fine
     np.testing.assert_array_equal([[0.5]], gsiso.D)
示例#21
0
    def output(self, act):
        g = control.tf([0.05, 0], [-0.6, 1])
        print(g)

        sys = control.tf2ss(g)
        print(sys)

        time_interval = np.linspace(0, 1, 100)

        return control.forced_response(sys, time_interval, act)
示例#22
0
def PID2(Kp=1, Ki=0.0, Kd=0, b=1, c=1, Tf=0, dt=None):
    # Inputs: ['ref', 'sens']
    # Outputs: ['cmd']

    sysR = control.tf2ss(
        control.tf([Kp * b * Tf + Kd * c, Kp * b + Ki * Tf, Ki], [Tf, 1, 0]))
    sysY = control.tf2ss(
        control.tf([Kp * Tf + Kd, Kp + Ki * Tf, Ki], [Tf, 1, 0]))

    sys = control.append(sysR, sysY)

    sys.C = sys.C[0, :] - sys.C[1, :]
    sys.D = sys.D[0, :] - sys.D[1, :]

    sys.outputs = 1

    if dt is not None:
        sys = control.c2d(sys, dt)

    return sys
示例#23
0
    def test_issiso_mimo(self):
        # MIMO transfer function
        sys = tf([[[-1, 41], [1]], [[1, 2], [3, 4]]],
                 [[[1, 10], [1, 20]], [[1, 30], [1, 40]]])
        assert not issiso(sys)
        assert not issiso(sys, strict=True)

        # MIMO state space system
        sys = tf2ss(sys)
        assert not issiso(sys)
        assert not issiso(sys, strict=True)
示例#24
0
 def testTf2ssStaticMimo(self):
     """Regression: tf2ss for MIMO static gain"""
     import control
     # 2x3 TFM
     gmimo = control.tf2ss(control.tf([[ [23],   [3],  [5] ], [ [-1],  [0.125],  [101.3] ]],
                                      [[ [46], [0.1], [80] ], [  [2],   [-0.1],      [1] ]]))
     self.assertEqual(0, gmimo.states)
     self.assertEqual(3, gmimo.inputs)
     self.assertEqual(2, gmimo.outputs)
     d = np.matrix([[0.5, 30, 0.0625], [-0.5, -1.25, 101.3]])
     np.testing.assert_array_equal(d, gmimo.D)
示例#25
0
    def _construct_rotor_speed_filter(self):
        cutoff_frequency = 5  # cut-off frequency
        low_pass_transfer_function = ct.tf([0, cutoff_frequency],
                                           [1, cutoff_frequency])
        low_pass_state_space = ct.tf2ss(low_pass_transfer_function)
        low_pass_state_space_discrete = ct.c2d(low_pass_state_space,
                                               self._sampling_time, 'tustin')

        beta_num = 0.0195  # notch parameter
        beta_den = 0.125  # notch parameter
        notch_frequency = 2 * np.pi * 0.62
        notch_transfer_function = ct.tf(
            [1, 2 * beta_num * notch_frequency, notch_frequency**2],
            [1, 2 * beta_den * notch_frequency, notch_frequency**2])
        notch_state_space = ct.tf2ss(notch_transfer_function)
        notch_state_space_discrete = ct.c2d(notch_state_space,
                                            self._sampling_time, 'tustin')

        combined_filter_transfer_function = low_pass_state_space_discrete * notch_state_space_discrete
        return combined_filter_transfer_function
 def testTf2ssStaticMimo(self):
     """Regression: tf2ss for MIMO static gain"""
     # 2x3 TFM
     gmimo = tf2ss(tf(
             [[ [23],   [3],  [5] ], [ [-1],  [0.125],  [101.3] ]],
             [[ [46], [0.1], [80] ], [  [2],   [-0.1],      [1] ]]))
     assert 0 == gmimo.nstates
     assert 3 == gmimo.ninputs
     assert 2 == gmimo.noutputs
     d = np.array([[0.5, 30, 0.0625], [-0.5, -1.25, 101.3]])
     np.testing.assert_allclose(d, gmimo.D)
示例#27
0
def pid_design(G,
               K_guess,
               d_tc,
               verbose=False,
               use_P=True,
               use_I=True,
               use_D=True):
    # type: (control.tf, np.array, float, bool, bool, bool, bool) -> (np.array, control.tf, control.tf)
    """
    :param G: transfer function
    :param K_guess: gain matrix guess
    :param d_tc: time constant for derivative
    :param verbose: show debug output
    :param use_P: use p gain in design
    :param use_I: use i gain in design
    :param use_D: use d gain in design
    :return: (K, G_comp, Gc_comp)
        K: gain matrix
        G_comp: open loop compensated plant
        Gc_comp: closed loop compensated plant
    """
    # compensator transfer function
    H = []
    if use_P:
        H += [control.tf(1, 1)]
    if use_I:
        H += [control.tf((1), (1, 0))]
    if use_D:
        H += [control.tf((1, 0), (d_tc, 1))]
    H = np.array([H]).T
    H_num = [[H[i][j].num[0][0] for i in range(H.shape[0])]
             for j in range(H.shape[1])]
    H_den = [[H[i][j].den[0][0] for i in range(H.shape[0])]
             for j in range(H.shape[1])]
    H = control.tf(H_num, H_den)

    # print('G', G)
    # print('H', H)

    ss_open = control.tf2ss(G * H)

    if verbose:
        print('optimizing controller')
    K = lqr_ofb_design(K_guess, ss_open, verbose)
    if verbose:
        print('done')

    # print('K', K)
    # print('H', H)
    G_comp = control.series(G, H * K)
    Gc_comp = control.feedback(G_comp, 1)

    return K, G_comp, Gc_comp
def PID2Exc(Kp=1, Ki=0, Kd=0, b=1, c=1, Tf=0, dt=None):
    # Inputs: ['ref', 'sens', 'exc']
    # Outputs: ['cmd', 'ff', 'fb', 'exc']

    sysR = control.tf2ss(
        control.tf([Kp * b * Tf + Kd * c, Kp * b + Ki * Tf, Ki], [Tf, 1, 0]))
    sysY = control.tf2ss(
        control.tf([Kp * Tf + Kd, Kp + Ki * Tf, Ki], [Tf, 1, 0]))
    sysX = control.tf2ss(control.tf(1, 1))  # Excitation Input

    sys = control.append(sysR, sysY, sysX)

    sys.C = np.concatenate((sys.C[0, :] - sys.C[1, :] + sys.C[2, :], sys.C))
    sys.D = np.concatenate((sys.D[0, :] - sys.D[1, :] + sys.D[2, :], sys.D))

    sys.outputs = 4

    if dt is not None:
        sys = control.c2d(sys, dt)

    return sys
示例#29
0
    def test_tf2ss_robustness(self):
        """Unit test to make sure that tf2ss is working correctly.
         Source: https://github.com/python-control/python-control/issues/240
        """
        import control
        
        num =  [ [[0], [1]],           [[1],   [0]] ]
        den1 = [ [[1], [1,1]],         [[1,4], [1]] ]
        sys1tf = control.tf(num, den1)
        sys1ss = control.tf2ss(sys1tf)

        # slight perturbation
        den2 = [ [[1], [1e-10, 1, 1]], [[1,4], [1]] ]
        sys2tf = control.tf(num, den2)
        sys2ss = control.tf2ss(sys2tf)

        # Make sure that the poles match for StateSpace and TransferFunction
        np.testing.assert_array_almost_equal(np.sort(sys1tf.pole()),
                                             np.sort(sys1ss.pole()))
        np.testing.assert_array_almost_equal(np.sort(sys2tf.pole()),
                                             np.sort(sys2ss.pole()))
示例#30
0
def get_T(tf_list, N=200, T=None):
    """ Get Time vector """
    if T is None:
        t_max = 0
        for tf in tf_list:
            ss = ctl.tf2ss(tf)
            T_temp = _default_response_times(ss.A, N)
            t_max_temp = T_temp[-1]
            if t_max_temp > t_max:
                t_max = t_max_temp
                T = T_temp
    return T
示例#31
0
    def test_tf2ss_robustness(self):
        """Unit test to make sure that tf2ss is working correctly.
         Source: https://github.com/python-control/python-control/issues/240
        """
        import control

        num = [[[0], [1]], [[1], [0]]]
        den1 = [[[1], [1, 1]], [[1, 4], [1]]]
        sys1tf = control.tf(num, den1)
        sys1ss = control.tf2ss(sys1tf)

        # slight perturbation
        den2 = [[[1], [1e-10, 1, 1]], [[1, 4], [1]]]
        sys2tf = control.tf(num, den2)
        sys2ss = control.tf2ss(sys2tf)

        # Make sure that the poles match for StateSpace and TransferFunction
        np.testing.assert_array_almost_equal(np.sort(sys1tf.pole()),
                                             np.sort(sys1ss.pole()))
        np.testing.assert_array_almost_equal(np.sort(sys2tf.pole()),
                                             np.sort(sys2ss.pole()))
示例#32
0
 def testTf2ssStaticMimo(self):
     """Regression: tf2ss for MIMO static gain"""
     import control
     # 2x3 TFM
     gmimo = control.tf2ss(
         control.tf([[[23], [3], [5]], [[-1], [0.125], [101.3]]],
                    [[[46], [0.1], [80]], [[2], [-0.1], [1]]]))
     self.assertEqual(0, gmimo.states)
     self.assertEqual(3, gmimo.inputs)
     self.assertEqual(2, gmimo.outputs)
     d = np.matrix([[0.5, 30, 0.0625], [-0.5, -1.25, 101.3]])
     np.testing.assert_array_equal(d, gmimo.D)
def get_PI_controller(delta_seconds):
    '''
    Effects: create a discrete state-space PI controller
    '''
    num_pi = [KP, KI] # numerator of the PI transfer function (KP*s + KI)
    den_pi = [1.0, 0.01*KI/KP] # denominator of PI transfer function (s + 0.01*KI/KP)

    sys = control.tf(num_pi,den_pi) # get transfer function for PI controller (since the denominator has a small term 0.01*KI/KP, it is actually a lag-compensator)
    sys = control.sample_system(sys, delta_seconds) # discretize the transfer function (from s-domain which is continuous to z-domain)
                                                        #since our simulation is discrete
    sys = control.tf2ss(sys) # transform transfer function into state space.
    return sys
示例#34
0
def pid_design(G, K_guess, d_tc, verbose=False, use_P=True, use_I=True, use_D=True):
    """
    :param G: transfer function
    :param K_guess: gain matrix guess
    :param d_tc: time constant for derivative
    :param use_P: use p gain in design
    :param use_I: use i gain in design
    :param use_D: use d gain in design

    :return: (K, G_comp, Gc_comp)
        K: gain matrix
        G_comp: open loop compensated plant
        Gc_comp: closed loop compensated plant
    """
    # compensator transfer function
    H = []
    if use_P:
        H += [control.tf(1, 1)]
    if use_I:
        H += [control.tf((1), (1, 0))]
    if use_D:
        H += [control.tf((1, 0), (d_tc, 1))]
    H = np.array([H]).T
    H_num = [[H[i][j].num[0][0] for i in range(H.shape[0])] for j in range(H.shape[1])]
    H_den = [[H[i][j].den[0][0] for i in range(H.shape[0])] for j in range(H.shape[1])]
    H = control.tf(H_num, H_den)

    # print('G', G)
    # print('H', H)

    ss_open = control.tf2ss(G*H)

    if verbose:
        print('optimizing controller')
    K = lqr_ofb_design(K_guess, ss_open, verbose)
    if verbose:
        print('done')

    # print('K', K)
    # print('H', H)
    G_comp = control.series(G, H*K)
    Gc_comp = control.feedback(G_comp, 1)

    return K, G_comp, Gc_comp
# doubleint.py - double integrator example
# RMM, 10 Nov 2012
#
# This example shows how to compute a trajectory for a very simple double
# integrator system.  Mainly useful to show the simplest type of trajectory
# generation computation.

import numpy as np
import matplotlib.pyplot as plt
import control as ctrl                 # control system toolbox
import control.trajgen as tg           # trajectory generation toolbox

# Define a double integrator system
sys1 = ctrl.tf2ss(ctrl.tf([1], [1, 0, 0]))
sysf = tg.LinearFlatSystem(sys1)

# Set the initial and final conditions
x0 = (0, 0);
xf = (1, 3);

# Find a trajectory
systraj = tg.point_to_point(sysf, x0, xf, 1)

# Plot the trajectory
t = np.linspace(0, 1, 100)
xd, ud = systraj.eval(t)

plt.figure(1); plt.clf()
plt.plot(t, xd[:,0], 'b-', t, xd[:,1], 'g-', t, ud[:,0], 'r--')
plt.legend(('x1', 'x2', 'u'))
plt.show()