From 88219780e6ad325b1f283837cd42f09af28a1515 Mon Sep 17 00:00:00 2001 From: UbeenII Date: Sat, 16 May 2026 22:13:59 +0100 Subject: [PATCH 1/6] 2 fixes. 1st fix: the m_nr branch which is meant to handle negative reals takes the -1 root and uses the p_nr case causes t_emp to become infinite due to ln|p|=0 causing a division by zero and a RuntimeWarning. FIX exclude |p|=1 so they use the m_w case which uses cycle counting formula which is appropriate for unit circle poles. 2nd fix: The m_int case used p.real -1 sqrt_eps) p_nr, p = p[m_nr], p[~m_nr] if p_nr.size > 0: t_emp = np.max(log_decay_percent / np.abs((np.log(p_nr)/dt).real)) tfinal = max(tfinal, t_emp) # discrete integrators + m_int = (p.real - 1 < sqrt_eps) & (np.abs(p.imag) < sqrt_eps) p_int, p = p[m_int], p[~m_int] # pure oscillatory modes From 287ce1a1afb0cd0d84ff81927207cc5c426cd183 Mon Sep 17 00:00:00 2001 From: UbeenII Date: Sun, 7 Jun 2026 15:33:16 +0100 Subject: [PATCH 2/6] Restore original continuous test target value to fix accidental edit --- control/tests/timeresp_test.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/control/tests/timeresp_test.py b/control/tests/timeresp_test.py index f7a66be77..b9a015ea1 100644 --- a/control/tests/timeresp_test.py +++ b/control/tests/timeresp_test.py @@ -820,7 +820,7 @@ def test_step_robustness(self): @pytest.mark.parametrize( "tfsys, tfinal", - [(TransferFunction(1, [1, .5]), 25), # pole at 0.5 + [(TransferFunction(1, [1, .5]), 13.81551), # pole at 0.5 (TransferFunction(1, [1, .5]).sample(.1), 25), # discrete pole at 0.5 (TransferFunction(1, [1, .5, 0]), 25)]) # poles at 0.5 and 0 def test_auto_generated_time_vector_tfinal(self, tfsys, tfinal): From a1d6f4e1f6d1c1c27c5e9bf67a0a6bf70d28998c Mon Sep 17 00:00:00 2001 From: UbeenII Date: Tue, 9 Jun 2026 09:18:32 +0100 Subject: [PATCH 3/6] Update control/tests/timeresp_test.py Co-authored-by: Scott C. Livingston --- control/tests/timeresp_test.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/control/tests/timeresp_test.py b/control/tests/timeresp_test.py index b9a015ea1..63442e437 100644 --- a/control/tests/timeresp_test.py +++ b/control/tests/timeresp_test.py @@ -832,7 +832,7 @@ def test_auto_generated_time_vector_tfinal(self, tfsys, tfinal): def test_discrete_time_negative_one_settling(self): #system with -1 pole - TF = TransferFunction([1,3,0],[1,3,2], dt =True) + TF = TransferFunction([1,3,0],[1,3,2], dt=True) with warnings.catch_warnings(): warnings.simplefilter("error") impulse_response(TF) From 005eebf43c919b8619a67230054d0943661b4622 Mon Sep 17 00:00:00 2001 From: UbeenII Date: Tue, 9 Jun 2026 09:18:45 +0100 Subject: [PATCH 4/6] Update control/timeresp.py Co-authored-by: Scott C. Livingston --- control/timeresp.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/control/timeresp.py b/control/timeresp.py index 24f085bd5..1d55646c0 100644 --- a/control/timeresp.py +++ b/control/timeresp.py @@ -2172,7 +2172,7 @@ def _ideal_tfinal_and_dt(sys, is_step=True): m_z = np.abs(p) < sqrt_eps p = p[~m_z] # Negative reals- treated as oscillatory mode - m_nr = (p.real < 0) & (np.abs(p.imag) < sqrt_eps) & (np.abs(p.real+1)>sqrt_eps) + m_nr = (p.real < 0) & (np.abs(p.imag) < sqrt_eps) & (np.abs(p.real+1) > sqrt_eps) p_nr, p = p[m_nr], p[~m_nr] if p_nr.size > 0: t_emp = np.max(log_decay_percent / np.abs((np.log(p_nr)/dt).real)) From 0d0309114460b81c9c1740f6d9cce24462ca5189 Mon Sep 17 00:00:00 2001 From: UbeenII Date: Tue, 9 Jun 2026 09:24:26 +0100 Subject: [PATCH 5/6] Clean up imports in timeresp_test.py adjusted formatting --- control/tests/timeresp_test.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/control/tests/timeresp_test.py b/control/tests/timeresp_test.py index 63442e437..e00fdb970 100644 --- a/control/tests/timeresp_test.py +++ b/control/tests/timeresp_test.py @@ -2,11 +2,11 @@ from copy import copy from math import isclose +import warnings import numpy as np import pytest - import control as ct from control import StateSpace, TransferFunction, c2d, isctime, ss2tf, tf2ss from control.exception import pandas_check @@ -14,7 +14,7 @@ forced_response, impulse_response, initial_response, step_info, \ step_response -import warnings + class TSys: From b0f9e9eae21e95b787507017a90ba0fa1c1d1064 Mon Sep 17 00:00:00 2001 From: UbeenII Date: Tue, 9 Jun 2026 09:26:25 +0100 Subject: [PATCH 6/6] Removed blank line --- control/timeresp.py | 1 - 1 file changed, 1 deletion(-) diff --git a/control/timeresp.py b/control/timeresp.py index 1d55646c0..1d252b270 100644 --- a/control/timeresp.py +++ b/control/timeresp.py @@ -2178,7 +2178,6 @@ def _ideal_tfinal_and_dt(sys, is_step=True): t_emp = np.max(log_decay_percent / np.abs((np.log(p_nr)/dt).real)) tfinal = max(tfinal, t_emp) # discrete integrators - m_int = (p.real - 1 < sqrt_eps) & (np.abs(p.imag) < sqrt_eps) p_int, p = p[m_int], p[~m_int] # pure oscillatory modes