|
9 | 9 |
|
10 | 10 | import operator |
11 | 11 |
|
12 | | -import control as ct |
13 | 12 | import numpy as np |
14 | 13 | import pytest |
| 14 | +from numpy.linalg import solve |
| 15 | +from numpy.testing import assert_array_almost_equal |
| 16 | +from scipy.linalg import block_diag, eigvals |
| 17 | + |
| 18 | +import control as ct |
15 | 19 | from control.config import defaults |
16 | 20 | from control.dtime import sample_system |
17 | 21 | from control.lti import evalfr |
18 | 22 | from control.statesp import (StateSpace, _convert_to_statespace, _rss_generate, |
19 | 23 | _statesp_defaults, drss, linfnorm, rss, ss, tf2ss) |
| 24 | +from control.tests.conftest import (assert_tf_close_coeff, editsdefaults, |
| 25 | + slycotonly) |
20 | 26 | from control.xferfcn import TransferFunction, ss2tf |
21 | | -from numpy.linalg import solve |
22 | | -from numpy.testing import assert_array_almost_equal |
23 | | -from scipy.linalg import block_diag, eigvals |
24 | | - |
25 | | -from .conftest import assert_tf_close_coeff, editsdefaults, slycotonly |
26 | 27 |
|
27 | 28 |
|
28 | 29 | class TestStateSpace: |
@@ -582,25 +583,28 @@ def test_pow(self, request, sysname, power): |
582 | 583 | np.testing.assert_allclose(expected.D, result.D) |
583 | 584 |
|
584 | 585 | @slycotonly |
585 | | - @pytest.mark.parametrize("order", ["inv*sys", "sys*inv"]) |
586 | | - @pytest.mark.parametrize("sysname", ["sys222", "sys322"]) |
| 586 | + @pytest.mark.parametrize("order", ["left", "right"]) |
| 587 | + @pytest.mark.parametrize("sysname", ["sys121", "sys222", "sys322"]) |
587 | 588 | def test_pow_inv(self, request, sysname, order): |
588 | | - """Power of -1 (inverse of biproper system). |
| 589 | + """Check for identity when multiplying by inverse. |
589 | 590 |
|
590 | | - Testing transfer function representations to avoid the |
591 | | - non-uniqueness of the state-space representation. Once MIMO |
592 | | - canonical forms are supported, can check canonical state-space |
593 | | - matrices instead. |
| 591 | + This holds approximately true for a few steps but is very |
| 592 | + unstable due to numerical precision. Don't assume this in |
| 593 | + real life. For testing purposes only! |
594 | 594 | """ |
595 | 595 | sys = request.getfixturevalue(sysname) |
596 | | - if order == "inv*sys": |
597 | | - result = (sys**-1 * sys).minreal() |
| 596 | + if order == "left": |
| 597 | + combined = sys**-1 * sys |
598 | 598 | else: |
599 | | - result = (sys * sys**-1).minreal() |
600 | | - expected = StateSpace([], [], [], np.eye(sys.ninputs), dt=0) |
601 | | - assert_tf_close_coeff( |
602 | | - ss2tf(expected).minreal(), |
603 | | - ss2tf(result).minreal()) |
| 599 | + combined = sys * sys**-1 |
| 600 | + combined = combined.minreal() |
| 601 | + np.testing.assert_allclose(combined.dcgain(), np.eye(sys.ninputs), |
| 602 | + atol=1e-7) |
| 603 | + T = np.linspace(0., 0.3, 100) |
| 604 | + U = np.random.rand(sys.ninputs, len(T)) |
| 605 | + R = combined.forced_response(T=T, U=U, squeeze=False) |
| 606 | + # Check that the output is the same as the input |
| 607 | + np.testing.assert_allclose(R.outputs, U) |
604 | 608 |
|
605 | 609 | @slycotonly |
606 | 610 | def test_truediv(self, sys222, sys322): |
|
0 commit comments