Skip to content

Commit 77d0ccd

Browse files
committed
BUG: allow empty (no input or output) StateSpace objects
1 parent 33bebc1 commit 77d0ccd

2 files changed

Lines changed: 41 additions & 8 deletions

File tree

control/statesp.py

Lines changed: 19 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -54,7 +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, \
57+
dot, empty, exp, eye, matrix, ones, pi, poly, poly1d, roots, shape, sin, \
5858
zeros, squeeze
5959
from numpy.random import rand, randn
6060
from numpy.linalg import solve, eigvals, matrix_rank
@@ -69,6 +69,19 @@
6969

7070
__all__ = ['StateSpace', 'ss', 'rss', 'drss', 'tf2ss', 'ssdata']
7171

72+
73+
def _matrix(a):
74+
"""_matrix(a) -> numpy.matrix
75+
a - passed to numpy.matrix
76+
Wrapper around numpy.matrix; unlike that function, _matrix([]) will be 0x0
77+
"""
78+
from numpy import matrix
79+
am = matrix(a)
80+
if (1,0) == am.shape:
81+
am.shape = (0,0)
82+
return am
83+
84+
7285
class StateSpace(LTI):
7386
"""StateSpace(A, B, C, D[, dt])
7487
@@ -130,7 +143,7 @@ def __init__(self, *args):
130143
else:
131144
raise ValueError("Needs 1 or 4 arguments; received %i." % len(args))
132145

133-
A, B, C, D = map(matrix, [A, B, C, D])
146+
A, B, C, D = [_matrix(M) for M in (A, B, C, D)]
134147

135148
# TODO: use super here?
136149
LTI.__init__(self, inputs=D.shape[1], outputs=D.shape[0], dt=dt)
@@ -336,7 +349,7 @@ def __rmul__(self, other):
336349

337350
# try to treat this as a matrix
338351
try:
339-
X = matrix(other)
352+
X = _matrix(other)
340353
C = X * self.C
341354
D = X * self.D
342355
return StateSpace(self.A, self.B, C, D, self.dt)
@@ -727,11 +740,9 @@ def _convertToStateSpace(sys, **kw):
727740

728741
# If this is a matrix, try to create a constant feedthrough
729742
try:
730-
D = matrix(sys)
731-
outputs, inputs = D.shape
732-
733-
return StateSpace(0., zeros((1, inputs)), zeros((outputs, 1)), D)
734-
except Exception(e):
743+
D = _matrix(sys)
744+
return StateSpace([], [], [], D)
745+
except Exception as e:
735746
print("Failure to assume argument is matrix-like in" \
736747
" _convertToStateSpace, result %s" % e)
737748

control/tests/statesp_test.py

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -350,6 +350,28 @@ def test_minrealStaticGain(self):
350350
np.testing.assert_array_equal(g1.D, g2.D)
351351

352352

353+
def test_Empty(self):
354+
"""Regression: can we create an empty StateSpace object?"""
355+
g1=StateSpace([],[],[],[])
356+
self.assertEqual(0,g1.states)
357+
self.assertEqual(0,g1.inputs)
358+
self.assertEqual(0,g1.outputs)
359+
360+
361+
def test_MatrixToStateSpace(self):
362+
"""_convertToStateSpace(matrix) gives ss([],[],[],D)"""
363+
D = np.matrix([[1,2,3],[4,5,6]])
364+
g = _convertToStateSpace(D)
365+
def empty(shape):
366+
m = np.matrix([])
367+
m.shape = shape
368+
return m
369+
np.testing.assert_array_equal(empty((0,0)), g.A)
370+
np.testing.assert_array_equal(empty((0,D.shape[1])), g.B)
371+
np.testing.assert_array_equal(empty((D.shape[0],0)), g.C)
372+
np.testing.assert_array_equal(D,g.D)
373+
374+
353375
class TestRss(unittest.TestCase):
354376
"""These are tests for the proper functionality of statesp.rss."""
355377

0 commit comments

Comments
 (0)