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
Prev Previous commit
Next Next commit
Expand unit tests, add info to doc string for parameters and returns,…
… rename is_passive to ispassive for naming convention consistency. Autoformat to pep8.
  • Loading branch information
Mark
Mark committed Jun 14, 2022
commit d6916c661a7799e5998f84f5e2d34368ace528a8
21 changes: 15 additions & 6 deletions control/passivity.py
Original file line number Diff line number Diff line change
Expand Up @@ -10,18 +10,27 @@
except ImportError as e:
cvx = None

lmi_epsilon = 1e-12

def is_passive(sys):
def ispassive(sys):
'''
Indicates if a linear time invariant system is passive
Indicates if a linear time invariant (LTI) system is passive

Constructs a linear matrix inequality and a feasibility optimization
such that if a solution exists, the system is passive.

The source for the algorithm is:
McCourt, Michael J., and Panos J. Antsaklis.
"Demonstrating passivity and dissipativity using computational methods." ISIS 8 (2013).

Parameters
----------
sys: A continuous LTI system
System to be checked.

Returns
-------
bool:
The input system passive.
'''
if cvx is None:
raise ModuleNotFoundError("cvxopt required for passivity module")
Expand All @@ -31,9 +40,9 @@ def is_passive(sys):
C = sys.C
D = sys.D

#account for strictly proper systems
[n,m] = D.shape
D = D + np.nextafter(0,1)*np.eye(n,m)
# account for strictly proper systems
[n, m] = D.shape
D = D + np.nextafter(0, 1)*np.eye(n, m)

def make_LMI_matrix(P):
V = np.vstack((
Expand Down
43 changes: 35 additions & 8 deletions control/tests/passivity_test.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,30 +7,57 @@
from control import ss, passivity
from control.tests.conftest import cvxoptonly


@cvxoptonly
def test_is_passive():
def test_ispassive():
A = numpy.array([[0, 1], [-2, -2]])
B = numpy.array([[0], [1]])
C = numpy.array([[-1, 2]])
D = numpy.array([[1.5]])
sys = ss(A, B, C, D)

# happy path is passive
assert(passivity.is_passive(sys))
assert(passivity.ispassive(sys))

# happy path not passive
D = -D
sys = ss(A, B, C, D)

assert(not passivity.is_passive(sys))
assert(not passivity.ispassive(sys))


@cvxoptonly
def test_ispassive_edge_cases():
A = numpy.array([[0, 1], [-2, -2]])
B = numpy.array([[0], [1]])
C = numpy.array([[-1, 2]])
D = numpy.array([[1.5]])

#edge cases of D=0 boundary condition
B *= 0
C *= 0
D *= 0

# strictly proper
sys = ss(A, B, C, D)
assert(passivity.is_passive(sys))
assert(passivity.ispassive(sys))

# ill conditioned
A = A*1e12
sys = ss(A, B, C, D)
assert(passivity.is_passive(sys))
assert(passivity.ispassive(sys))

# different combinations of zero A,B,C,D are 0
Comment thread
Mark-Yeatman marked this conversation as resolved.
Outdated
B *= 0
C *= 0
assert(passivity.ispassive(sys))

A *= 0
B = numpy.array([[0], [1]])
C = numpy.array([[-1, 2]])
D = numpy.array([[1.5]])
assert(passivity.ispassive(sys))

B *= 0
C *= 0
assert(passivity.ispassive(sys))

A *= 0
assert(passivity.ispassive(sys))