Skip to content

This system broke step_info function test #598

Closed
@juanodecc

Description

@juanodecc

The SettlingMin or SettlingMax or/and Peak values calculus depend on span time selección when the system is asymptotic system:

step_info test broke with this test (In this case Fail SettingMax):

@pytest.fixture
    def siso_tf_peak1(self):
        # Peak_value = Undershoot = y_final(y(t=inf))
        # step info time values depend on time vector discretization
        # use T=linspace(0,50,10000)
        T = TSys(TransferFunction([-1, 1],[1, 1]))
        T.step_info = {
            'RiseTime': 2.2002,
            'SettlingTime': 4.6104, 
            'SettlingMin': 0.9004, 
            'SettlingMax': 0.9999, 
            'Overshoot': 0, 
            'Undershoot': 100.0, 
            'Peak': 1.0, 
            'PeakTime': 0.0, 
            'SteadyStateValue': 1.0}
        return T

the problem is with SettlingMax using T by deafault


========================================================================== FAILURES ===========================================================================
__________________________________________________ TestTimeresp.test_step_info[siso_tf_peak1-ltisys-yfinal] ___________________________________________________

self = <control.tests.timeresp_test.TestTimeresp object at 0x7f443b7aebb0>, tsystem = TransferFunction(array([-1,  1]), array([1, 1])), systype = 'ltisys'
time_2d = False, yfinal = True

    @pytest.mark.parametrize(
        "yfinal", [True, False], ids=["yfinal", "no yfinal"])
    @pytest.mark.parametrize(
        "systype, time_2d",
        [("ltisys", False),
         ("time response", False),
         ("time response", True),
         ],
        ids=["ltisys", "time response (n,)", "time response (1,n)"])
    @pytest.mark.parametrize(
        "tsystem",
        ["siso_tf_step_matlab",
         "siso_ss_step_matlab",
         "siso_tf_kpos",
         "siso_tf_kneg",
         "siso_tf_type1",
         "siso_tf_peak1"],
        indirect=["tsystem"])
    def test_step_info(self, tsystem, systype, time_2d, yfinal):
        """Test step info for SISO systems."""
        step_info_kwargs = tsystem.kwargs.get('step_info', {})
        if systype == "time response":
            # simulate long enough for steady state value
            tfinal = 3 * tsystem.step_info['SettlingTime']
            if np.isnan(tfinal):
                pytest.skip("test system does not settle")
            t, y = step_response(tsystem.sys, T=tfinal, T_num=5000)
            sysdata = y
            step_info_kwargs['T'] = t[np.newaxis, :] if time_2d else t
        else:
            sysdata = tsystem.sys
        if yfinal:
            step_info_kwargs['yfinal'] = tsystem.step_info['SteadyStateValue']
    
        info = step_info(sysdata, **step_info_kwargs)
    
>       self.assert_step_info_match(tsystem.sys, info, tsystem.step_info)

control/tests/timeresp_test.py:509: 
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _

self = <control.tests.timeresp_test.TestTimeresp object at 0x7f443b7aebb0>, sys = TransferFunction(array([-1,  1]), array([1, 1]))
info = {'Overshoot': 0, 'Peak': 1.0, 'PeakTime': 0.0, 'RiseTime': 2.1630344812974367, ...}
info_ref = {'Overshoot': 0, 'Peak': 1.0, 'PeakTime': 0.0, 'RiseTime': 2.2002, ...}

    def assert_step_info_match(self, sys, info, info_ref):
        """Assert reasonable step_info accuracy."""
        if sys.isdtime(strict=True):
            dt = sys.dt
        else:
            _, dt = _ideal_tfinal_and_dt(sys, is_step=True)
    
        for k in ['RiseTime', 'SettlingTime', 'PeakTime']:
            np.testing.assert_allclose(info[k], info_ref[k], atol=dt,
                                       err_msg=f"{k} does not match")
        for k in ['Overshoot', 'Undershoot', 'Peak', 'SteadyStateValue']:
            np.testing.assert_allclose(info[k], info_ref[k], rtol=5e-3,
                                       err_msg=f"{k} does not match")
    
        # steep gradient right after RiseTime
        absrefinf = np.abs(info_ref['SteadyStateValue'])
        if info_ref['RiseTime'] > 0:
            y_next_sample_max = 0.8*absrefinf/info_ref['RiseTime']*dt
        else:
            y_next_sample_max = 0
        for k in ['SettlingMin', 'SettlingMax']:
            if (np.abs(info_ref[k]) - 0.9 * absrefinf) > y_next_sample_max:
                # local min/max peak well after signal has risen
>               np.testing.assert_allclose(info[k], info_ref[k], rtol=1e-3)
E               AssertionError: 
E               Not equal to tolerance rtol=0.001, atol=0
E               
E               Mismatched elements: 1 / 1 (100%)
E               Max absolute difference: 0.0019
E               Max relative difference: 0.00190019
E                x: array(0.998)
E                y: array(0.9999)

control/tests/timeresp_test.py:471: AssertionError
_________________________________________________ TestTimeresp.test_step_info[siso_tf_peak1-ltisys-no yfinal] _________________________________________________

self = <control.tests.timeresp_test.TestTimeresp object at 0x7f44b0132df0>, tsystem = TransferFunction(array([-1,  1]), array([1, 1])), systype = 'ltisys'
time_2d = False, yfinal = False

    @pytest.mark.parametrize(
        "yfinal", [True, False], ids=["yfinal", "no yfinal"])
    @pytest.mark.parametrize(
        "systype, time_2d",
        [("ltisys", False),
         ("time response", False),
         ("time response", True),
         ],
        ids=["ltisys", "time response (n,)", "time response (1,n)"])
    @pytest.mark.parametrize(
        "tsystem",
        ["siso_tf_step_matlab",
         "siso_ss_step_matlab",
         "siso_tf_kpos",
         "siso_tf_kneg",
         "siso_tf_type1",
         "siso_tf_peak1"],
        indirect=["tsystem"])
    def test_step_info(self, tsystem, systype, time_2d, yfinal):
        """Test step info for SISO systems."""
        step_info_kwargs = tsystem.kwargs.get('step_info', {})
        if systype == "time response":
            # simulate long enough for steady state value
            tfinal = 3 * tsystem.step_info['SettlingTime']
            if np.isnan(tfinal):
                pytest.skip("test system does not settle")
            t, y = step_response(tsystem.sys, T=tfinal, T_num=5000)
            sysdata = y
            step_info_kwargs['T'] = t[np.newaxis, :] if time_2d else t
        else:
            sysdata = tsystem.sys
        if yfinal:
            step_info_kwargs['yfinal'] = tsystem.step_info['SteadyStateValue']
    
        info = step_info(sysdata, **step_info_kwargs)
    
>       self.assert_step_info_match(tsystem.sys, info, tsystem.step_info)

control/tests/timeresp_test.py:509: 
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _

self = <control.tests.timeresp_test.TestTimeresp object at 0x7f44b0132df0>, sys = TransferFunction(array([-1,  1]), array([1, 1]))
info = {'Overshoot': 0, 'Peak': 1.0, 'PeakTime': 0.0, 'RiseTime': 2.1630344812974367, ...}
info_ref = {'Overshoot': 0, 'Peak': 1.0, 'PeakTime': 0.0, 'RiseTime': 2.2002, ...}

    def assert_step_info_match(self, sys, info, info_ref):
        """Assert reasonable step_info accuracy."""
        if sys.isdtime(strict=True):
            dt = sys.dt
        else:
            _, dt = _ideal_tfinal_and_dt(sys, is_step=True)
    
        for k in ['RiseTime', 'SettlingTime', 'PeakTime']:
            np.testing.assert_allclose(info[k], info_ref[k], atol=dt,
                                       err_msg=f"{k} does not match")
        for k in ['Overshoot', 'Undershoot', 'Peak', 'SteadyStateValue']:
            np.testing.assert_allclose(info[k], info_ref[k], rtol=5e-3,
                                       err_msg=f"{k} does not match")
    
        # steep gradient right after RiseTime
        absrefinf = np.abs(info_ref['SteadyStateValue'])
        if info_ref['RiseTime'] > 0:
            y_next_sample_max = 0.8*absrefinf/info_ref['RiseTime']*dt
        else:
            y_next_sample_max = 0
        for k in ['SettlingMin', 'SettlingMax']:
            if (np.abs(info_ref[k]) - 0.9 * absrefinf) > y_next_sample_max:
                # local min/max peak well after signal has risen
>               np.testing.assert_allclose(info[k], info_ref[k], rtol=1e-3)
E               AssertionError: 
E               Not equal to tolerance rtol=0.001, atol=0
E               
E               Mismatched elements: 1 / 1 (100%)
E               Max absolute difference: 0.0019
E               Max relative difference: 0.00190019
E                x: array(0.998)
E                y: array(0.9999)

control/tests/timeresp_test.py:471: AssertionError
====================================================================== warnings summary =======================================================================
control/tests/rlocus_test.py:79
  /home/jpp/github_repos/my_python_control/python-control/control/tests/rlocus_test.py:79: PytestUnknownMarkWarning: Unknown pytest.mark.timeout - is this a typo?  You can register custom marks to avoid this warning - for details, see https://docs.pytest.org/en/stable/mark.html
    @pytest.mark.timeout(2)

-- Docs: https://docs.pytest.org/en/stable/warnings.html
=================================================================== short test summary info ===================================================================
SKIPPED [1] control/tests/matlab2_test.py:204: skipping test_check_convert_shape, need to update test
SKIPPED [1] control/tests/matlab2_test.py:275: need to update test
SKIPPED [4] control/tests/timeresp_test.py:498: test system does not settle
SKIPPED [6] control/tests/timeresp_test.py:880: No continuous forced_response without time vector.
SKIPPED [1] control/tests/type_conversion_test.py:162: future test; conversions not yet fully implemented
SKIPPED [2] control/tests/xferfcn_test.py:742: .__matmul__ not implemented
XFAIL control/tests/lti_test.py::TestLTI::test_timebaseEqual_deprecated[None-True-True]
  returns false
XFAIL control/tests/optimal_test.py::test_discrete_lqr
  reason: discrete LQR not implemented
XFAIL control/tests/statefbk_test.py::TestStatefbk::testLQR_warning
  warning not implemented
FAILED control/tests/timeresp_test.py::TestTimeresp::test_step_info[siso_tf_peak1-ltisys-yfinal] - AssertionError: 
FAILED control/tests/timeresp_test.py::TestTimeresp::test_step_info[siso_tf_peak1-ltisys-no yfinal] - AssertionError: 
========================================= 2 failed, 2483 passed, 15 skipped, 3 xfailed, 1 warning in 93.49s (0:01:33) =========================================
(control-dev) jpp@jpp-linux:~/github_repos/my_python_control/python-control$ /home/jpp/miniconda3/envs/control-dev/bin/python /home/jpp/github_repos/my_python_control/python-control/examples/step_info_example2.py

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions