Skip to content

Commit 4bad487

Browse files
committed
fix computation of default response time for constant systems
1 parent 874d52e commit 4bad487

2 files changed

Lines changed: 59 additions & 15 deletions

File tree

‎control/tests/timeresp_test.py‎

Lines changed: 13 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -94,9 +94,21 @@ def test_step_response(self):
9494
np.testing.assert_array_equal(Tc.shape, Td.shape)
9595
np.testing.assert_array_equal(youtc.shape, youtd.shape)
9696

97+
# Recreate issue #374 ("Bug in step_response()")
98+
def test_step_nostates(self):
99+
# Continuous time, constant system
100+
sys = TransferFunction([1], [1])
101+
t, y = step_response(sys)
102+
np.testing.assert_array_equal(y, np.ones(len(t)))
103+
104+
# Discrete time, constant system
105+
sys = TransferFunction([1], [1], 1)
106+
t, y = step_response(sys)
107+
np.testing.assert_array_equal(y, np.ones(len(t)))
108+
97109
def test_step_info(self):
98110
# From matlab docs:
99-
sys = TransferFunction([1,5,5],[1,1.65,5,6.5,2])
111+
sys = TransferFunction([1, 5, 5], [1, 1.65, 5, 6.5, 2])
100112
Strue = {
101113
'RiseTime': 3.8456,
102114
'SettlingTime': 27.9762,

‎control/timeresp.py‎

Lines changed: 46 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -513,12 +513,19 @@ def step_response(sys, T=None, X0=0., input=None, output=None,
513513
sys = _get_ss_simo(sys, input, output)
514514
if T is None:
515515
if isctime(sys):
516-
T = _default_response_times(sys.A, 100)
516+
if sys.A.shape == (0, 0):
517+
# No dynamics; use the unit time interval
518+
T = np.linspace(0, 1, 100, endpoint=False)
519+
else:
520+
T = _default_response_times(sys.A, 100)
517521
else:
518522
# For discrete time, use integers
519-
tvec = _default_response_times(sys.A, 100)
520-
T = range(int(np.ceil(max(tvec))))
521-
523+
if sys.A.shape == (0, 0):
524+
# No dynamics; use 100 time steps
525+
T = range(100)
526+
else:
527+
tvec = _default_response_times(sys.A, 100)
528+
T = range(int(np.ceil(max(tvec))))
522529
U = np.ones_like(T)
523530

524531
T, yout, xout = forced_response(sys, T, U, X0, transpose=transpose,
@@ -574,11 +581,21 @@ def step_info(sys, T=None, SettlingTimeThreshold=0.02,
574581
sys = _get_ss_simo(sys)
575582
if T is None:
576583
if isctime(sys):
577-
T = _default_response_times(sys.A, 1000)
584+
if sys.A.shape == (0, 0):
585+
# No dynamics; use the unit time interval
586+
T = np.linspace(0, 1, 100, endpoint=False)
587+
else:
588+
# Use 1000 time points for accuracy
589+
T = _default_response_times(sys.A, 1000)
578590
else:
579591
# For discrete time, use integers
580-
tvec = _default_response_times(sys.A, 1000)
581-
T = range(int(np.ceil(max(tvec))))
592+
if sys.A.shape == (0, 0):
593+
# No dynamics; use 100 time steps
594+
T = range(100)
595+
else:
596+
# Use 1000 time points for accuracy
597+
tvec = _default_response_times(sys.A, 1000)
598+
T = range(int(np.ceil(max(tvec))))
582599

583600
T, yout = step_response(sys, T)
584601

@@ -698,11 +715,19 @@ def initial_response(sys, T=None, X0=0., input=0, output=None,
698715
# The initial vector X0 is created in forced_response(...) if necessary
699716
if T is None:
700717
if isctime(sys):
701-
T = _default_response_times(sys.A, 1000)
718+
if sys.A.shape == (0, 0):
719+
# No dynamics; use the unit time interval
720+
T = np.linspace(0, 1, 100, endpoint=False)
721+
else:
722+
T = _default_response_times(sys.A, 100)
702723
else:
703724
# For discrete time, use integers
704-
tvec = _default_response_times(sys.A, 1000)
705-
T = range(int(np.ceil(max(tvec))))
725+
if sys.A.shape == (0, 0):
726+
# No dynamics; use 100 time steps
727+
T = range(100)
728+
else:
729+
tvec = _default_response_times(sys.A, 100)
730+
T = range(int(np.ceil(max(tvec))))
706731
U = np.zeros_like(T)
707732

708733
T, yout, _xout = forced_response(sys, T, U, X0, transpose=transpose,
@@ -802,12 +827,19 @@ def impulse_response(sys, T=None, X0=0., input=0, output=None,
802827
# Compute T and U, no checks necessary, they will be checked in lsim
803828
if T is None:
804829
if isctime(sys):
805-
T = _default_response_times(sys.A, 100)
830+
if sys.A.shape == (0, 0):
831+
# No dynamics; use the unit time interval
832+
T = np.linspace(0, 1, 100, endpoint=False)
833+
else:
834+
T = _default_response_times(sys.A, 100)
806835
else:
807836
# For discrete time, use integers
808-
tvec = _default_response_times(sys.A, 100)
809-
T = range(int(np.ceil(max(tvec))))
810-
837+
if sys.A.shape == (0, 0):
838+
# No dynamics; use 100 time steps
839+
T = range(100)
840+
else:
841+
tvec = _default_response_times(sys.A, 100)
842+
T = range(int(np.ceil(max(tvec))))
811843
U = np.zeros_like(T)
812844

813845
# Compute new X0 that contains the impulse

0 commit comments

Comments
 (0)