|
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