Ejemplo n.º 1
0
    def test_timebaseEqual_deprecated(self, dt1, dt2, expected):
        """Test that timbaseEqual throws a warning and returns as documented"""
        sys1 = tf([1], [1, 2, 3], dt1)
        sys2 = tf([1], [1, 4, 5], dt2)

        print(sys1.dt)
        print(sys2.dt)

        with pytest.deprecated_call():
            assert timebaseEqual(sys1, sys2) is expected
        # Make sure behaviour is symmetric
        with pytest.deprecated_call():
            assert timebaseEqual(sys2, sys1) is expected
Ejemplo n.º 2
0
 def testTimebaseEqual(self):
     self.assertEqual(timebaseEqual(self.siso_ss1, self.siso_tf1), True)
     self.assertEqual(timebaseEqual(self.siso_ss1, self.siso_ss1c), True)
     self.assertEqual(timebaseEqual(self.siso_ss1, self.siso_ss1d), True)
     self.assertEqual(timebaseEqual(self.siso_ss1d, self.siso_ss1c), False)
     self.assertEqual(timebaseEqual(self.siso_ss1d, self.siso_ss2d), False)
     self.assertEqual(timebaseEqual(self.siso_ss1d, self.siso_ss3d), False)
Ejemplo n.º 3
0
 def testTimebaseEqual(self):
     self.assertEqual(timebaseEqual(self.siso_ss1, self.siso_tf1), True)
     self.assertEqual(timebaseEqual(self.siso_ss1, self.siso_ss1c), True)
     self.assertEqual(timebaseEqual(self.siso_ss1, self.siso_ss1d), True)
     self.assertEqual(timebaseEqual(self.siso_ss1d, self.siso_ss1c), False)
     self.assertEqual(timebaseEqual(self.siso_ss1d, self.siso_ss2d), False)
     self.assertEqual(timebaseEqual(self.siso_ss1d, self.siso_ss3d), False)
Ejemplo n.º 4
0
    def feedback(self, other=1, sign=-1):
        """Feedback interconnection between two LTI systems."""
 
        other = _convertToStateSpace(other)

        # Check to make sure the dimensions are OK
        if ((self.inputs != other.outputs) or (self.outputs != other.inputs)):
                raise ValueError("State space systems don't have compatible \
inputs/outputs for feedback.")

        # Figure out the sampling time to use
        if (self.dt == None and other.dt != None):
            dt = other.dt       # use dt from second argument
        elif (other.dt == None and self.dt != None) or \
                timebaseEqual(self, other):
            dt = self.dt        # use dt from first argument
        else:
            raise ValueError("Systems have different sampling times")

        A1 = self.A
        B1 = self.B
        C1 = self.C
        D1 = self.D
        A2 = other.A
        B2 = other.B
        C2 = other.C
        D2 = other.D
        
        F = eye(self.inputs) - sign * D2 * D1
        if abs(det(F)) < 1.e-6:
            raise ValueError("I - sign * D2 * D1 is singular.")

        E = inv(F)
        T1 = eye(self.outputs) + sign * D1 * E * D2
        T2 = eye(self.inputs) + sign * E * D2 * D1

        A = concatenate(
            (concatenate(
                (A1 + sign * B1 * E * D2 * C1, sign * B1 * E * C2), axis=1),
            concatenate(
                (B2 * T1 * C1, A2 + sign * B2 * D1 * E * C2), axis=1)),
            axis=0)
        B = concatenate((B1 * T2, B2 * D1 * T2), axis=0)
        C = concatenate((T1 * C1, sign * D1 * E * C2), axis=1)
        D = D1 * T2

        return StateSpace(A, B, C, D, dt)
Ejemplo n.º 5
0
    def feedback(self, other=1, sign=-1):
        """Feedback interconnection between two LTI systems."""

        other = _convertToStateSpace(other)

        # Check to make sure the dimensions are OK
        if ((self.inputs != other.outputs) or (self.outputs != other.inputs)):
            raise ValueError("State space systems don't have compatible \
inputs/outputs for feedback.")

        # Figure out the sampling time to use
        if (self.dt == None and other.dt != None):
            dt = other.dt  # use dt from second argument
        elif (other.dt == None and self.dt != None) or \
                timebaseEqual(self, other):
            dt = self.dt  # use dt from first argument
        else:
            raise ValueError("Systems have different sampling times")

        A1 = self.A
        B1 = self.B
        C1 = self.C
        D1 = self.D
        A2 = other.A
        B2 = other.B
        C2 = other.C
        D2 = other.D

        F = eye(self.inputs) - sign * D2 * D1
        if abs(det(F)) < 1.e-6:
            raise ValueError("I - sign * D2 * D1 is singular.")

        E = inv(F)
        T1 = eye(self.outputs) + sign * D1 * E * D2
        T2 = eye(self.inputs) + sign * E * D2 * D1

        A = concatenate(
            (concatenate(
                (A1 + sign * B1 * E * D2 * C1, sign * B1 * E * C2), axis=1),
             concatenate(
                 (B2 * T1 * C1, A2 + sign * B2 * D1 * E * C2), axis=1)),
            axis=0)
        B = concatenate((B1 * T2, B2 * D1 * T2), axis=0)
        C = concatenate((T1 * C1, sign * D1 * E * C2), axis=1)
        D = D1 * T2

        return StateSpace(A, B, C, D, dt)
Ejemplo n.º 6
0
    def __add__(self, other):
        """Add two LTI objects (parallel connection)."""
        from control.statesp import StateSpace

        # Convert the second argument to a transfer function.
        if (isinstance(other, StateSpace)):
            other = _convertToTransferFunction(other)
        elif not isinstance(other, TransferFunction):
            other = _convertToTransferFunction(other,
                                               inputs=self.inputs,
                                               outputs=self.outputs)

        # Check that the input-output sizes are consistent.
        if self.inputs != other.inputs:
            raise ValueError("The first summand has %i input(s), but the \
second has %i." % (self.inputs, other.inputs))
        if self.outputs != other.outputs:
            raise ValueError("The first summand has %i output(s), but the \
second has %i." % (self.outputs, other.outputs))

        # Figure out the sampling time to use
        if (self.dt == None and other.dt != None):
            dt = other.dt  # use dt from second argument
        elif (other.dt == None and self.dt != None) or \
                (timebaseEqual(self, other)):
            dt = self.dt  # use dt from first argument
        else:
            raise ValueError("Systems have different sampling times")

        # Preallocate the numerator and denominator of the sum.
        num = [[[] for j in range(self.inputs)] for i in range(self.outputs)]
        den = [[[] for j in range(self.inputs)] for i in range(self.outputs)]

        for i in range(self.outputs):
            for j in range(self.inputs):
                num[i][j], den[i][j] = _addSISO(self.num[i][j], self.den[i][j],
                                                other.num[i][j],
                                                other.den[i][j])

        return TransferFunction(num, den, dt)
Ejemplo n.º 7
0
    def __add__(self, other):
        """Add two LTI systems (parallel connection)."""

        # Check for a couple of special cases
        if (isinstance(other, (int, float, complex))):
            # Just adding a scalar; put it in the D matrix
            A, B, C = self.A, self.B, self.C
            D = self.D + other
            dt = self.dt
        else:
            other = _convertToStateSpace(other)

            # Check to make sure the dimensions are OK
            if ((self.inputs != other.inputs)
                    or (self.outputs != other.outputs)):
                raise ValueError("Systems have different shapes.")

            # Figure out the sampling time to use
            if (self.dt == None and other.dt != None):
                dt = other.dt  # use dt from second argument
            elif (other.dt == None and self.dt != None) or \
                    (timebaseEqual(self, other)):
                dt = self.dt  # use dt from first argument
            else:
                raise ValueError("Systems have different sampling times")

            # Concatenate the various arrays
            A = concatenate(
                (concatenate(
                    (self.A, zeros((self.A.shape[0], other.A.shape[-1]))),
                    axis=1),
                 concatenate((zeros(
                     (other.A.shape[0], self.A.shape[-1])), other.A),
                             axis=1)),
                axis=0)
            B = concatenate((self.B, other.B), axis=0)
            C = concatenate((self.C, other.C), axis=1)
            D = self.D + other.D

        return StateSpace(A, B, C, D, dt)
Ejemplo n.º 8
0
    def __add__(self, other):
        """Add two LTI objects (parallel connection)."""
        from control.statesp import StateSpace
        
        # Convert the second argument to a transfer function.
        if (isinstance(other, StateSpace)):
            other = _convertToTransferFunction(other)
        elif not isinstance(other, TransferFunction):
            other = _convertToTransferFunction(other, inputs=self.inputs, 
                outputs=self.outputs)

        # Check that the input-output sizes are consistent.
        if self.inputs != other.inputs:
            raise ValueError("The first summand has %i input(s), but the \
second has %i." % (self.inputs, other.inputs))
        if self.outputs != other.outputs:
            raise ValueError("The first summand has %i output(s), but the \
second has %i." % (self.outputs, other.outputs))

        # Figure out the sampling time to use
        if (self.dt == None and other.dt != None):
            dt = other.dt       # use dt from second argument
        elif (other.dt == None and self.dt != None) or \
                (timebaseEqual(self, other)):
            dt = self.dt        # use dt from first argument
        else:
            raise ValueError("Systems have different sampling times")

        # Preallocate the numerator and denominator of the sum.
        num = [[[] for j in range(self.inputs)] for i in range(self.outputs)]
        den = [[[] for j in range(self.inputs)] for i in range(self.outputs)]

        for i in range(self.outputs):
            for j in range(self.inputs):
                num[i][j], den[i][j] = _addSISO(self.num[i][j], self.den[i][j],
                    other.num[i][j], other.den[i][j])

        return TransferFunction(num, den, dt)
Ejemplo n.º 9
0
    def __add__(self, other):
        """Add two LTI systems (parallel connection)."""
        
        # Check for a couple of special cases
        if (isinstance(other, (int, float, complex))):
            # Just adding a scalar; put it in the D matrix
            A, B, C = self.A, self.B, self.C;
            D = self.D + other;
            dt = self.dt
        else:
            other = _convertToStateSpace(other)

            # Check to make sure the dimensions are OK
            if ((self.inputs != other.inputs) or 
                    (self.outputs != other.outputs)):
                raise ValueError("Systems have different shapes.")

            # Figure out the sampling time to use
            if (self.dt == None and other.dt != None):
                dt = other.dt       # use dt from second argument
            elif (other.dt == None and self.dt != None) or \
                    (timebaseEqual(self, other)):
                dt = self.dt        # use dt from first argument
            else:
                raise ValueError("Systems have different sampling times")

            # Concatenate the various arrays
            A = concatenate((
                concatenate((self.A, zeros((self.A.shape[0],
                                           other.A.shape[-1]))),axis=1),
                concatenate((zeros((other.A.shape[0], self.A.shape[-1])),
                                other.A),axis=1)
                            ),axis=0)
            B = concatenate((self.B, other.B), axis=0)
            C = concatenate((self.C, other.C), axis=1)
            D = self.D + other.D

        return StateSpace(A, B, C, D, dt)
Ejemplo n.º 10
0
    def __mul__(self, other):
        """Multiply two LTI objects (serial connection)."""

        # Check for a couple of special cases
        if isinstance(other, (int, float, complex)):
            # Just multiplying by a scalar; change the output
            A, B = self.A, self.B
            C = self.C * other
            D = self.D * other
            dt = self.dt
        else:
            other = _convertToStateSpace(other)

            # Check to make sure the dimensions are OK
            if self.inputs != other.outputs:
                raise ValueError("C = A * B: A has %i column(s) (input(s)), \
but B has %i row(s)\n(output(s))." % (self.inputs, other.outputs))

            # Figure out the sampling time to use
            if (self.dt == None and other.dt != None):
                dt = other.dt  # use dt from second argument
            elif (other.dt == None and self.dt != None) or \
                    (timebaseEqual(self, other)):
                dt = self.dt  # use dt from first argument
            else:
                raise ValueError("Systems have different sampling times")

            # Concatenate the various arrays
            A = concatenate(
                (concatenate(
                    (other.A, zeros((other.A.shape[0], self.A.shape[1]))),
                    axis=1), concatenate((self.B * other.C, self.A), axis=1)),
                axis=0)
            B = concatenate((other.B, self.B * other.D), axis=0)
            C = concatenate((self.D * other.C, self.C), axis=1)
            D = self.D * other.D

        return StateSpace(A, B, C, D, dt)
Ejemplo n.º 11
0
    def __mul__(self, other):
        """Multiply two LTI objects (serial connection)."""
        
        # Check for a couple of special cases
        if isinstance(other, (int, float, complex)):
            # Just multiplying by a scalar; change the output
            A, B = self.A, self.B
            C = self.C * other
            D = self.D * other
            dt = self.dt
        else:
            other = _convertToStateSpace(other)

            # Check to make sure the dimensions are OK
            if self.inputs != other.outputs:
                raise ValueError("C = A * B: A has %i column(s) (input(s)), \
but B has %i row(s)\n(output(s))." % (self.inputs, other.outputs))

            # Figure out the sampling time to use
            if (self.dt == None and other.dt != None):
                dt = other.dt       # use dt from second argument
            elif (other.dt == None and self.dt != None) or \
                    (timebaseEqual(self, other)):
                dt = self.dt        # use dt from first argument
            else:
                raise ValueError("Systems have different sampling times")

            # Concatenate the various arrays
            A = concatenate(
                (concatenate((other.A, zeros((other.A.shape[0], self.A.shape[1]))), 
                 axis=1),
                concatenate((self.B * other.C, self.A), axis=1)), axis=0)
            B = concatenate((other.B, self.B * other.D), axis=0)
            C = concatenate((self.D * other.C, self.C),axis=1)
            D = self.D * other.D

        return StateSpace(A, B, C, D, dt)