Support NumPy 2 by bnavigator · Pull Request #994 · python-control/python-control

Fixes error

[   58s] ==================================== ERRORS ====================================
[   58s] ___ ERROR at setup of TestTimeresp.test_step_response_siso[siso_ss1-kwargs0] ___
[   58s] [gw0] linux -- Python 3.10.14 /usr/bin/python3.10
[   58s] 
[   58s] self = <control.tests.timeresp_test.TestTimeresp object at 0x7fed247aa830>
[   58s] request = <SubRequest 'tsystem' for <Function test_step_response_siso[siso_ss1-kwargs0]>>
[   58s] 
[   58s]     @pytest.fixture
[   58s]     def tsystem(self, request):
[   58s]         """Define some test systems"""
[   58s]     
[   58s]         """continuous"""
[   58s]         A = np.array([[1., -2.], [3., -4.]])
[   58s]         B = np.array([[5.], [7.]])
[   58s]         C = np.array([[6., 8.]])
[   58s]         D = np.array([[9.]])
[   58s]         siso_ss1 = TSys(StateSpace(A, B, C, D, 0))
[   58s]         siso_ss1.t = np.linspace(0, 1, 10)
[   58s]         siso_ss1.ystep = np.array([9., 17.6457, 24.7072, 30.4855, 35.2234,
[   58s]                                    39.1165, 42.3227, 44.9694, 47.1599,
[   58s]                                    48.9776])
[   58s]         siso_ss1.X0 = np.array([[.5], [1.]])
[   58s]         siso_ss1.yinitial = np.array([11., 8.1494, 5.9361, 4.2258, 2.9118,
[   58s]                                       1.9092, 1.1508, 0.5833, 0.1645, -0.1391])
[   58s]         ss1 = siso_ss1.sys
[   58s]     
[   58s]         """D=0, continuous"""
[   58s]         siso_ss2 = TSys(StateSpace(ss1.A, ss1.B, ss1.C, 0, 0))
[   58s]         siso_ss2.t = siso_ss1.t
[   58s]         siso_ss2.ystep = siso_ss1.ystep - 9
[   58s]         siso_ss2.initial = siso_ss1.yinitial - 9
[   58s]         siso_ss2.yimpulse = np.array([86., 70.1808, 57.3753, 46.9975, 38.5766,
[   58s]                                       31.7344, 26.1668, 21.6292, 17.9245,
[   58s]                                       14.8945])
[   58s]     
[   58s]         """System with unspecified timebase"""
[   58s]         siso_ss2_dtnone = TSys(StateSpace(ss1.A, ss1.B, ss1.C, 0, None))
[   58s]         siso_ss2_dtnone.t = np.arange(0, 10, 1.)
[   58s]         siso_ss2_dtnone.ystep = np.array([0., 86., -72., 230., -360.,  806.,
[   58s]                                           -1512.,  3110., -6120., 12326.])
[   58s]     
[   58s]         siso_tf1 = TSys(TransferFunction([1], [1, 2, 1], 0))
[   58s]     
[   58s]         siso_tf2 = copy(siso_ss1)
[   58s]         siso_tf2.sys = ss2tf(siso_ss1.sys)
[   58s]     
[   58s]         """MIMO system, contains ``siso_ss1`` twice"""
[   58s]         mimo_ss1 = copy(siso_ss1)
[   58s]         A = np.zeros((4, 4))
[   58s]         A[:2, :2] = siso_ss1.sys.A
[   58s]         A[2:, 2:] = siso_ss1.sys.A
[   58s]         B = np.zeros((4, 2))
[   58s]         B[:2, :1] = siso_ss1.sys.B
[   58s]         B[2:, 1:] = siso_ss1.sys.B
[   58s]         C = np.zeros((2, 4))
[   58s]         C[:1, :2] = siso_ss1.sys.C
[   58s]         C[1:, 2:] = siso_ss1.sys.C
[   58s]         D = np.zeros((2, 2))
[   58s]         D[:1, :1] = siso_ss1.sys.D
[   58s]         D[1:, 1:] = siso_ss1.sys.D
[   58s]         mimo_ss1.sys = StateSpace(A, B, C, D)
[   58s]     
[   58s]         """MIMO system, contains ``siso_ss2`` twice"""
[   58s]         mimo_ss2 = copy(siso_ss2)
[   58s]         A = np.zeros((4, 4))
[   58s]         A[:2, :2] = siso_ss2.sys.A
[   58s]         A[2:, 2:] = siso_ss2.sys.A
[   58s]         B = np.zeros((4, 2))
[   58s]         B[:2, :1] = siso_ss2.sys.B
[   58s]         B[2:, 1:] = siso_ss2.sys.B
[   58s]         C = np.zeros((2, 4))
[   58s]         C[:1, :2] = siso_ss2.sys.C
[   58s]         C[1:, 2:] = siso_ss2.sys.C
[   58s]         D = np.zeros((2, 2))
[   58s]         mimo_ss2.sys = StateSpace(A, B, C, D, 0)
[   58s]     
[   58s]         """discrete"""
[   58s]         siso_dtf0 = TSys(TransferFunction([1.], [1., 0.], 1.))
[   58s]         siso_dtf0.t = np.arange(4)
[   58s]         siso_dtf0.yimpulse = [0., 1., 0., 0.]
[   58s]     
[   58s]         siso_dtf1 =  TSys(TransferFunction([1], [1, 1, 0.25], True))
[   58s]         siso_dtf1.t = np.arange(0, 5, 1)
[   58s]         siso_dtf1.ystep = np.array([0.  , 0.  , 1.  , 0.  , 0.75])
[   58s]     
[   58s]         siso_dtf2 = TSys(TransferFunction([1], [1, 1, 0.25], 0.2))
[   58s]         siso_dtf2.t = np.arange(0, 5, 0.2)
[   58s]         siso_dtf2.ystep = np.array(
[   58s]             [0.    , 0.    , 1.    , 0.    , 0.75  , 0.25  ,
[   58s]              0.5625, 0.375 , 0.4844, 0.4219, 0.457 , 0.4375,
[   58s]              0.4482, 0.4424, 0.4456, 0.4438, 0.4448, 0.4443,
[   58s]              0.4445, 0.4444, 0.4445, 0.4444, 0.4445, 0.4444,
[   58s]              0.4444])
[   58s]     
[   58s]         """Time step which leads to rounding errors for time vector length"""
[   58s]         num = [-0.10966442, 0.12431949]
[   58s]         den = [1., -1.86789511, 0.88255018]
[   58s]         dt = 0.12493963338370018
[   58s]         siso_dtf3 = TSys(TransferFunction(num, den, dt))
[   58s]         siso_dtf3.t = np.linspace(0, 9*dt, 10)
[   58s]         siso_dtf3.ystep = np.array(
[   58s]             [ 0.    , -0.1097, -0.1902, -0.2438, -0.2729,
[   58s]              -0.2799, -0.2674, -0.2377, -0.1934, -0.1368])
[   58s]     
[   58s]         """dtf1 converted statically, because Slycot and Scipy produce
[   58s]         different realizations, wich means different initial condtions,"""
[   58s]         siso_dss1 = copy(siso_dtf1)
[   58s]         siso_dss1.sys = StateSpace([[-1., -0.25],
[   58s]                                     [ 1.,  0.]],
[   58s]                                    [[1.],
[   58s]                                     [0.]],
[   58s]                                    [[0., 1.]],
[   58s]                                    [[0.]],
[   58s]                                    True)
[   58s]         siso_dss1.X0 = [0.5, 1.]
[   58s]         siso_dss1.yinitial = np.array([1., 0.5, -0.75, 0.625, -0.4375])
[   58s]     
[   58s]         siso_dss2 = copy(siso_dtf2)
[   58s]         siso_dss2.sys = tf2ss(siso_dtf2.sys)
[   58s]     
[   58s]         mimo_dss1 = TSys(StateSpace(ss1.A, ss1.B, ss1.C, ss1.D, True))
[   58s]         mimo_dss1.t = np.arange(0, 5, 0.2)
[   58s]     
[   58s]         mimo_dss2 = copy(mimo_ss1)
[   58s]         mimo_dss2.sys = c2d(mimo_ss1.sys, mimo_ss1.t[1]-mimo_ss1.t[0])
[   58s]     
[   58s]         mimo_tf2 = copy(mimo_ss2)
[   58s]         tf_ = ss2tf(siso_ss2.sys)
[   58s]         mimo_tf2.sys = TransferFunction(
[   58s]             [[tf_.num[0][0], [0]], [[0], tf_.num[0][0]]],
[   58s]             [[tf_.den[0][0], [1]], [[1], tf_.den[0][0]]],
[   58s]             0)
[   58s]     
[   58s]         mimo_dtf1 = copy(siso_dtf1)
[   58s]         tf_ = siso_dtf1.sys
[   58s]         mimo_dtf1.sys = TransferFunction(
[   58s]             [[tf_.num[0][0], [0]], [[0], tf_.num[0][0]]],
[   58s]             [[tf_.den[0][0], [1]], [[1], tf_.den[0][0]]],
[   58s]             True)
[   58s]     
[   58s]         # for pole cancellation tests
[   58s]         pole_cancellation = TSys(TransferFunction(
[   58s]             [1.067e+05, 5.791e+04],
[   58s]             [10.67, 1.067e+05, 5.791e+04]))
[   58s]     
[   58s]         no_pole_cancellation = TSys(TransferFunction(
[   58s]             [1.881e+06],
[   58s]             [188.1, 1.881e+06]))
[   58s]     
[   58s]         # System Type 1 - Step response not stationary:  G(s)=1/s(s+1)
[   58s]         siso_tf_type1 = TSys(TransferFunction(1, [1, 1, 0]))
[   58s]         siso_tf_type1.step_info = {
[   58s] >            'RiseTime': np.NaN,
[   58s]              'SettlingTime': np.NaN,
[   58s]              'SettlingMin': np.NaN,
[   58s]              'SettlingMax': np.NaN,
[   58s]              'Overshoot': np.NaN,
[   58s]              'Undershoot': np.NaN,
[   58s]              'Peak': np.Inf,
[   58s]              'PeakTime': np.Inf,
[   58s]              'SteadyStateValue': np.NaN}
[   58s] 
[   58s] control/tests/timeresp_test.py:176: 
[   58s] _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 
[   58s] 
[   58s] attr = 'NaN'
[   58s] 
[   58s]     def __getattr__(attr):
[   58s]         # Warn for expired attributes
[   58s]         import warnings
[   58s]     
[   58s]         if attr == "linalg":
[   58s]             import numpy.linalg as linalg
[   58s]             return linalg
[   58s]         elif attr == "fft":
[   58s]             import numpy.fft as fft
[   58s]             return fft
[   58s]         elif attr == "dtypes":
[   58s]             import numpy.dtypes as dtypes
[   58s]             return dtypes
[   58s]         elif attr == "random":
[   58s]             import numpy.random as random
[   58s]             return random
[   58s]         elif attr == "polynomial":
[   58s]             import numpy.polynomial as polynomial
[   58s]             return polynomial
[   58s]         elif attr == "ma":
[   58s]             import numpy.ma as ma
[   58s]             return ma
[   58s]         elif attr == "ctypeslib":
[   58s]             import numpy.ctypeslib as ctypeslib
[   58s]             return ctypeslib
[   58s]         elif attr == "exceptions":
[   58s]             import numpy.exceptions as exceptions
[   58s]             return exceptions
[   58s]         elif attr == "testing":
[   58s]             import numpy.testing as testing
[   58s]             return testing
[   58s]         elif attr == "matlib":
[   58s]             import numpy.matlib as matlib
[   58s]             return matlib
[   58s]         elif attr == "f2py":
[   58s]             import numpy.f2py as f2py
[   58s]             return f2py
[   58s]         elif attr == "typing":
[   58s]             import numpy.typing as typing
[   58s]             return typing
[   58s]         elif attr == "rec":
[   58s]             import numpy.rec as rec
[   58s]             return rec
[   58s]         elif attr == "char":
[   58s]             import numpy.char as char
[   58s]             return char
[   58s]         elif attr == "array_api":
[   58s]             raise AttributeError("`numpy.array_api` is not available from "
[   58s]                                  "numpy 2.0 onwards")
[   58s]         elif attr == "core":
[   58s]             import numpy.core as core
[   58s]             return core
[   58s]         elif attr == "strings":
[   58s]             import numpy.strings as strings
[   58s]             return strings
[   58s]         elif attr == "distutils":
[   58s]             if 'distutils' in __numpy_submodules__:
[   58s]                 import numpy.distutils as distutils
[   58s]                 return distutils
[   58s]             else:
[   58s]                 raise AttributeError("`numpy.distutils` is not available from "
[   58s]                                      "Python 3.12 onwards")
[   58s]     
[   58s]         if attr in __future_scalars__:
[   58s]             # And future warnings for those that will change, but also give
[   58s]             # the AttributeError
[   58s]             warnings.warn(
[   58s]                 f"In the future `np.{attr}` will be defined as the "
[   58s]                 "corresponding NumPy scalar.", FutureWarning, stacklevel=2)
[   58s]     
[   58s]         if attr in __former_attrs__:
[   58s]             raise AttributeError(__former_attrs__[attr])
[   58s]     
[   58s]         if attr in __expired_attributes__:
[   58s] >           raise AttributeError(
[   58s]                 f"`np.{attr}` was removed in the NumPy 2.0 release. "
[   58s]                 f"{__expired_attributes__[attr]}"
[   58s]             )
[   58s] E           AttributeError: `np.NaN` was removed in the NumPy 2.0 release. Use `np.nan` instead.. Did you mean: 'nan'?
[   58s] 
[   58s] /usr/lib64/python3.10/site-packages/numpy/__init__.py:397: AttributeError