StateSpace.zero() now supports MIMO systems · python-control/python-control@8607fb0
@@ -54,8 +54,7 @@
5454import math
5555import numpy as np
5656from 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
5958from numpy.random import rand, randn
6059from numpy.linalg import solve, eigvals, matrix_rank
6160from numpy.linalg.linalg import LinAlgError
@@ -516,17 +515,22 @@ def pole(self):
516515def 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+# This implements the QZ algorithm for finding transmission zeros from
519+# https://dspace.mit.edu/bitstream/handle/1721.1/841/P-0802-06587335.pdf.
520+# The QZ algorithm solves the generalized eigenvalue problem: given
521+# `L = [A, B; C, D]` and `M = [I_nxn 0]`, find all finite λ for which
522+# there exist nontrivial solutions of the equation `Lz - λMz`.
523+L = concatenate((concatenate((self.A, self.B), axis=1),
524+concatenate((self.C, self.D), axis=1)), axis=0)
525+M = pad(eye(self.A.shape[0]), ((0, self.C.shape[0]),
526+ (0, self.B.shape[1])), "constant")
522527523-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)
528+if self.states:
529+return np.array([x for x in sp.linalg.eigvals(L, M,
530+overwrite_a=True)
531+if not isinf(x)])
532+else:
533+return np.array([])
530534531535# Feedback around a state space system
532536def feedback(self, other=1, sign=-1):