test_SISO_delay

wield.control.SISO.test.test_SISO_delay

This is a pytest module needing documentation

pytest-html report

Functions

bessel_delay_ZPK(delay_s[, order, rescale])

This is a pytest needing documentation

bode(xfer, axm, axp, *[, deg])

This is a pytest needing documentation

test_SS_delay_print(idx_ord)

Test the conversions to and from ZPK representation and statespace representation using a delay filter

test_ZPK_delay_many()

This is a pytest needing documentation

test_ZPK_delay_math()

Test the conversions to and from ZPK representation and statespace representation using a delay filter

test_ZPK_delay_various(idx_ord)

Test the conversions to and from ZPK representation and statespace representation using a delay filter

test_ZPK_various(zpk)

Test the conversions to and from ZPK representation and statespace representation using a delay filter

Details

bessel_delay_ZPK(delay_s, order=1, rescale=None)[source][github]

This is a pytest needing documentation

code
 1def bessel_delay_ZPK(delay_s, order=1, rescale=None):
 2    # take the poles of this normalized bessel filter (delay=1s)
 3    z, p, k = scipy.signal.besselap(order, norm="delay")
 4
 5    # now rescale for desired delay
 6    roots = p / delay_s * 2
 7    if order % 2 == 0:
 8        k = 1
 9    else:
10        k = -1
11
12    return SISO.zpk(
13        -roots.conjugate(),
14        roots,
15        k
16    )
pytest information

This code is wrapped in a pytest function using conventions detailed in Pytest Conventions. The full name of this test, as known by the documentation, is:

wield.control.SISO.test.test_SISO_delay.bessel_delay_ZPK

The full name is useful when building documentation, to link a reference to this page using :func:`name`, or directly include it with an autofunction directive. The collapse nodes below show every instance of the test run. There may only be one, but if the test was run multiple times through pytest parametrizations, the list can be longer.

bode(xfer, axm, axp, *, deg=True, **kw)[source][github]

This is a pytest needing documentation

code
 1def bode(xfer, axm, axp, *, deg=True, **kw):
 2    if axm is not None:
 3        line, = axm.plot(
 4            xfer.f,
 5            abs(xfer.tf),
 6            **kw
 7        )
 8        kw.setdefault('color', line.get_color())
 9
10    if axp is not None:
11        line, = axp.plot(
12            xfer.f,
13            np.angle(xfer.tf, deg=deg),
14            **kw
15        )
16    return
pytest information

This code is wrapped in a pytest function using conventions detailed in Pytest Conventions. The full name of this test, as known by the documentation, is:

wield.control.SISO.test.test_SISO_delay.bode

The full name is useful when building documentation, to link a reference to this page using :func:`name`, or directly include it with an autofunction directive. The collapse nodes below show every instance of the test run. There may only be one, but if the test was run multiple times through pytest parametrizations, the list can be longer.

test_SS_delay_print(idx_ord)[source][github]

Test the conversions to and from ZPK representation and statespace representation using a delay filter

code
docstring
"""
Test the conversions to and from ZPK representation and statespace representation
using a delay filter
"""
 1@pytest.mark.parametrize('idx_ord', [4, 40, 100])
 2def test_SS_delay_print(idx_ord):
 3
 4    length_m = 3995
 5    delta_t = length_m / c_m_s
 6    delta_t = 1
 7    axB = mplfigB(Nrows=2)
 8    F_Hz = logspaced(0.01 / delta_t, 2 / delta_t, 1000)
 9
10    filt = bessel_delay_ZPK(delta_t, order=idx_ord).asSS
11
12    print()
13    print()
14    filt.print_nonzero()
pytest information

This code is wrapped in a pytest function using conventions detailed in Pytest Conventions. The full name of this test, as known by the documentation, is:

wield.control.SISO.test.test_SISO_delay.test_SS_delay_print

The full name is useful when building documentation, to link a reference to this page using :func:`name`, or directly include it with an autofunction directive. The collapse nodes below show every instance of the test run. There may only be one, but if the test was run multiple times through pytest parametrizations, the list can be longer.

test_SS_delay_print[4]
output
|   ABCD   |       |         
0 | [[212.]  | [[2]  | [[1...] 
1 |  [3...]  |  [.]  |  [.1..] 
2 |  [..21]  |  [2]  |  [..1.] 
3 |  [..3.]] |  [.]] |  [...1]]
  |          |       |         
  | [[1.1.]] | [[1]] |
test_SS_delay_print[100]
output
status: failed
duration: 0.039s
captured errors:
idx_ord = 100

    @pytest.mark.parametrize('idx_ord', [4, 40, 100])
    def test_SS_delay_print(idx_ord):
        """
        Test the conversions to and from ZPK representation and statespace representation
        using a delay filter
        """
        length_m = 3995
        delta_t = length_m / c_m_s
        delta_t = 1
        axB = mplfigB(Nrows=2)
        F_Hz = logspaced(0.01 / delta_t, 2 / delta_t, 1000)

>       filt = bessel_delay_ZPK(delta_t, order=idx_ord).asSS

../../src/wield/control/SISO/test/test_SISO_delay.py:264: 
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 
../../src/wield/control/SISO/test/test_SISO_delay.py:54: in bessel_delay_ZPK
    z, p, k = scipy.signal.besselap(order, norm="delay")
/opt/conda/lib/python3.12/site-packages/scipy/signal/_filter_design.py:4914: in besselap
    p = 1/_bessel_zeros(N)
/opt/conda/lib/python3.12/site-packages/scipy/signal/_filter_design.py:4786: in _bessel_zeros
    x = _aberth(f, fp, x0)
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 

f = <function _bessel_zeros.<locals>.f at 0x7f6877df7240>
fp = <function _bessel_zeros.<locals>.fp at 0x7f6877df6c00>
x0 = array([-0.00058824-0.01j      , -0.00116471-0.01018214j,
       -0.00172941-0.01034076j, -0.00228235-0.01047634j,
    ...38j,
       -0.00228235+0.01047634j, -0.00172941+0.01034076j,
       -0.00116471+0.01018214j, -0.00058824+0.01j      ])
tol = 1e-15, maxiter = 50

    def _aberth(f, fp, x0, tol=1e-15, maxiter=50):
        """
        Given a function `f`, its first derivative `fp`, and a set of initial
        guesses `x0`, simultaneously find the roots of the polynomial using the
        Aberth-Ehrlich method.

        ``len(x0)`` should equal the number of roots of `f`.

        (This is not a complete implementation of Bini's algorithm.)
        """

        N = len(x0)

        x = array(x0, complex)
        beta = np.empty_like(x0)

        for iteration in range(maxiter):
            alpha = -f(x) / fp(x)  # Newton's method

            # Model "repulsion" between zeros
            for k in range(N):
                beta[k] = np.sum(1/(x[k] - x[k+1:]))
                beta[k] += np.sum(1/(x[k] - x[:k]))

            x += alpha / (1 + alpha * beta)

            if not all(np.isfinite(x)):
>               raise RuntimeError('Root-finding calculation failed')
E               RuntimeError: Root-finding calculation failed

/opt/conda/lib/python3.12/site-packages/scipy/signal/_filter_design.py:4751: RuntimeError
test_SS_delay_print[40]
output
|   ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmn   |       |                                             
0  | [[233.3.3.3.3.2.2.2.2.2.2.2.2.2.2.2.2.1.1.]  | [[2]  | [[1.......................................] 
1  |  [3.......................................]  |  [.]  |  [.1......................................] 
2  |  [..333.3.3.3.3.3.3.3.3.2.2.2.2.2.2.2.2.2.]  |  [3]  |  [..1.....................................] 
3  |  [..3.....................................]  |  [.]  |  [...1....................................] 
4  |  [....333.3.3.3.3.3.3.3.2.2.2.2.2.2.2.2.2.]  |  [3]  |  [....1...................................] 
5  |  [....3...................................]  |  [.]  |  [.....1..................................] 
6  |  [......333.3.3.3.3.3.3.2.2.2.2.2.2.2.2.2.]  |  [3]  |  [......1.................................] 
7  |  [......3.................................]  |  [.]  |  [.......1................................] 
8  |  [........333.3.3.3.3.3.2.2.2.2.2.2.2.2.2.]  |  [3]  |  [........1...............................] 
9  |  [........3...............................]  |  [.]  |  [.........1..............................] 
10 |  [..........333.3.3.3.3.3.3.3.3.3.2.2.2.2.]  |  [3]  |  [..........1.............................] 
11 |  [..........3.............................]  |  [.]  |  [...........1............................] 
12 |  [............333.3.3.3.3.3.3.3.3.3.3.2.2.]  |  [3]  |  [............1...........................] 
13 |  [............3...........................]  |  [.]  |  [.............1..........................] 
14 |  [..............333.3.3.3.3.3.3.3.3.3.2.2.]  |  [3]  |  [..............1.........................] 
15 |  [..............3.........................]  |  [.]  |  [...............1........................] 
16 |  [................333.3.3.3.3.3.3.3.3.2.2.]  |  [3]  |  [................1.......................] 
17 |  [................3.......................]  |  [.]  |  [.................1......................] 
18 |  [..................333.3.3.3.3.3.3.3.2.2.]  |  [3]  |  [..................1.....................] 
19 |  [..................3.....................]  |  [.]  |  [...................1....................] 
20 |  [....................333.3.3.3.3.3.3.2.2.]  |  [3]  |  [....................1...................] 
21 |  [....................3...................]  |  [.]  |  [.....................1..................] 
22 |  [......................333.3.3.3.3.3.3.3.]  |  [4]  |  [......................1.................] 
23 |  [......................3.................]  |  [.]  |  [.......................1................] 
24 |  [........................333.3.3.3.3.3.3.]  |  [4]  |  [........................1...............] 
25 |  [........................3...............]  |  [.]  |  [.........................1..............] 
26 |  [..........................333.3.3.3.3.3.]  |  [4]  |  [..........................1.............] 
27 |  [..........................3.............]  |  [.]  |  [...........................1............] 
28 |  [............................333.3.3.3.3.]  |  [4]  |  [............................1...........] 
29 |  [............................3...........]  |  [.]  |  [.............................1..........] 
30 |  [..............................333.3.3.3.]  |  [4]  |  [..............................1.........] 
31 |  [..............................3.........]  |  [.]  |  [...............................1........] 
32 |  [................................333.3.3.]  |  [4]  |  [................................1.......] 
33 |  [................................3.......]  |  [.]  |  [.................................1......] 
34 |  [..................................333.3.]  |  [4]  |  [..................................1.....] 
35 |  [..................................3.....]  |  [.]  |  [...................................1....] 
36 |  [....................................333.]  |  [4]  |  [....................................1...] 
37 |  [....................................3...]  |  [.]  |  [.....................................1..] 
38 |  [......................................33]  |  [4]  |  [......................................1.] 
39 |  [......................................3.]] |  [.]] |  [.......................................1]]
   |                                              |       |                                             
   | [[1.1.1.1.1.1.1.1.1.1.1.1.1.1.1.1.a.a.a.a.]] | [[1]] |
test_ZPK_delay_many()[source][github]

This is a pytest needing documentation

code
 1def test_ZPK_delay_many():
 2    length_m = 3995
 3    delta_t = length_m / c_m_s
 4    delta_t = 1
 5    axB = mplfigB(Nrows=2)
 6    F_Hz = logspaced(0.01 / delta_t, 2 / delta_t, 1000)
 7
 8    for idx_ord in range(1, 7):
 9        filt = bessel_delay_ZPK(delta_t, order=idx_ord)
10
11        xfer = filt.fresponse(f=F_Hz).tf
12        # print("filt.z: ", filt.z, tuple(filt.z))
13        # print("filt.p: ", filt.p, tuple(filt.p))
14        w, zpk0 = scipy.signal.freqs_zpk(
15            tuple(filt.z),
16            tuple(filt.p),
17            filt.k,
18            2 * np.pi * F_Hz
19        )
20
21        # Test that the ZPK is internally using the scipy convention
22        np.testing.assert_almost_equal(xfer, zpk0)
23
24        axB.ax0.semilogx(F_Hz, abs(xfer), label="order {}".format(idx_ord))
25        axB.ax1.plot(F_Hz, np.angle(xfer, deg=True))
26
27    xfer_delay = np.exp(-2j * np.pi * F_Hz * delta_t)
28    axB.ax1.plot(F_Hz, np.angle(xfer_delay, deg=True), color="magenta", ls="--")
29    axB.ax1.axvline(1 / delta_t / 4, ls='--', color='black')
30    axB.ax1.axvline(2 / delta_t / 4, ls='--', color='black')
31    axB.ax1.axvline(3 / delta_t / 4, ls='--', color='black')
32    axB.ax1.axvline(4 / delta_t / 4, ls='--', color='black')
33    axB.ax0.legend()
34    axB.save(tjoin("test_ZPK"))
pytest information

This code is wrapped in a pytest function using conventions detailed in Pytest Conventions. The full name of this test, as known by the documentation, is:

wield.control.SISO.test.test_SISO_delay.test_ZPK_delay_many

The full name is useful when building documentation, to link a reference to this page using :func:`name`, or directly include it with an autofunction directive. The collapse nodes below show every instance of the test run. There may only be one, but if the test was run multiple times through pytest parametrizations, the list can be longer.

test_ZPK_delay_many
output
status: passed
duration: 1.659s
test_ZPK_delay_math()[source][github]

Test the conversions to and from ZPK representation and statespace representation using a delay filter

code
docstring
"""
Test the conversions to and from ZPK representation and statespace representation
using a delay filter
"""
 1def test_ZPK_delay_math():
 2
 3    length_m = 3995
 4    delta_t = length_m / c_m_s
 5    delta_t = 1
 6    axB = mplfigB(Nrows=1)
 7    F_Hz = logspaced(0.01 / delta_t, 2 / delta_t, 1000)
 8
 9    filt = bessel_delay_ZPK(delta_t, order=50)
10
11    fr = filt.fresponse(f=F_Hz)
12    axB.ax0.semilogx(*fr.fplot_mag, label="SS2ZPK")
13    #axB.ax1.semilogx(fr.fplot_deg135, label="SS2ZPK")
14
15    fr2 = (1 / (filt.asSS)).fresponse(f=F_Hz)
16    #
17    fr2 = (1 / (1 - .9 * filt.asSS)).fresponse(f=F_Hz)
18    axB.ax0.semilogx(*fr2.fplot_mag, label="SS2ZPK")
19    #axB.ax1.semilogx(fr2.fplot_deg, label="SS2ZPK")
20
21    axB.ax0.legend()
22    axB.save(tjoin("test_ZPK.pdf"))
pytest information

This code is wrapped in a pytest function using conventions detailed in Pytest Conventions. The full name of this test, as known by the documentation, is:

wield.control.SISO.test.test_SISO_delay.test_ZPK_delay_math

The full name is useful when building documentation, to link a reference to this page using :func:`name`, or directly include it with an autofunction directive. The collapse nodes below show every instance of the test run. There may only be one, but if the test was run multiple times through pytest parametrizations, the list can be longer.

test_ZPK_delay_math
output
status: passed
duration: 1.009s
test_ZPK_delay_various(idx_ord)[source][github]

Test the conversions to and from ZPK representation and statespace representation using a delay filter

code
docstring
"""
Test the conversions to and from ZPK representation and statespace representation
using a delay filter
"""
 1@pytest.mark.parametrize('idx_ord', [4, 40, 100])
 2def test_ZPK_delay_various(idx_ord):
 3
 4    length_m = 3995
 5    delta_t = length_m / c_m_s
 6    delta_t = 1
 7    axB = mplfigB(Nrows=2)
 8    F_Hz = logspaced(0.01 / delta_t, 2 / delta_t, 1000)
 9
10    filt = bessel_delay_ZPK(delta_t, order=idx_ord)
11
12    xfer1 = filt.fresponse(f=F_Hz).tf
13    axB.ax0.semilogx(F_Hz, abs(xfer1), label="Direct ZPK")
14    axB.ax1.plot(F_Hz, np.angle(xfer1, deg=True))
15
16    xfer2 = (filt * filt).fresponse(f=F_Hz).tf
17    axB.ax0.semilogx(F_Hz, abs(xfer2), label="ZPK self product")
18    axB.ax1.plot(F_Hz, np.angle(xfer2, deg=True))
19
20    filt_ss = filt.asSS * 4
21    filt_ssi = 1/filt_ss
22    xfer3 = filt_ss.fresponse(f=F_Hz).tf
23    xfer3b = filt_ssi.fresponse(f=F_Hz).tf
24    axB.ax0.semilogx(F_Hz, abs(xfer3) / 4, label="ZPK2SS")
25    axB.ax1.plot(F_Hz, np.angle(xfer3, deg=True))
26    axB.ax0.semilogx(F_Hz, abs(1/xfer3b) / 4, label="ZPK2SS inv")
27    axB.ax1.plot(F_Hz, np.angle(1/xfer3b, deg=True))
28
29    filt_zpk = filt_ss.asZPK
30    filt_zpki = filt_ssi.asZPK
31    xfer4 = filt_zpk.fresponse(f=F_Hz).tf
32    xfer4b = (1/filt_zpk).fresponse(f=F_Hz).tf
33    xfer4c = (filt_zpki).fresponse(f=F_Hz).tf
34    axB.ax0.semilogx(F_Hz, abs(xfer4) / 4, label="SS2ZPK")
35    axB.ax1.plot(F_Hz, np.angle(xfer3, deg=True))
36    axB.ax0.semilogx(F_Hz, abs(1/xfer4b) / 4, label="SS2ZPK inv")
37    axB.ax1.plot(F_Hz, np.angle(1/xfer4b, deg=True))
38    axB.ax0.semilogx(F_Hz, abs(1/xfer4c) / 4, label="SS2ZPK ss inv")
39    axB.ax1.plot(F_Hz, np.angle(1/xfer4c, deg=True))
40
41    axB.ax0.legend()
42    axB.save(tjoin("test_ZPK"))
43
44    np.testing.assert_almost_equal(xfer2, xfer1**2)
45    np.testing.assert_almost_equal(xfer3, 4 * xfer1)
46    np.testing.assert_almost_equal(xfer4, 4 * xfer1)
47    np.testing.assert_almost_equal(xfer3, 1/xfer3b)
48    np.testing.assert_almost_equal(xfer4, 1/xfer4b)
49    np.testing.assert_almost_equal(xfer4, 1/xfer4c)
pytest information

This code is wrapped in a pytest function using conventions detailed in Pytest Conventions. The full name of this test, as known by the documentation, is:

wield.control.SISO.test.test_SISO_delay.test_ZPK_delay_various

The full name is useful when building documentation, to link a reference to this page using :func:`name`, or directly include it with an autofunction directive. The collapse nodes below show every instance of the test run. There may only be one, but if the test was run multiple times through pytest parametrizations, the list can be longer.

test_ZPK_delay_various[40]
output
status: passed
duration: 1.376s
test_ZPK_delay_various[100]
output
status: failed
duration: 0.041s
captured errors:
idx_ord = 100

    @pytest.mark.parametrize('idx_ord', [4, 40, 100])
    def test_ZPK_delay_various(idx_ord):
        """
        Test the conversions to and from ZPK representation and statespace representation
        using a delay filter
        """
        length_m = 3995
        delta_t = length_m / c_m_s
        delta_t = 1
        axB = mplfigB(Nrows=2)
        F_Hz = logspaced(0.01 / delta_t, 2 / delta_t, 1000)

>       filt = bessel_delay_ZPK(delta_t, order=idx_ord)

../../src/wield/control/SISO/test/test_SISO_delay.py:118: 
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 
../../src/wield/control/SISO/test/test_SISO_delay.py:54: in bessel_delay_ZPK
    z, p, k = scipy.signal.besselap(order, norm="delay")
/opt/conda/lib/python3.12/site-packages/scipy/signal/_filter_design.py:4914: in besselap
    p = 1/_bessel_zeros(N)
/opt/conda/lib/python3.12/site-packages/scipy/signal/_filter_design.py:4786: in _bessel_zeros
    x = _aberth(f, fp, x0)
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 

f = <function _bessel_zeros.<locals>.f at 0x7f68742e1d00>
fp = <function _bessel_zeros.<locals>.fp at 0x7f68742e1da0>
x0 = array([-0.00058824-0.01j      , -0.00116471-0.01018214j,
       -0.00172941-0.01034076j, -0.00228235-0.01047634j,
    ...38j,
       -0.00228235+0.01047634j, -0.00172941+0.01034076j,
       -0.00116471+0.01018214j, -0.00058824+0.01j      ])
tol = 1e-15, maxiter = 50

    def _aberth(f, fp, x0, tol=1e-15, maxiter=50):
        """
        Given a function `f`, its first derivative `fp`, and a set of initial
        guesses `x0`, simultaneously find the roots of the polynomial using the
        Aberth-Ehrlich method.

        ``len(x0)`` should equal the number of roots of `f`.

        (This is not a complete implementation of Bini's algorithm.)
        """

        N = len(x0)

        x = array(x0, complex)
        beta = np.empty_like(x0)

        for iteration in range(maxiter):
            alpha = -f(x) / fp(x)  # Newton's method

            # Model "repulsion" between zeros
            for k in range(N):
                beta[k] = np.sum(1/(x[k] - x[k+1:]))
                beta[k] += np.sum(1/(x[k] - x[:k]))

            x += alpha / (1 + alpha * beta)

            if not all(np.isfinite(x)):
>               raise RuntimeError('Root-finding calculation failed')
E               RuntimeError: Root-finding calculation failed

/opt/conda/lib/python3.12/site-packages/scipy/signal/_filter_design.py:4751: RuntimeError
test_ZPK_delay_various[4]
output
status: passed
duration: 1.029s
test_ZPK_various(zpk)[source][github]

Test the conversions to and from ZPK representation and statespace representation using a delay filter

code
docstring
"""
Test the conversions to and from ZPK representation and statespace representation
using a delay filter
"""
 1@pytest.mark.parametrize('zpk', [
 2    ((0,), (), 0.1),
 3    ((), (0,), 0.1),
 4    ((-1,), (), 0.1),
 5    ((), (-1,), 0.1),
 6    ((0, 0,), (10, 10), 0.1),
 7    ((10, 10), (0, 0), 0.1),
 8    ((-1, -1,), (10, 10), 0.1),
 9    ((10, 10), (-1, -1), 0.1),
10    ((0, ), (10, 10), 0.1),
11    ((10, 10), (0,), 0.1),
12    ((-1, ), (10, 10), 0.1),
13    ((10, 10), (-1, ), 0.1),
14])
15def test_ZPK_various(zpk):
16
17    delta_t = 1
18    axB = mplfigB(Nrows=2)
19    F_Hz = logspaced(0.01 / delta_t, 2 / delta_t, 1000)
20
21    filt = SISO.zpk(zpk, fiducial_rtol=1e-7)
22    print(filt)
23
24    xfer1 = filt.fresponse(f=F_Hz).tf
25    axB.ax0.semilogx(F_Hz, abs(xfer1), label="Direct ZPK")
26    axB.ax1.plot(F_Hz, np.angle(xfer1, deg=True))
27
28    xfer2 = (filt * filt).fresponse(f=F_Hz).tf
29    axB.ax0.semilogx(F_Hz, abs(xfer2), label="ZPK self product")
30    axB.ax1.plot(F_Hz, np.angle(xfer2, deg=True))
31
32    filt_ss = filt.asSS * 4
33    filt_ssi = 1/filt_ss
34    xfer3 = filt_ss.fresponse(f=F_Hz).tf
35    xfer3b = filt_ssi.fresponse(f=F_Hz).tf
36    axB.ax0.semilogx(F_Hz, abs(xfer3) / 4, label="ZPK2SS")
37    axB.ax1.plot(F_Hz, np.angle(xfer3, deg=True))
38    axB.ax0.semilogx(F_Hz, abs(1/xfer3b) / 4, label="ZPK2SS inv")
39    axB.ax1.plot(F_Hz, np.angle(1/xfer3b, deg=True))
40
41    filt_zpk = filt_ss.asZPK
42    filt_zpki = filt_ssi.asZPK
43    xfer4 = filt_zpk.fresponse(f=F_Hz).tf
44    xfer4b = (1/filt_zpk).fresponse(f=F_Hz).tf
45    xfer4c = (filt_zpki).fresponse(f=F_Hz).tf
46    axB.ax0.semilogx(F_Hz, abs(xfer4) / 4, label="SS2ZPK")
47    axB.ax1.plot(F_Hz, np.angle(xfer3, deg=True))
48    axB.ax0.semilogx(F_Hz, abs(1/xfer4b) / 4, label="SS2ZPK inv")
49    axB.ax1.plot(F_Hz, np.angle(1/xfer4b, deg=True))
50    axB.ax0.semilogx(F_Hz, abs(1/xfer4c) / 4, label="SS2ZPK ss inv")
51    axB.ax1.plot(F_Hz, np.angle(1/xfer4c, deg=True))
52
53    axB.ax0.legend()
54    axB.save(tjoin("test_ZPK"))
55
56    np.testing.assert_almost_equal(xfer2, xfer1**2)
57    np.testing.assert_almost_equal(xfer3, 4 * xfer1)
58    np.testing.assert_almost_equal(xfer4, 4 * xfer1)
59    np.testing.assert_almost_equal(xfer3, 1/xfer3b)
60    np.testing.assert_almost_equal(xfer4, 1/xfer4b)
61    np.testing.assert_almost_equal(xfer4, 1/xfer4c)
pytest information

This code is wrapped in a pytest function using conventions detailed in Pytest Conventions. The full name of this test, as known by the documentation, is:

wield.control.SISO.test.test_SISO_delay.test_ZPK_various

The full name is useful when building documentation, to link a reference to this page using :func:`name`, or directly include it with an autofunction directive. The collapse nodes below show every instance of the test run. There may only be one, but if the test was run multiple times through pytest parametrizations, the list can be longer.

test_ZPK_various[zpk9]
output
zpk(z=2π·[ 1.591549430918954,  1.591549430918954], p=2π·[0.0], k=0.1)
captured errors:
zpk = ((10, 10), (0,), 0.1)

    @pytest.mark.parametrize('zpk', [
        ((0,), (), 0.1),
        ((), (0,), 0.1),
        ((-1,), (), 0.1),
        ((), (-1,), 0.1),
        ((0, 0,), (10, 10), 0.1),
        ((10, 10), (0, 0), 0.1),
        ((-1, -1,), (10, 10), 0.1),
        ((10, 10), (-1, -1), 0.1),
        ((0, ), (10, 10), 0.1),
        ((10, 10), (0,), 0.1),
        ((-1, ), (10, 10), 0.1),
        ((10, 10), (-1, ), 0.1),
    ])
    def test_ZPK_various(zpk):
        """
        Test the conversions to and from ZPK representation and statespace representation
        using a delay filter
        """
        delta_t = 1
        axB = mplfigB(Nrows=2)
        F_Hz = logspaced(0.01 / delta_t, 2 / delta_t, 1000)

        filt = SISO.zpk(zpk, fiducial_rtol=1e-7)
        print(filt)

        xfer1 = filt.fresponse(f=F_Hz).tf
        axB.ax0.semilogx(F_Hz, abs(xfer1), label="Direct ZPK")
        axB.ax1.plot(F_Hz, np.angle(xfer1, deg=True))

        xfer2 = (filt * filt).fresponse(f=F_Hz).tf
        axB.ax0.semilogx(F_Hz, abs(xfer2), label="ZPK self product")
        axB.ax1.plot(F_Hz, np.angle(xfer2, deg=True))

>       filt_ss = filt.asSS * 4

../../src/wield/control/SISO/test/test_SISO_delay.py:194: 
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 
../../src/wield/control/SISO/zpk.py:219: in asSS
    self._SS = algorithm_choice.algo_run(
../../src/wield/control/utilities/algorithm_choice.py:174: in algo_run
    ret = func(*args, **kwargs)
../../src/wield/control/SISO/algorithms_zpk2ss.py:81: in zpk2ss_chain_poly
    statesp = ss.SISOStateSpace(
../../src/wield/control/SISO/ss.py:130: in __init__
    self.__init_internal__(
../../src/wield/control/utilities/__init__.py:35: in wrap
    ret = self.method(inst, *args, **kw)
../../src/wield/control/SISO/ss.py:163: in __init_internal__
    self.test_fresponse(
../../src/wield/control/SISO/siso.py:45: in test_fresponse
    self_response = self.fresponse(**fiducial.domain_kw())
../../src/wield/control/SISO/ss.py:287: in fresponse
    tf = self.ss.fresponse_raw(f=f, w=w, s=s, z=z, **kwargs)[..., 0, 0]
../../src/wield/control/ss_bare/ss.py:288: in fresponse_raw
    return algorithm_choice.algo_run(
../../src/wield/control/utilities/algorithm_choice.py:174: in algo_run
    ret = func(*args, **kwargs)
../../src/wield/control/ss_bare/algorithms_xfers.py:21: in ss2fresponse_laub
    ss = ss.balanceA(which='ABC')
../../src/wield/control/ss_bare/ss.py:574: in balanceA
    Ascale, (sca, P) = scipy.linalg.matrix_balance(
/opt/conda/lib/python3.12/site-packages/scipy/linalg/_basic.py:1662: in matrix_balance
    A = np.atleast_2d(_asarray_validated(A, check_finite=True))
/opt/conda/lib/python3.12/site-packages/scipy/_lib/_util.py:321: in _asarray_validated
    a = toarray(a)
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 

a = array([[ 0.,  1.,  0.],
       [ 1., nan, nan],
       [ 0., nan, nan]])
dtype = None, order = None

    @set_module('numpy')
    def asarray_chkfinite(a, dtype=None, order=None):
        """Convert the input to an array, checking for NaNs or Infs.

        Parameters
        ----------
        a : array_like
            Input data, in any form that can be converted to an array.  This
            includes lists, lists of tuples, tuples, tuples of tuples, tuples
            of lists and ndarrays.  Success requires no NaNs or Infs.
        dtype : data-type, optional
            By default, the data-type is inferred from the input data.
        order : {'C', 'F', 'A', 'K'}, optional
            Memory layout.  'A' and 'K' depend on the order of input array a.
            'C' row-major (C-style),
            'F' column-major (Fortran-style) memory representation.
            'A' (any) means 'F' if `a` is Fortran contiguous, 'C' otherwise
            'K' (keep) preserve input order
            Defaults to 'C'.

        Returns
        -------
        out : ndarray
            Array interpretation of `a`.  No copy is performed if the input
            is already an ndarray.  If `a` is a subclass of ndarray, a base
            class ndarray is returned.

        Raises
        ------
        ValueError
            Raises ValueError if `a` contains NaN (Not a Number) or Inf (Infinity).

        See Also
        --------
        asarray : Create and array.
        asanyarray : Similar function which passes through subclasses.
        ascontiguousarray : Convert input to a contiguous array.
        asfarray : Convert input to a floating point ndarray.
        asfortranarray : Convert input to an ndarray with column-major
                         memory order.
        fromiter : Create an array from an iterator.
        fromfunction : Construct an array by executing a function on grid
                       positions.

        Examples
        --------
        Convert a list into an array.  If all elements are finite
        ``asarray_chkfinite`` is identical to ``asarray``.

        >>> a = [1, 2]
        >>> np.asarray_chkfinite(a, dtype=float)
        array([1., 2.])

        Raises ValueError if array_like contains Nans or Infs.

        >>> a = [1, 2, np.inf]
        >>> try:
        ...     np.asarray_chkfinite(a)
        ... except ValueError:
        ...     print('ValueError')
        ...
        ValueError

        """
        a = asarray(a, dtype=dtype, order=order)
        if a.dtype.char in typecodes['AllFloat'] and not np.isfinite(a).all():
>           raise ValueError(
                "array must not contain infs or NaNs")
E           ValueError: array must not contain infs or NaNs

/opt/conda/lib/python3.12/site-packages/numpy/lib/function_base.py:630: ValueError
test_ZPK_various[zpk0]
output
zpk(z=2π·[0.0], p=2π·[], k=0.1)
captured errors:
zpk = ((0,), (), 0.1)

    @pytest.mark.parametrize('zpk', [
        ((0,), (), 0.1),
        ((), (0,), 0.1),
        ((-1,), (), 0.1),
        ((), (-1,), 0.1),
        ((0, 0,), (10, 10), 0.1),
        ((10, 10), (0, 0), 0.1),
        ((-1, -1,), (10, 10), 0.1),
        ((10, 10), (-1, -1), 0.1),
        ((0, ), (10, 10), 0.1),
        ((10, 10), (0,), 0.1),
        ((-1, ), (10, 10), 0.1),
        ((10, 10), (-1, ), 0.1),
    ])
    def test_ZPK_various(zpk):
        """
        Test the conversions to and from ZPK representation and statespace representation
        using a delay filter
        """
        delta_t = 1
        axB = mplfigB(Nrows=2)
        F_Hz = logspaced(0.01 / delta_t, 2 / delta_t, 1000)

        filt = SISO.zpk(zpk, fiducial_rtol=1e-7)
        print(filt)

        xfer1 = filt.fresponse(f=F_Hz).tf
        axB.ax0.semilogx(F_Hz, abs(xfer1), label="Direct ZPK")
        axB.ax1.plot(F_Hz, np.angle(xfer1, deg=True))

        xfer2 = (filt * filt).fresponse(f=F_Hz).tf
        axB.ax0.semilogx(F_Hz, abs(xfer2), label="ZPK self product")
        axB.ax1.plot(F_Hz, np.angle(xfer2, deg=True))

>       filt_ss = filt.asSS * 4

../../src/wield/control/SISO/test/test_SISO_delay.py:194: 
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 
../../src/wield/control/SISO/zpk.py:219: in asSS
    self._SS = algorithm_choice.algo_run(
../../src/wield/control/utilities/algorithm_choice.py:174: in algo_run
    ret = func(*args, **kwargs)
../../src/wield/control/SISO/algorithms_zpk2ss.py:81: in zpk2ss_chain_poly
    statesp = ss.SISOStateSpace(
../../src/wield/control/SISO/ss.py:130: in __init__
    self.__init_internal__(
../../src/wield/control/utilities/__init__.py:35: in wrap
    ret = self.method(inst, *args, **kw)
../../src/wield/control/SISO/ss.py:163: in __init_internal__
    self.test_fresponse(
../../src/wield/control/SISO/siso.py:45: in test_fresponse
    self_response = self.fresponse(**fiducial.domain_kw())
../../src/wield/control/SISO/ss.py:287: in fresponse
    tf = self.ss.fresponse_raw(f=f, w=w, s=s, z=z, **kwargs)[..., 0, 0]
../../src/wield/control/ss_bare/ss.py:288: in fresponse_raw
    return algorithm_choice.algo_run(
../../src/wield/control/utilities/algorithm_choice.py:174: in algo_run
    ret = func(*args, **kwargs)
../../src/wield/control/ss_bare/algorithms_xfers.py:21: in ss2fresponse_laub
    ss = ss.balanceA(which='ABC')
../../src/wield/control/ss_bare/ss.py:574: in balanceA
    Ascale, (sca, P) = scipy.linalg.matrix_balance(
/opt/conda/lib/python3.12/site-packages/scipy/linalg/_basic.py:1662: in matrix_balance
    A = np.atleast_2d(_asarray_validated(A, check_finite=True))
/opt/conda/lib/python3.12/site-packages/scipy/_lib/_util.py:321: in _asarray_validated
    a = toarray(a)
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 

a = array([[0. , 1. ],
       [0.5, nan]]), dtype = None, order = None

    @set_module('numpy')
    def asarray_chkfinite(a, dtype=None, order=None):
        """Convert the input to an array, checking for NaNs or Infs.

        Parameters
        ----------
        a : array_like
            Input data, in any form that can be converted to an array.  This
            includes lists, lists of tuples, tuples, tuples of tuples, tuples
            of lists and ndarrays.  Success requires no NaNs or Infs.
        dtype : data-type, optional
            By default, the data-type is inferred from the input data.
        order : {'C', 'F', 'A', 'K'}, optional
            Memory layout.  'A' and 'K' depend on the order of input array a.
            'C' row-major (C-style),
            'F' column-major (Fortran-style) memory representation.
            'A' (any) means 'F' if `a` is Fortran contiguous, 'C' otherwise
            'K' (keep) preserve input order
            Defaults to 'C'.

        Returns
        -------
        out : ndarray
            Array interpretation of `a`.  No copy is performed if the input
            is already an ndarray.  If `a` is a subclass of ndarray, a base
            class ndarray is returned.

        Raises
        ------
        ValueError
            Raises ValueError if `a` contains NaN (Not a Number) or Inf (Infinity).

        See Also
        --------
        asarray : Create and array.
        asanyarray : Similar function which passes through subclasses.
        ascontiguousarray : Convert input to a contiguous array.
        asfarray : Convert input to a floating point ndarray.
        asfortranarray : Convert input to an ndarray with column-major
                         memory order.
        fromiter : Create an array from an iterator.
        fromfunction : Construct an array by executing a function on grid
                       positions.

        Examples
        --------
        Convert a list into an array.  If all elements are finite
        ``asarray_chkfinite`` is identical to ``asarray``.

        >>> a = [1, 2]
        >>> np.asarray_chkfinite(a, dtype=float)
        array([1., 2.])

        Raises ValueError if array_like contains Nans or Infs.

        >>> a = [1, 2, np.inf]
        >>> try:
        ...     np.asarray_chkfinite(a)
        ... except ValueError:
        ...     print('ValueError')
        ...
        ValueError

        """
        a = asarray(a, dtype=dtype, order=order)
        if a.dtype.char in typecodes['AllFloat'] and not np.isfinite(a).all():
>           raise ValueError(
                "array must not contain infs or NaNs")
E           ValueError: array must not contain infs or NaNs

/opt/conda/lib/python3.12/site-packages/numpy/lib/function_base.py:630: ValueError
test_ZPK_various[zpk7]
output
zpk(z=2π·[ 1.591549430918954,  1.591549430918954], p=2π·[-0.1591549430918953, -0.1591549430918953], k=0.1)
test_ZPK_various[zpk10]
output
zpk(z=2π·[-0.1591549430918953], p=2π·[ 1.591549430918954,  1.591549430918954], k=0.1)
test_ZPK_various[zpk4]
output
zpk(z=2π·[0.0, 0.0], p=2π·[ 1.591549430918954,  1.591549430918954], k=0.1)
test_ZPK_various[zpk11]
output
zpk(z=2π·[ 1.591549430918954,  1.591549430918954], p=2π·[-0.1591549430918953], k=0.1)
captured errors:
zpk = ((10, 10), (-1,), 0.1)

    @pytest.mark.parametrize('zpk', [
        ((0,), (), 0.1),
        ((), (0,), 0.1),
        ((-1,), (), 0.1),
        ((), (-1,), 0.1),
        ((0, 0,), (10, 10), 0.1),
        ((10, 10), (0, 0), 0.1),
        ((-1, -1,), (10, 10), 0.1),
        ((10, 10), (-1, -1), 0.1),
        ((0, ), (10, 10), 0.1),
        ((10, 10), (0,), 0.1),
        ((-1, ), (10, 10), 0.1),
        ((10, 10), (-1, ), 0.1),
    ])
    def test_ZPK_various(zpk):
        """
        Test the conversions to and from ZPK representation and statespace representation
        using a delay filter
        """
        delta_t = 1
        axB = mplfigB(Nrows=2)
        F_Hz = logspaced(0.01 / delta_t, 2 / delta_t, 1000)

        filt = SISO.zpk(zpk, fiducial_rtol=1e-7)
        print(filt)

        xfer1 = filt.fresponse(f=F_Hz).tf
        axB.ax0.semilogx(F_Hz, abs(xfer1), label="Direct ZPK")
        axB.ax1.plot(F_Hz, np.angle(xfer1, deg=True))

        xfer2 = (filt * filt).fresponse(f=F_Hz).tf
        axB.ax0.semilogx(F_Hz, abs(xfer2), label="ZPK self product")
        axB.ax1.plot(F_Hz, np.angle(xfer2, deg=True))

>       filt_ss = filt.asSS * 4

../../src/wield/control/SISO/test/test_SISO_delay.py:194: 
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 
../../src/wield/control/SISO/zpk.py:219: in asSS
    self._SS = algorithm_choice.algo_run(
../../src/wield/control/utilities/algorithm_choice.py:174: in algo_run
    ret = func(*args, **kwargs)
../../src/wield/control/SISO/algorithms_zpk2ss.py:81: in zpk2ss_chain_poly
    statesp = ss.SISOStateSpace(
../../src/wield/control/SISO/ss.py:130: in __init__
    self.__init_internal__(
../../src/wield/control/utilities/__init__.py:35: in wrap
    ret = self.method(inst, *args, **kw)
../../src/wield/control/SISO/ss.py:163: in __init_internal__
    self.test_fresponse(
../../src/wield/control/SISO/siso.py:45: in test_fresponse
    self_response = self.fresponse(**fiducial.domain_kw())
../../src/wield/control/SISO/ss.py:287: in fresponse
    tf = self.ss.fresponse_raw(f=f, w=w, s=s, z=z, **kwargs)[..., 0, 0]
../../src/wield/control/ss_bare/ss.py:288: in fresponse_raw
    return algorithm_choice.algo_run(
../../src/wield/control/utilities/algorithm_choice.py:174: in algo_run
    ret = func(*args, **kwargs)
../../src/wield/control/ss_bare/algorithms_xfers.py:21: in ss2fresponse_laub
    ss = ss.balanceA(which='ABC')
../../src/wield/control/ss_bare/ss.py:574: in balanceA
    Ascale, (sca, P) = scipy.linalg.matrix_balance(
/opt/conda/lib/python3.12/site-packages/scipy/linalg/_basic.py:1662: in matrix_balance
    A = np.atleast_2d(_asarray_validated(A, check_finite=True))
/opt/conda/lib/python3.12/site-packages/scipy/_lib/_util.py:321: in _asarray_validated
    a = toarray(a)
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 

a = array([[0.        , 1.        , 0.        ],
       [1.        ,        nan,        nan],
       [1.41421356,        nan,        nan]])
dtype = None, order = None

    @set_module('numpy')
    def asarray_chkfinite(a, dtype=None, order=None):
        """Convert the input to an array, checking for NaNs or Infs.

        Parameters
        ----------
        a : array_like
            Input data, in any form that can be converted to an array.  This
            includes lists, lists of tuples, tuples, tuples of tuples, tuples
            of lists and ndarrays.  Success requires no NaNs or Infs.
        dtype : data-type, optional
            By default, the data-type is inferred from the input data.
        order : {'C', 'F', 'A', 'K'}, optional
            Memory layout.  'A' and 'K' depend on the order of input array a.
            'C' row-major (C-style),
            'F' column-major (Fortran-style) memory representation.
            'A' (any) means 'F' if `a` is Fortran contiguous, 'C' otherwise
            'K' (keep) preserve input order
            Defaults to 'C'.

        Returns
        -------
        out : ndarray
            Array interpretation of `a`.  No copy is performed if the input
            is already an ndarray.  If `a` is a subclass of ndarray, a base
            class ndarray is returned.

        Raises
        ------
        ValueError
            Raises ValueError if `a` contains NaN (Not a Number) or Inf (Infinity).

        See Also
        --------
        asarray : Create and array.
        asanyarray : Similar function which passes through subclasses.
        ascontiguousarray : Convert input to a contiguous array.
        asfarray : Convert input to a floating point ndarray.
        asfortranarray : Convert input to an ndarray with column-major
                         memory order.
        fromiter : Create an array from an iterator.
        fromfunction : Construct an array by executing a function on grid
                       positions.

        Examples
        --------
        Convert a list into an array.  If all elements are finite
        ``asarray_chkfinite`` is identical to ``asarray``.

        >>> a = [1, 2]
        >>> np.asarray_chkfinite(a, dtype=float)
        array([1., 2.])

        Raises ValueError if array_like contains Nans or Infs.

        >>> a = [1, 2, np.inf]
        >>> try:
        ...     np.asarray_chkfinite(a)
        ... except ValueError:
        ...     print('ValueError')
        ...
        ValueError

        """
        a = asarray(a, dtype=dtype, order=order)
        if a.dtype.char in typecodes['AllFloat'] and not np.isfinite(a).all():
>           raise ValueError(
                "array must not contain infs or NaNs")
E           ValueError: array must not contain infs or NaNs

/opt/conda/lib/python3.12/site-packages/numpy/lib/function_base.py:630: ValueError
test_ZPK_various[zpk2]
output
zpk(z=2π·[-0.1591549430918953], p=2π·[], k=0.1)
captured errors:
zpk = ((-1,), (), 0.1)

    @pytest.mark.parametrize('zpk', [
        ((0,), (), 0.1),
        ((), (0,), 0.1),
        ((-1,), (), 0.1),
        ((), (-1,), 0.1),
        ((0, 0,), (10, 10), 0.1),
        ((10, 10), (0, 0), 0.1),
        ((-1, -1,), (10, 10), 0.1),
        ((10, 10), (-1, -1), 0.1),
        ((0, ), (10, 10), 0.1),
        ((10, 10), (0,), 0.1),
        ((-1, ), (10, 10), 0.1),
        ((10, 10), (-1, ), 0.1),
    ])
    def test_ZPK_various(zpk):
        """
        Test the conversions to and from ZPK representation and statespace representation
        using a delay filter
        """
        delta_t = 1
        axB = mplfigB(Nrows=2)
        F_Hz = logspaced(0.01 / delta_t, 2 / delta_t, 1000)

        filt = SISO.zpk(zpk, fiducial_rtol=1e-7)
        print(filt)

        xfer1 = filt.fresponse(f=F_Hz).tf
        axB.ax0.semilogx(F_Hz, abs(xfer1), label="Direct ZPK")
        axB.ax1.plot(F_Hz, np.angle(xfer1, deg=True))

        xfer2 = (filt * filt).fresponse(f=F_Hz).tf
        axB.ax0.semilogx(F_Hz, abs(xfer2), label="ZPK self product")
        axB.ax1.plot(F_Hz, np.angle(xfer2, deg=True))

>       filt_ss = filt.asSS * 4

../../src/wield/control/SISO/test/test_SISO_delay.py:194: 
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 
../../src/wield/control/SISO/zpk.py:219: in asSS
    self._SS = algorithm_choice.algo_run(
../../src/wield/control/utilities/algorithm_choice.py:174: in algo_run
    ret = func(*args, **kwargs)
../../src/wield/control/SISO/algorithms_zpk2ss.py:81: in zpk2ss_chain_poly
    statesp = ss.SISOStateSpace(
../../src/wield/control/SISO/ss.py:130: in __init__
    self.__init_internal__(
../../src/wield/control/utilities/__init__.py:35: in wrap
    ret = self.method(inst, *args, **kw)
../../src/wield/control/SISO/ss.py:163: in __init_internal__
    self.test_fresponse(
../../src/wield/control/SISO/siso.py:45: in test_fresponse
    self_response = self.fresponse(**fiducial.domain_kw())
../../src/wield/control/SISO/ss.py:287: in fresponse
    tf = self.ss.fresponse_raw(f=f, w=w, s=s, z=z, **kwargs)[..., 0, 0]
../../src/wield/control/ss_bare/ss.py:288: in fresponse_raw
    return algorithm_choice.algo_run(
../../src/wield/control/utilities/algorithm_choice.py:174: in algo_run
    ret = func(*args, **kwargs)
../../src/wield/control/ss_bare/algorithms_xfers.py:21: in ss2fresponse_laub
    ss = ss.balanceA(which='ABC')
../../src/wield/control/ss_bare/ss.py:574: in balanceA
    Ascale, (sca, P) = scipy.linalg.matrix_balance(
/opt/conda/lib/python3.12/site-packages/scipy/linalg/_basic.py:1662: in matrix_balance
    A = np.atleast_2d(_asarray_validated(A, check_finite=True))
/opt/conda/lib/python3.12/site-packages/scipy/_lib/_util.py:321: in _asarray_validated
    a = toarray(a)
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 

a = array([[0. , 1. ],
       [0.5, nan]]), dtype = None, order = None

    @set_module('numpy')
    def asarray_chkfinite(a, dtype=None, order=None):
        """Convert the input to an array, checking for NaNs or Infs.

        Parameters
        ----------
        a : array_like
            Input data, in any form that can be converted to an array.  This
            includes lists, lists of tuples, tuples, tuples of tuples, tuples
            of lists and ndarrays.  Success requires no NaNs or Infs.
        dtype : data-type, optional
            By default, the data-type is inferred from the input data.
        order : {'C', 'F', 'A', 'K'}, optional
            Memory layout.  'A' and 'K' depend on the order of input array a.
            'C' row-major (C-style),
            'F' column-major (Fortran-style) memory representation.
            'A' (any) means 'F' if `a` is Fortran contiguous, 'C' otherwise
            'K' (keep) preserve input order
            Defaults to 'C'.

        Returns
        -------
        out : ndarray
            Array interpretation of `a`.  No copy is performed if the input
            is already an ndarray.  If `a` is a subclass of ndarray, a base
            class ndarray is returned.

        Raises
        ------
        ValueError
            Raises ValueError if `a` contains NaN (Not a Number) or Inf (Infinity).

        See Also
        --------
        asarray : Create and array.
        asanyarray : Similar function which passes through subclasses.
        ascontiguousarray : Convert input to a contiguous array.
        asfarray : Convert input to a floating point ndarray.
        asfortranarray : Convert input to an ndarray with column-major
                         memory order.
        fromiter : Create an array from an iterator.
        fromfunction : Construct an array by executing a function on grid
                       positions.

        Examples
        --------
        Convert a list into an array.  If all elements are finite
        ``asarray_chkfinite`` is identical to ``asarray``.

        >>> a = [1, 2]
        >>> np.asarray_chkfinite(a, dtype=float)
        array([1., 2.])

        Raises ValueError if array_like contains Nans or Infs.

        >>> a = [1, 2, np.inf]
        >>> try:
        ...     np.asarray_chkfinite(a)
        ... except ValueError:
        ...     print('ValueError')
        ...
        ValueError

        """
        a = asarray(a, dtype=dtype, order=order)
        if a.dtype.char in typecodes['AllFloat'] and not np.isfinite(a).all():
>           raise ValueError(
                "array must not contain infs or NaNs")
E           ValueError: array must not contain infs or NaNs

/opt/conda/lib/python3.12/site-packages/numpy/lib/function_base.py:630: ValueError
test_ZPK_various[zpk3]
output
zpk(z=2π·[], p=2π·[-0.1591549430918953], k=0.1)
captured errors:
args = (array([0.19921354, 0.19920518, 0.19919674, 0.19918821, 0.19917959,
       0.19917088, 0.19916207, 0.19915318, 0.19914...8, 0.00273848, 0.00270978, 0.00268139, 0.00265328,
       0.00262547, 0.00259795, 0.00257071, 0.00254376, 0.00251709]))
kwds = {'decimal': 7}

    @wraps(func)
    def inner(*args, **kwds):
        with self._recreate_cm():
>           return func(*args, **kwds)

/opt/conda/lib/python3.12/contextlib.py:81: 
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 
/opt/conda/lib/python3.12/contextlib.py:81: in inner
    return func(*args, **kwds)
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 

args = (<function assert_array_almost_equal.<locals>.compare at 0x7f6870947d80>, array([0.19921354, 0.19920518, 0.19919674, 0...8, 0.00273848, 0.00270978, 0.00268139, 0.00265328,
       0.00262547, 0.00259795, 0.00257071, 0.00254376, 0.00251709]))
kwds = {'err_msg': '', 'header': 'Arrays are not almost equal to 7 decimals', 'precision': 7, 'verbose': True}

    @wraps(func)
    def inner(*args, **kwds):
        with self._recreate_cm():
>           return func(*args, **kwds)
E           AssertionError: 
E           Arrays are not almost equal to 7 decimals
E           
E           Mismatched elements: 1000 / 1000 (100%)
E           Max absolute difference: 0.19921354
E           Max relative difference: 0.5
E            x: array([0.1992135, 0.1992052, 0.1991967, 0.1991882, 0.1991796, 0.1991709,
E                  0.1991621, 0.1991532, 0.1991442, 0.1991351, 0.1991259, 0.1991166,
E                  0.1991073, 0.1990978, 0.1990882, 0.1990785, 0.1990687, 0.1990589,...
E            y: array([0.3984271, 0.3984104, 0.3983935, 0.3983764, 0.3983592, 0.3983418,
E                  0.3983241, 0.3983064, 0.3982884, 0.3982702, 0.3982518, 0.3982333,
E                  0.3982145, 0.3981956, 0.3981764, 0.398157 , 0.3981375, 0.3981177,...

/opt/conda/lib/python3.12/contextlib.py:81: AssertionError

During handling of the above exception, another exception occurred:

zpk = ((), (-1,), 0.1)

    @pytest.mark.parametrize('zpk', [
        ((0,), (), 0.1),
        ((), (0,), 0.1),
        ((-1,), (), 0.1),
        ((), (-1,), 0.1),
        ((0, 0,), (10, 10), 0.1),
        ((10, 10), (0, 0), 0.1),
        ((-1, -1,), (10, 10), 0.1),
        ((10, 10), (-1, -1), 0.1),
        ((0, ), (10, 10), 0.1),
        ((10, 10), (0,), 0.1),
        ((-1, ), (10, 10), 0.1),
        ((10, 10), (-1, ), 0.1),
    ])
    def test_ZPK_various(zpk):
        """
        Test the conversions to and from ZPK representation and statespace representation
        using a delay filter
        """
        delta_t = 1
        axB = mplfigB(Nrows=2)
        F_Hz = logspaced(0.01 / delta_t, 2 / delta_t, 1000)

        filt = SISO.zpk(zpk, fiducial_rtol=1e-7)
        print(filt)

        xfer1 = filt.fresponse(f=F_Hz).tf
        axB.ax0.semilogx(F_Hz, abs(xfer1), label="Direct ZPK")
        axB.ax1.plot(F_Hz, np.angle(xfer1, deg=True))

        xfer2 = (filt * filt).fresponse(f=F_Hz).tf
        axB.ax0.semilogx(F_Hz, abs(xfer2), label="ZPK self product")
        axB.ax1.plot(F_Hz, np.angle(xfer2, deg=True))

        filt_ss = filt.asSS * 4
        filt_ssi = 1/filt_ss
        xfer3 = filt_ss.fresponse(f=F_Hz).tf
        xfer3b = filt_ssi.fresponse(f=F_Hz).tf
        axB.ax0.semilogx(F_Hz, abs(xfer3) / 4, label="ZPK2SS")
        axB.ax1.plot(F_Hz, np.angle(xfer3, deg=True))
        axB.ax0.semilogx(F_Hz, abs(1/xfer3b) / 4, label="ZPK2SS inv")
        axB.ax1.plot(F_Hz, np.angle(1/xfer3b, deg=True))

        filt_zpk = filt_ss.asZPK
        filt_zpki = filt_ssi.asZPK
        xfer4 = filt_zpk.fresponse(f=F_Hz).tf
        xfer4b = (1/filt_zpk).fresponse(f=F_Hz).tf
        xfer4c = (filt_zpki).fresponse(f=F_Hz).tf
        axB.ax0.semilogx(F_Hz, abs(xfer4) / 4, label="SS2ZPK")
        axB.ax1.plot(F_Hz, np.angle(xfer3, deg=True))
        axB.ax0.semilogx(F_Hz, abs(1/xfer4b) / 4, label="SS2ZPK inv")
        axB.ax1.plot(F_Hz, np.angle(1/xfer4b, deg=True))
        axB.ax0.semilogx(F_Hz, abs(1/xfer4c) / 4, label="SS2ZPK ss inv")
        axB.ax1.plot(F_Hz, np.angle(1/xfer4c, deg=True))

        axB.ax0.legend()
        axB.save(tjoin("test_ZPK"))

        np.testing.assert_almost_equal(xfer2, xfer1**2)
>       np.testing.assert_almost_equal(xfer3, 4 * xfer1)

../../src/wield/control/SISO/test/test_SISO_delay.py:219: 
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 

args = (array([0.19921354-0.01251696j, 0.19920518-0.01258299j,
       0.19919674-0.01264937j, 0.19918821-0.01271609j,
       ...30007j,
       0.00259795-0.03213144j, 0.00257071-0.03196367j,
       0.00254376-0.03179675j, 0.00251709-0.03163068j]))
kwds = {}

    @wraps(func)
    def inner(*args, **kwds):
        with self._recreate_cm():
>           return func(*args, **kwds)
E           AssertionError: 
E           Arrays are not almost equal to 7 decimals
E            ACTUAL: array([0.19921354-0.01251696j, 0.19920518-0.01258299j,
E                  0.19919674-0.01264937j, 0.19918821-0.01271609j,
E                  0.19917959-0.01278315j, 0.19917088-0.01285057j,...
E            DESIRED: array([0.39842707-0.02503391j, 0.39841037-0.02516598j,
E                  0.39839348-0.02529873j, 0.39837642-0.02543217j,
E                  0.39835918-0.02556631j, 0.39834175-0.02570114j,...

/opt/conda/lib/python3.12/contextlib.py:81: AssertionError
test_ZPK_various[zpk6]
output
zpk(z=2π·[-0.1591549430918953, -0.1591549430918953], p=2π·[ 1.591549430918954,  1.591549430918954], k=0.1)
test_ZPK_various[zpk8]
output
zpk(z=2π·[0.0], p=2π·[ 1.591549430918954,  1.591549430918954], k=0.1)
test_ZPK_various[zpk5]
output
zpk(z=2π·[ 1.591549430918954,  1.591549430918954], p=2π·[0.0, 0.0], k=0.1)
test_ZPK_various[zpk1]
output
zpk(z=2π·[], p=2π·[0.0], k=0.1)
captured errors:
args = (array([-3.18309886, -3.1662616 , -3.1495134 , -3.13285379, -3.11628231,
       -3.09979848, -3.08340184, -3.06709194,...21061, -0.03303494, -0.03286019, -0.03268638,
       -0.03251348, -0.0323415 , -0.03217042, -0.03200026, -0.03183099]))
kwds = {'decimal': 7}

    @wraps(func)
    def inner(*args, **kwds):
        with self._recreate_cm():
>           return func(*args, **kwds)

/opt/conda/lib/python3.12/contextlib.py:81: 
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 
/opt/conda/lib/python3.12/contextlib.py:81: in inner
    return func(*args, **kwds)
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 

args = (<function assert_array_almost_equal.<locals>.compare at 0x7f6877be27a0>, array([-3.18309886, -3.1662616 , -3.1495134 ...21061, -0.03303494, -0.03286019, -0.03268638,
       -0.03251348, -0.0323415 , -0.03217042, -0.03200026, -0.03183099]))
kwds = {'err_msg': '', 'header': 'Arrays are not almost equal to 7 decimals', 'precision': 7, 'verbose': True}

    @wraps(func)
    def inner(*args, **kwds):
        with self._recreate_cm():
>           return func(*args, **kwds)
E           AssertionError: 
E           Arrays are not almost equal to 7 decimals
E           
E           Mismatched elements: 1000 / 1000 (100%)
E           Max absolute difference: 3.18309886
E           Max relative difference: 0.5
E            x: array([-3.1830989, -3.1662616, -3.1495134, -3.1328538, -3.1162823,
E                  -3.0997985, -3.0834018, -3.0670919, -3.0508683, -3.0347305,
E                  -3.018678 , -3.0027105, -2.9868274, -2.9710283, -2.9553128,...
E            y: array([-6.3661977, -6.3325232, -6.2990268, -6.2657076, -6.2325646,
E                  -6.199597 , -6.1668037, -6.1341839, -6.1017366, -6.069461 ,
E                  -6.0373561, -6.005421 , -5.9736548, -5.9420567, -5.9106257,...

/opt/conda/lib/python3.12/contextlib.py:81: AssertionError

During handling of the above exception, another exception occurred:

zpk = ((), (0,), 0.1)

    @pytest.mark.parametrize('zpk', [
        ((0,), (), 0.1),
        ((), (0,), 0.1),
        ((-1,), (), 0.1),
        ((), (-1,), 0.1),
        ((0, 0,), (10, 10), 0.1),
        ((10, 10), (0, 0), 0.1),
        ((-1, -1,), (10, 10), 0.1),
        ((10, 10), (-1, -1), 0.1),
        ((0, ), (10, 10), 0.1),
        ((10, 10), (0,), 0.1),
        ((-1, ), (10, 10), 0.1),
        ((10, 10), (-1, ), 0.1),
    ])
    def test_ZPK_various(zpk):
        """
        Test the conversions to and from ZPK representation and statespace representation
        using a delay filter
        """
        delta_t = 1
        axB = mplfigB(Nrows=2)
        F_Hz = logspaced(0.01 / delta_t, 2 / delta_t, 1000)

        filt = SISO.zpk(zpk, fiducial_rtol=1e-7)
        print(filt)

        xfer1 = filt.fresponse(f=F_Hz).tf
        axB.ax0.semilogx(F_Hz, abs(xfer1), label="Direct ZPK")
        axB.ax1.plot(F_Hz, np.angle(xfer1, deg=True))

        xfer2 = (filt * filt).fresponse(f=F_Hz).tf
        axB.ax0.semilogx(F_Hz, abs(xfer2), label="ZPK self product")
        axB.ax1.plot(F_Hz, np.angle(xfer2, deg=True))

        filt_ss = filt.asSS * 4
        filt_ssi = 1/filt_ss
        xfer3 = filt_ss.fresponse(f=F_Hz).tf
        xfer3b = filt_ssi.fresponse(f=F_Hz).tf
        axB.ax0.semilogx(F_Hz, abs(xfer3) / 4, label="ZPK2SS")
        axB.ax1.plot(F_Hz, np.angle(xfer3, deg=True))
        axB.ax0.semilogx(F_Hz, abs(1/xfer3b) / 4, label="ZPK2SS inv")
        axB.ax1.plot(F_Hz, np.angle(1/xfer3b, deg=True))

        filt_zpk = filt_ss.asZPK
        filt_zpki = filt_ssi.asZPK
        xfer4 = filt_zpk.fresponse(f=F_Hz).tf
        xfer4b = (1/filt_zpk).fresponse(f=F_Hz).tf
        xfer4c = (filt_zpki).fresponse(f=F_Hz).tf
        axB.ax0.semilogx(F_Hz, abs(xfer4) / 4, label="SS2ZPK")
        axB.ax1.plot(F_Hz, np.angle(xfer3, deg=True))
        axB.ax0.semilogx(F_Hz, abs(1/xfer4b) / 4, label="SS2ZPK inv")
        axB.ax1.plot(F_Hz, np.angle(1/xfer4b, deg=True))
        axB.ax0.semilogx(F_Hz, abs(1/xfer4c) / 4, label="SS2ZPK ss inv")
        axB.ax1.plot(F_Hz, np.angle(1/xfer4c, deg=True))

        axB.ax0.legend()
        axB.save(tjoin("test_ZPK"))

        np.testing.assert_almost_equal(xfer2, xfer1**2)
>       np.testing.assert_almost_equal(xfer3, 4 * xfer1)

../../src/wield/control/SISO/test/test_SISO_delay.py:219: 
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 

args = (array([0.-3.18309886j, 0.-3.1662616j , 0.-3.1495134j , 0.-3.13285379j,
       0.-3.11628231j, 0.-3.09979848j, 0.-3.08....-0.03286019j, 0.-0.03268638j, 0.-0.03251348j,
       0.-0.0323415j , 0.-0.03217042j, 0.-0.03200026j, 0.-0.03183099j]))
kwds = {}

    @wraps(func)
    def inner(*args, **kwds):
        with self._recreate_cm():
>           return func(*args, **kwds)
E           AssertionError: 
E           Arrays are not almost equal to 7 decimals
E            ACTUAL: array([0.-3.18309886j, 0.-3.1662616j , 0.-3.1495134j , 0.-3.13285379j,
E                  0.-3.11628231j, 0.-3.09979848j, 0.-3.08340184j, 0.-3.06709194j,
E                  0.-3.0508683j , 0.-3.03473048j, 0.-3.01867803j, 0.-3.00271049j,...
E            DESIRED: array([0.-6.36619772j, 0.-6.3325232j , 0.-6.2990268j , 0.-6.26570759j,
E                  0.-6.23256461j, 0.-6.19959696j, 0.-6.16680368j, 0.-6.13418387j,
E                  0.-6.1017366j , 0.-6.06946097j, 0.-6.03735606j, 0.-6.00542097j,...

/opt/conda/lib/python3.12/contextlib.py:81: AssertionError