StateSpace.zero() now supports MIMO systems · python-control/python-control@f66315d

@@ -54,8 +54,7 @@

5454

import math

5555

import numpy as np

5656

from numpy import all, angle, any, array, asarray, concatenate, cos, delete, \

57-

dot, empty, exp, eye, matrix, ones, poly, poly1d, roots, shape, sin, \

58-

zeros, squeeze

57+

dot, empty, exp, eye, isinf, matrix, ones, pad, shape, sin, zeros, squeeze

5958

from numpy.random import rand, randn

6059

from numpy.linalg import solve, eigvals, matrix_rank

6160

from numpy.linalg.linalg import LinAlgError

@@ -516,17 +515,29 @@ def pole(self):

516515

def zero(self):

517516

"""Compute the zeros of a state space system."""

518517519-

if self.inputs > 1 or self.outputs > 1:

520-

raise NotImplementedError("StateSpace.zeros is currently \

521-

implemented only for SISO systems.")

518+

if self.A.shape[0] != self.A.shape[1]:

519+

raise NotImplementedError("StateSpace.zero only supports systems "

520+

"with square A matrices.")

521+522+

# This implements the QZ algorithm for finding transmission zeros from

523+

# https://dspace.mit.edu/bitstream/handle/1721.1/841/P-0802-06587335.pdf.

524+

# The QZ algorithm solves the generalized eigenvalue problem: given

525+

# `L = [A, B; C, D]` and `M = [I_nxn 0]`, find all finite λ for which

526+

# there exist nontrivial solutions of the equation `Lz - λMz`.

527+

#

528+

# The generalized eigenvalue problem is only solvable if its arguments

529+

# are square matrices.

530+

L = concatenate((concatenate((self.A, self.B), axis=1),

531+

concatenate((self.C, self.D), axis=1)), axis=0)

532+

M = pad(eye(self.A.shape[0]), ((0, self.C.shape[0]),

533+

(0, self.B.shape[1])), "constant")

522534523-

den = poly1d(poly(self.A))

524-

# Compute the numerator based on zeros

525-

#! TODO: This is currently limited to SISO systems

526-

num = poly1d(poly(self.A - dot(self.B, self.C)) + ((self.D[0, 0] - 1) *

527-

den))

528-529-

return roots(num)

535+

if self.states:

536+

return np.array([x for x in sp.linalg.eigvals(L, M,

537+

overwrite_a=True)

538+

if not isinf(x)])

539+

else:

540+

return np.array([])

530541531542

# Feedback around a state space system

532543

def feedback(self, other=1, sign=-1):