Skip to content
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Next Next commit
BUG: allow empty (no input or output) StateSpace objects
  • Loading branch information
roryyorke committed Jan 2, 2018
commit 77d0ccdeb18caedf7c3c24e67cd2a89316868df0
27 changes: 19 additions & 8 deletions control/statesp.py
Original file line number Diff line number Diff line change
Expand Up @@ -54,7 +54,7 @@
import math
import numpy as np
from numpy import all, angle, any, array, asarray, concatenate, cos, delete, \
dot, empty, exp, eye, matrix, ones, poly, poly1d, roots, shape, sin, \
dot, empty, exp, eye, matrix, ones, pi, poly, poly1d, roots, shape, sin, \

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We should avoid using numpy.pi since this can generate errors when numpy is incorporated as a mock function. See PR 171, commit b881b7. Replace with math.pi.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

unqualified pi no longer used following your aa6e0df anyway. Will remove.

zeros, squeeze
from numpy.random import rand, randn
from numpy.linalg import solve, eigvals, matrix_rank
Expand All @@ -69,6 +69,19 @@

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


def _matrix(a):
"""_matrix(a) -> numpy.matrix
a - passed to numpy.matrix
Wrapper around numpy.matrix; unlike that function, _matrix([]) will be 0x0

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Not clear to my why this is useful? Can you say a bit here (or in a comment in the code)?

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'll expand the commentary; it's just a helper to make it easier to get 0x0 matrices, which are needed for empty state space systems.

"""
from numpy import matrix
am = matrix(a)
if (1,0) == am.shape:
am.shape = (0,0)
return am


class StateSpace(LTI):
"""StateSpace(A, B, C, D[, dt])

Expand Down Expand Up @@ -130,7 +143,7 @@ def __init__(self, *args):
else:
raise ValueError("Needs 1 or 4 arguments; received %i." % len(args))

A, B, C, D = map(matrix, [A, B, C, D])
A, B, C, D = [_matrix(M) for M in (A, B, C, D)]

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

# try to treat this as a matrix
try:
X = matrix(other)
X = _matrix(other)
C = X * self.C
D = X * self.D
return StateSpace(self.A, self.B, C, D, self.dt)
Expand Down Expand Up @@ -727,11 +740,9 @@ def _convertToStateSpace(sys, **kw):

# If this is a matrix, try to create a constant feedthrough
try:
D = matrix(sys)
outputs, inputs = D.shape

return StateSpace(0., zeros((1, inputs)), zeros((outputs, 1)), D)
except Exception(e):
D = _matrix(sys)
return StateSpace([], [], [], D)
except Exception as e:
print("Failure to assume argument is matrix-like in" \
" _convertToStateSpace, result %s" % e)

Expand Down
22 changes: 22 additions & 0 deletions control/tests/statesp_test.py
Original file line number Diff line number Diff line change
Expand Up @@ -350,6 +350,28 @@ def test_minrealStaticGain(self):
np.testing.assert_array_equal(g1.D, g2.D)


def test_Empty(self):
"""Regression: can we create an empty StateSpace object?"""
g1=StateSpace([],[],[],[])
self.assertEqual(0,g1.states)
self.assertEqual(0,g1.inputs)
self.assertEqual(0,g1.outputs)


def test_MatrixToStateSpace(self):
"""_convertToStateSpace(matrix) gives ss([],[],[],D)"""
D = np.matrix([[1,2,3],[4,5,6]])
g = _convertToStateSpace(D)
def empty(shape):
m = np.matrix([])
m.shape = shape
return m
np.testing.assert_array_equal(empty((0,0)), g.A)
np.testing.assert_array_equal(empty((0,D.shape[1])), g.B)
np.testing.assert_array_equal(empty((D.shape[0],0)), g.C)
np.testing.assert_array_equal(D,g.D)


class TestRss(unittest.TestCase):
"""These are tests for the proper functionality of statesp.rss."""

Expand Down