test_residues¶

wield.control.fitting.SISO.test.residues.test_residues

This is a pytest module needing documentation

pytest-html report

Functions

test_residues(ZPK)

This is a pytest needing documentation

Details

test_residues(ZPK)[source][github]¶

This is a pytest needing documentation

code
 1@pytest.mark.parametrize(
 2    "ZPK",
 3    [
 4        (((), (-1,), 10)),
 5        (((), (-1, -2), 10)),
 6        (
 7            (
 8                (),
 9                (
10                    -1,
11                    -1,
12                ),
13                10,
14            )
15        ),
16        (((), (-1, -1, -2), 10)),
17        (((), (-1, -1, -1), 10)),
18        (((), (-1, -1, -1, -2), 10)),
19        (((), (-1, -1, -1, -1), 10)),
20        (((), (-1, -1, -1, -1, -2), 10)),
21        (((-3,) * 1, (-1,), 10)),
22        (((-3,) * 1, (-1, -2), 10)),
23        (
24            (
25                (-3,) * 1,
26                (
27                    -1,
28                    -1,
29                ),
30                10,
31            )
32        ),
33        (((-3,) * 1, (-1, -1, -2), 10)),
34        (((-3,) * 1, (-1, -1, -1), 10)),
35        (((-3,) * 1, (-1, -1, -1, -2), 10)),
36        (((-3,) * 1, (-1, -1, -1, -1), 10)),
37        (((-3,) * 1, (-1, -1, -1, -1, -2), 10)),
38        (((-3,) * 2, (-1,), 10)),
39        (((-3,) * 2, (-1, -2), 10)),
40        (
41            (
42                (-3,) * 2,
43                (
44                    -1,
45                    -1,
46                ),
47                10,
48            )
49        ),
50        (((-3,) * 2, (-1, -1, -2), 10)),
51        (((-3,) * 2, (-1, -1, -1), 10)),
52        (((-3,) * 2, (-1, -1, -1, -2), 10)),
53        (((-3,) * 2, (-1, -1, -1, -1), 10)),
54        (((-3,) * 2, (-1, -1, -1, -1, -2), 10)),
55        (((-3,) * 3, (-1, -2), 10)),
56        (((-3,) * 4, (-1, -2), 10)),
57        (((-3,) * 5, (-1, -2), 10)),
58        (((-3,) * 6, (-1, -2), 10)),
59        (((-3,) * 7, (-1, -2), 10)),
60        (((-3,) * 8, (-1, -2), 10)),
61    ],
62)
63def test_residues(ZPK):
64    print("ZPK: ", ZPK)
65    r_sci, zpk_sci = ZPK2residues_scipy(ZPK)
66    r_std, zpk_std = ZPK2residues(ZPK)
67    print("r_sci: ", r_sci)
68    print("r_std: ", r_std)
69    print()
70    print("zpk_sci: ", zpk_std)
71    print("zpk_std: ", zpk_std)
72
73    ZPK_recomp = residues2ZPK(r_std, zpk_std)
74    print("ZPK recomp: ", ZPK_recomp)
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.fitting.SISO.test.residues.test_residues.test_residues

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_residues[ZPK0]
output
ZPK:  ((), (-1,), 10)
captured errors:
ZPK = ((), (-1,), 10)

    @pytest.mark.parametrize(
        "ZPK",
        [
            (((), (-1,), 10)),
            (((), (-1, -2), 10)),
            (
                (
                    (),
                    (
                        -1,
                        -1,
                    ),
                    10,
                )
            ),
            (((), (-1, -1, -2), 10)),
            (((), (-1, -1, -1), 10)),
            (((), (-1, -1, -1, -2), 10)),
            (((), (-1, -1, -1, -1), 10)),
            (((), (-1, -1, -1, -1, -2), 10)),
            (((-3,) * 1, (-1,), 10)),
            (((-3,) * 1, (-1, -2), 10)),
            (
                (
                    (-3,) * 1,
                    (
                        -1,
                        -1,
                    ),
                    10,
                )
            ),
            (((-3,) * 1, (-1, -1, -2), 10)),
            (((-3,) * 1, (-1, -1, -1), 10)),
            (((-3,) * 1, (-1, -1, -1, -2), 10)),
            (((-3,) * 1, (-1, -1, -1, -1), 10)),
            (((-3,) * 1, (-1, -1, -1, -1, -2), 10)),
            (((-3,) * 2, (-1,), 10)),
            (((-3,) * 2, (-1, -2), 10)),
            (
                (
                    (-3,) * 2,
                    (
                        -1,
                        -1,
                    ),
                    10,
                )
            ),
            (((-3,) * 2, (-1, -1, -2), 10)),
            (((-3,) * 2, (-1, -1, -1), 10)),
            (((-3,) * 2, (-1, -1, -1, -2), 10)),
            (((-3,) * 2, (-1, -1, -1, -1), 10)),
            (((-3,) * 2, (-1, -1, -1, -1, -2), 10)),
            (((-3,) * 3, (-1, -2), 10)),
            (((-3,) * 4, (-1, -2), 10)),
            (((-3,) * 5, (-1, -2), 10)),
            (((-3,) * 6, (-1, -2), 10)),
            (((-3,) * 7, (-1, -2), 10)),
            (((-3,) * 8, (-1, -2), 10)),
        ],
    )
    def test_residues(ZPK):
        print("ZPK: ", ZPK)
>       r_sci, zpk_sci = ZPK2residues_scipy(ZPK)

../../src/wield/control/fitting/SISO/test/residues/test_residues.py:80: 
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 

ZPK = ((), (-1,), 10), F_nyquist_Hz = None

    def ZPK2residues_scipy(
        ZPK,
        F_nyquist_Hz=None,
    ):
        """
        Useful for testing
        """
        residue_list = []
        b, a = scisig.zpk2tf(*ZPK)
        if F_nyquist_Hz is None:
            r, p, k = scisig.residue(b, a)
        else:
            r, p, k = scisig.residuez(b, a)

        # some indexing tricks to change the output to the form above
        same = p[1:] == p[:-1]
        same_adj = np.concatenate([[False], same, [False]])
        same_shift = ~(same_adj[1:] | same_adj[:-1])
        same_starts = ~same_adj[:-1] & same_adj[1:]
        same_ends = same_adj[:-1] & ~same_adj[1:]
        # the addition of same_adj puts all of the non-multiple back in
        for idx_start, idx_end in zip(
            np.argwhere(same_starts | same_shift), np.argwhere(same_ends | same_shift)
        ):
            idx_start = int(idx_start)
            idx_end = int(idx_end)
            pole = p[idx_start]
            res = r[idx_start : idx_end + 1]
            residue_list.append((pole,) + tuple(res))

        if len(k) < 2:
>           return residue_list, ((), (), k[0])
E           IndexError: index 0 is out of bounds for axis 0 with size 0

../../src/wield/control/fitting/SISO/representations/residues.py:310: IndexError
test_residues[ZPK8]
output
ZPK:  ((-3,), (-1,), 10)
r_sci:  [(-1.0, 20.0)]
r_std:  [(-1, 20.0)]

zpk_sci:  ((), (), 10)
zpk_std:  ((), (), 10)
ZPK recomp:  (((-3+0j),), (-1,), (10+0j))
test_residues[ZPK10]
output
ZPK:  ((-3,), (-1, -1), 10)
captured errors:
ZPK = ((-3,), (-1, -1), 10)

    @pytest.mark.parametrize(
        "ZPK",
        [
            (((), (-1,), 10)),
            (((), (-1, -2), 10)),
            (
                (
                    (),
                    (
                        -1,
                        -1,
                    ),
                    10,
                )
            ),
            (((), (-1, -1, -2), 10)),
            (((), (-1, -1, -1), 10)),
            (((), (-1, -1, -1, -2), 10)),
            (((), (-1, -1, -1, -1), 10)),
            (((), (-1, -1, -1, -1, -2), 10)),
            (((-3,) * 1, (-1,), 10)),
            (((-3,) * 1, (-1, -2), 10)),
            (
                (
                    (-3,) * 1,
                    (
                        -1,
                        -1,
                    ),
                    10,
                )
            ),
            (((-3,) * 1, (-1, -1, -2), 10)),
            (((-3,) * 1, (-1, -1, -1), 10)),
            (((-3,) * 1, (-1, -1, -1, -2), 10)),
            (((-3,) * 1, (-1, -1, -1, -1), 10)),
            (((-3,) * 1, (-1, -1, -1, -1, -2), 10)),
            (((-3,) * 2, (-1,), 10)),
            (((-3,) * 2, (-1, -2), 10)),
            (
                (
                    (-3,) * 2,
                    (
                        -1,
                        -1,
                    ),
                    10,
                )
            ),
            (((-3,) * 2, (-1, -1, -2), 10)),
            (((-3,) * 2, (-1, -1, -1), 10)),
            (((-3,) * 2, (-1, -1, -1, -2), 10)),
            (((-3,) * 2, (-1, -1, -1, -1), 10)),
            (((-3,) * 2, (-1, -1, -1, -1, -2), 10)),
            (((-3,) * 3, (-1, -2), 10)),
            (((-3,) * 4, (-1, -2), 10)),
            (((-3,) * 5, (-1, -2), 10)),
            (((-3,) * 6, (-1, -2), 10)),
            (((-3,) * 7, (-1, -2), 10)),
            (((-3,) * 8, (-1, -2), 10)),
        ],
    )
    def test_residues(ZPK):
        print("ZPK: ", ZPK)
>       r_sci, zpk_sci = ZPK2residues_scipy(ZPK)

../../src/wield/control/fitting/SISO/test/residues/test_residues.py:80: 
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 

ZPK = ((-3,), (-1, -1), 10), F_nyquist_Hz = None

    def ZPK2residues_scipy(
        ZPK,
        F_nyquist_Hz=None,
    ):
        """
        Useful for testing
        """
        residue_list = []
        b, a = scisig.zpk2tf(*ZPK)
        if F_nyquist_Hz is None:
            r, p, k = scisig.residue(b, a)
        else:
            r, p, k = scisig.residuez(b, a)

        # some indexing tricks to change the output to the form above
        same = p[1:] == p[:-1]
        same_adj = np.concatenate([[False], same, [False]])
        same_shift = ~(same_adj[1:] | same_adj[:-1])
        same_starts = ~same_adj[:-1] & same_adj[1:]
        same_ends = same_adj[:-1] & ~same_adj[1:]
        # the addition of same_adj puts all of the non-multiple back in
        for idx_start, idx_end in zip(
            np.argwhere(same_starts | same_shift), np.argwhere(same_ends | same_shift)
        ):
            idx_start = int(idx_start)
            idx_end = int(idx_end)
            pole = p[idx_start]
            res = r[idx_start : idx_end + 1]
            residue_list.append((pole,) + tuple(res))

        if len(k) < 2:
>           return residue_list, ((), (), k[0])
E           IndexError: index 0 is out of bounds for axis 0 with size 0

../../src/wield/control/fitting/SISO/representations/residues.py:310: IndexError
test_residues[ZPK20]
output
ZPK:  ((-3, -3), (-1, -1, -1), 10)
captured errors:
ZPK = ((-3, -3), (-1, -1, -1), 10)

    @pytest.mark.parametrize(
        "ZPK",
        [
            (((), (-1,), 10)),
            (((), (-1, -2), 10)),
            (
                (
                    (),
                    (
                        -1,
                        -1,
                    ),
                    10,
                )
            ),
            (((), (-1, -1, -2), 10)),
            (((), (-1, -1, -1), 10)),
            (((), (-1, -1, -1, -2), 10)),
            (((), (-1, -1, -1, -1), 10)),
            (((), (-1, -1, -1, -1, -2), 10)),
            (((-3,) * 1, (-1,), 10)),
            (((-3,) * 1, (-1, -2), 10)),
            (
                (
                    (-3,) * 1,
                    (
                        -1,
                        -1,
                    ),
                    10,
                )
            ),
            (((-3,) * 1, (-1, -1, -2), 10)),
            (((-3,) * 1, (-1, -1, -1), 10)),
            (((-3,) * 1, (-1, -1, -1, -2), 10)),
            (((-3,) * 1, (-1, -1, -1, -1), 10)),
            (((-3,) * 1, (-1, -1, -1, -1, -2), 10)),
            (((-3,) * 2, (-1,), 10)),
            (((-3,) * 2, (-1, -2), 10)),
            (
                (
                    (-3,) * 2,
                    (
                        -1,
                        -1,
                    ),
                    10,
                )
            ),
            (((-3,) * 2, (-1, -1, -2), 10)),
            (((-3,) * 2, (-1, -1, -1), 10)),
            (((-3,) * 2, (-1, -1, -1, -2), 10)),
            (((-3,) * 2, (-1, -1, -1, -1), 10)),
            (((-3,) * 2, (-1, -1, -1, -1, -2), 10)),
            (((-3,) * 3, (-1, -2), 10)),
            (((-3,) * 4, (-1, -2), 10)),
            (((-3,) * 5, (-1, -2), 10)),
            (((-3,) * 6, (-1, -2), 10)),
            (((-3,) * 7, (-1, -2), 10)),
            (((-3,) * 8, (-1, -2), 10)),
        ],
    )
    def test_residues(ZPK):
        print("ZPK: ", ZPK)
>       r_sci, zpk_sci = ZPK2residues_scipy(ZPK)

../../src/wield/control/fitting/SISO/test/residues/test_residues.py:80: 
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 

ZPK = ((-3, -3), (-1, -1, -1), 10), F_nyquist_Hz = None

    def ZPK2residues_scipy(
        ZPK,
        F_nyquist_Hz=None,
    ):
        """
        Useful for testing
        """
        residue_list = []
        b, a = scisig.zpk2tf(*ZPK)
        if F_nyquist_Hz is None:
            r, p, k = scisig.residue(b, a)
        else:
            r, p, k = scisig.residuez(b, a)

        # some indexing tricks to change the output to the form above
        same = p[1:] == p[:-1]
        same_adj = np.concatenate([[False], same, [False]])
        same_shift = ~(same_adj[1:] | same_adj[:-1])
        same_starts = ~same_adj[:-1] & same_adj[1:]
        same_ends = same_adj[:-1] & ~same_adj[1:]
        # the addition of same_adj puts all of the non-multiple back in
        for idx_start, idx_end in zip(
            np.argwhere(same_starts | same_shift), np.argwhere(same_ends | same_shift)
        ):
            idx_start = int(idx_start)
            idx_end = int(idx_end)
            pole = p[idx_start]
            res = r[idx_start : idx_end + 1]
            residue_list.append((pole,) + tuple(res))

        if len(k) < 2:
>           return residue_list, ((), (), k[0])
E           IndexError: index 0 is out of bounds for axis 0 with size 0

../../src/wield/control/fitting/SISO/representations/residues.py:310: IndexError
test_residues[ZPK5]
output
ZPK:  ((), (-1, -1, -1, -2), 10)
captured errors:
ZPK = ((), (-1, -1, -1, -2), 10)

    @pytest.mark.parametrize(
        "ZPK",
        [
            (((), (-1,), 10)),
            (((), (-1, -2), 10)),
            (
                (
                    (),
                    (
                        -1,
                        -1,
                    ),
                    10,
                )
            ),
            (((), (-1, -1, -2), 10)),
            (((), (-1, -1, -1), 10)),
            (((), (-1, -1, -1, -2), 10)),
            (((), (-1, -1, -1, -1), 10)),
            (((), (-1, -1, -1, -1, -2), 10)),
            (((-3,) * 1, (-1,), 10)),
            (((-3,) * 1, (-1, -2), 10)),
            (
                (
                    (-3,) * 1,
                    (
                        -1,
                        -1,
                    ),
                    10,
                )
            ),
            (((-3,) * 1, (-1, -1, -2), 10)),
            (((-3,) * 1, (-1, -1, -1), 10)),
            (((-3,) * 1, (-1, -1, -1, -2), 10)),
            (((-3,) * 1, (-1, -1, -1, -1), 10)),
            (((-3,) * 1, (-1, -1, -1, -1, -2), 10)),
            (((-3,) * 2, (-1,), 10)),
            (((-3,) * 2, (-1, -2), 10)),
            (
                (
                    (-3,) * 2,
                    (
                        -1,
                        -1,
                    ),
                    10,
                )
            ),
            (((-3,) * 2, (-1, -1, -2), 10)),
            (((-3,) * 2, (-1, -1, -1), 10)),
            (((-3,) * 2, (-1, -1, -1, -2), 10)),
            (((-3,) * 2, (-1, -1, -1, -1), 10)),
            (((-3,) * 2, (-1, -1, -1, -1, -2), 10)),
            (((-3,) * 3, (-1, -2), 10)),
            (((-3,) * 4, (-1, -2), 10)),
            (((-3,) * 5, (-1, -2), 10)),
            (((-3,) * 6, (-1, -2), 10)),
            (((-3,) * 7, (-1, -2), 10)),
            (((-3,) * 8, (-1, -2), 10)),
        ],
    )
    def test_residues(ZPK):
        print("ZPK: ", ZPK)
>       r_sci, zpk_sci = ZPK2residues_scipy(ZPK)

../../src/wield/control/fitting/SISO/test/residues/test_residues.py:80: 
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 

ZPK = ((), (-1, -1, -1, -2), 10), F_nyquist_Hz = None

    def ZPK2residues_scipy(
        ZPK,
        F_nyquist_Hz=None,
    ):
        """
        Useful for testing
        """
        residue_list = []
        b, a = scisig.zpk2tf(*ZPK)
        if F_nyquist_Hz is None:
            r, p, k = scisig.residue(b, a)
        else:
            r, p, k = scisig.residuez(b, a)

        # some indexing tricks to change the output to the form above
        same = p[1:] == p[:-1]
        same_adj = np.concatenate([[False], same, [False]])
        same_shift = ~(same_adj[1:] | same_adj[:-1])
        same_starts = ~same_adj[:-1] & same_adj[1:]
        same_ends = same_adj[:-1] & ~same_adj[1:]
        # the addition of same_adj puts all of the non-multiple back in
        for idx_start, idx_end in zip(
            np.argwhere(same_starts | same_shift), np.argwhere(same_ends | same_shift)
        ):
            idx_start = int(idx_start)
            idx_end = int(idx_end)
            pole = p[idx_start]
            res = r[idx_start : idx_end + 1]
            residue_list.append((pole,) + tuple(res))

        if len(k) < 2:
>           return residue_list, ((), (), k[0])
E           IndexError: index 0 is out of bounds for axis 0 with size 0

../../src/wield/control/fitting/SISO/representations/residues.py:310: IndexError
test_residues[ZPK9]
output
ZPK:  ((-3,), (-1, -2), 10)
captured errors:
ZPK = ((-3,), (-1, -2), 10)

    @pytest.mark.parametrize(
        "ZPK",
        [
            (((), (-1,), 10)),
            (((), (-1, -2), 10)),
            (
                (
                    (),
                    (
                        -1,
                        -1,
                    ),
                    10,
                )
            ),
            (((), (-1, -1, -2), 10)),
            (((), (-1, -1, -1), 10)),
            (((), (-1, -1, -1, -2), 10)),
            (((), (-1, -1, -1, -1), 10)),
            (((), (-1, -1, -1, -1, -2), 10)),
            (((-3,) * 1, (-1,), 10)),
            (((-3,) * 1, (-1, -2), 10)),
            (
                (
                    (-3,) * 1,
                    (
                        -1,
                        -1,
                    ),
                    10,
                )
            ),
            (((-3,) * 1, (-1, -1, -2), 10)),
            (((-3,) * 1, (-1, -1, -1), 10)),
            (((-3,) * 1, (-1, -1, -1, -2), 10)),
            (((-3,) * 1, (-1, -1, -1, -1), 10)),
            (((-3,) * 1, (-1, -1, -1, -1, -2), 10)),
            (((-3,) * 2, (-1,), 10)),
            (((-3,) * 2, (-1, -2), 10)),
            (
                (
                    (-3,) * 2,
                    (
                        -1,
                        -1,
                    ),
                    10,
                )
            ),
            (((-3,) * 2, (-1, -1, -2), 10)),
            (((-3,) * 2, (-1, -1, -1), 10)),
            (((-3,) * 2, (-1, -1, -1, -2), 10)),
            (((-3,) * 2, (-1, -1, -1, -1), 10)),
            (((-3,) * 2, (-1, -1, -1, -1, -2), 10)),
            (((-3,) * 3, (-1, -2), 10)),
            (((-3,) * 4, (-1, -2), 10)),
            (((-3,) * 5, (-1, -2), 10)),
            (((-3,) * 6, (-1, -2), 10)),
            (((-3,) * 7, (-1, -2), 10)),
            (((-3,) * 8, (-1, -2), 10)),
        ],
    )
    def test_residues(ZPK):
        print("ZPK: ", ZPK)
>       r_sci, zpk_sci = ZPK2residues_scipy(ZPK)

../../src/wield/control/fitting/SISO/test/residues/test_residues.py:80: 
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 

ZPK = ((-3,), (-1, -2), 10), F_nyquist_Hz = None

    def ZPK2residues_scipy(
        ZPK,
        F_nyquist_Hz=None,
    ):
        """
        Useful for testing
        """
        residue_list = []
        b, a = scisig.zpk2tf(*ZPK)
        if F_nyquist_Hz is None:
            r, p, k = scisig.residue(b, a)
        else:
            r, p, k = scisig.residuez(b, a)

        # some indexing tricks to change the output to the form above
        same = p[1:] == p[:-1]
        same_adj = np.concatenate([[False], same, [False]])
        same_shift = ~(same_adj[1:] | same_adj[:-1])
        same_starts = ~same_adj[:-1] & same_adj[1:]
        same_ends = same_adj[:-1] & ~same_adj[1:]
        # the addition of same_adj puts all of the non-multiple back in
        for idx_start, idx_end in zip(
            np.argwhere(same_starts | same_shift), np.argwhere(same_ends | same_shift)
        ):
            idx_start = int(idx_start)
            idx_end = int(idx_end)
            pole = p[idx_start]
            res = r[idx_start : idx_end + 1]
            residue_list.append((pole,) + tuple(res))

        if len(k) < 2:
>           return residue_list, ((), (), k[0])
E           IndexError: index 0 is out of bounds for axis 0 with size 0

../../src/wield/control/fitting/SISO/representations/residues.py:310: IndexError
test_residues[ZPK21]
output
ZPK:  ((-3, -3), (-1, -1, -1, -2), 10)
captured errors:
ZPK = ((-3, -3), (-1, -1, -1, -2), 10)

    @pytest.mark.parametrize(
        "ZPK",
        [
            (((), (-1,), 10)),
            (((), (-1, -2), 10)),
            (
                (
                    (),
                    (
                        -1,
                        -1,
                    ),
                    10,
                )
            ),
            (((), (-1, -1, -2), 10)),
            (((), (-1, -1, -1), 10)),
            (((), (-1, -1, -1, -2), 10)),
            (((), (-1, -1, -1, -1), 10)),
            (((), (-1, -1, -1, -1, -2), 10)),
            (((-3,) * 1, (-1,), 10)),
            (((-3,) * 1, (-1, -2), 10)),
            (
                (
                    (-3,) * 1,
                    (
                        -1,
                        -1,
                    ),
                    10,
                )
            ),
            (((-3,) * 1, (-1, -1, -2), 10)),
            (((-3,) * 1, (-1, -1, -1), 10)),
            (((-3,) * 1, (-1, -1, -1, -2), 10)),
            (((-3,) * 1, (-1, -1, -1, -1), 10)),
            (((-3,) * 1, (-1, -1, -1, -1, -2), 10)),
            (((-3,) * 2, (-1,), 10)),
            (((-3,) * 2, (-1, -2), 10)),
            (
                (
                    (-3,) * 2,
                    (
                        -1,
                        -1,
                    ),
                    10,
                )
            ),
            (((-3,) * 2, (-1, -1, -2), 10)),
            (((-3,) * 2, (-1, -1, -1), 10)),
            (((-3,) * 2, (-1, -1, -1, -2), 10)),
            (((-3,) * 2, (-1, -1, -1, -1), 10)),
            (((-3,) * 2, (-1, -1, -1, -1, -2), 10)),
            (((-3,) * 3, (-1, -2), 10)),
            (((-3,) * 4, (-1, -2), 10)),
            (((-3,) * 5, (-1, -2), 10)),
            (((-3,) * 6, (-1, -2), 10)),
            (((-3,) * 7, (-1, -2), 10)),
            (((-3,) * 8, (-1, -2), 10)),
        ],
    )
    def test_residues(ZPK):
        print("ZPK: ", ZPK)
>       r_sci, zpk_sci = ZPK2residues_scipy(ZPK)

../../src/wield/control/fitting/SISO/test/residues/test_residues.py:80: 
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 

ZPK = ((-3, -3), (-1, -1, -1, -2), 10), F_nyquist_Hz = None

    def ZPK2residues_scipy(
        ZPK,
        F_nyquist_Hz=None,
    ):
        """
        Useful for testing
        """
        residue_list = []
        b, a = scisig.zpk2tf(*ZPK)
        if F_nyquist_Hz is None:
            r, p, k = scisig.residue(b, a)
        else:
            r, p, k = scisig.residuez(b, a)

        # some indexing tricks to change the output to the form above
        same = p[1:] == p[:-1]
        same_adj = np.concatenate([[False], same, [False]])
        same_shift = ~(same_adj[1:] | same_adj[:-1])
        same_starts = ~same_adj[:-1] & same_adj[1:]
        same_ends = same_adj[:-1] & ~same_adj[1:]
        # the addition of same_adj puts all of the non-multiple back in
        for idx_start, idx_end in zip(
            np.argwhere(same_starts | same_shift), np.argwhere(same_ends | same_shift)
        ):
            idx_start = int(idx_start)
            idx_end = int(idx_end)
            pole = p[idx_start]
            res = r[idx_start : idx_end + 1]
            residue_list.append((pole,) + tuple(res))

        if len(k) < 2:
>           return residue_list, ((), (), k[0])
E           IndexError: index 0 is out of bounds for axis 0 with size 0

../../src/wield/control/fitting/SISO/representations/residues.py:310: IndexError
test_residues[ZPK27]
output
ZPK:  ((-3, -3, -3, -3, -3, -3), (-1, -2), 10)
r_sci:  [(-1.0, 640.0), (-2.0, -10.0)]
r_std:  [(-2, -10.0), (-1, 640.0)]

zpk_sci:  (((-2.484436493304871-2.229300816165238j), (-5.015563506695129-1.3632754123807578j), (-5.015563506695137+1.363275412380754j), (-2.484436493304865+2.2293008161652432j)), (), (10+0j))
zpk_std:  (((-2.484436493304871-2.229300816165238j), (-5.015563506695129-1.3632754123807578j), (-5.015563506695137+1.363275412380754j), (-2.484436493304865+2.2293008161652432j)), (), (10+0j))
ZPK recomp:  (((-2.994994843255661-0.010644097007477501j), (-3.006736835111709-0.009688638363545278j), (-2.9883006797254437-0.001019278604737983j), (-3.0117760186515206+0.0010246182916762957j), (-2.993229440065107+0.009619546403573764j), (-3.004962183190546+0.010707849280506672j)), (-2, -1), (10+0j))
test_residues[ZPK19]
output
ZPK:  ((-3, -3), (-1, -1, -2), 10)
captured errors:
ZPK = ((-3, -3), (-1, -1, -2), 10)

    @pytest.mark.parametrize(
        "ZPK",
        [
            (((), (-1,), 10)),
            (((), (-1, -2), 10)),
            (
                (
                    (),
                    (
                        -1,
                        -1,
                    ),
                    10,
                )
            ),
            (((), (-1, -1, -2), 10)),
            (((), (-1, -1, -1), 10)),
            (((), (-1, -1, -1, -2), 10)),
            (((), (-1, -1, -1, -1), 10)),
            (((), (-1, -1, -1, -1, -2), 10)),
            (((-3,) * 1, (-1,), 10)),
            (((-3,) * 1, (-1, -2), 10)),
            (
                (
                    (-3,) * 1,
                    (
                        -1,
                        -1,
                    ),
                    10,
                )
            ),
            (((-3,) * 1, (-1, -1, -2), 10)),
            (((-3,) * 1, (-1, -1, -1), 10)),
            (((-3,) * 1, (-1, -1, -1, -2), 10)),
            (((-3,) * 1, (-1, -1, -1, -1), 10)),
            (((-3,) * 1, (-1, -1, -1, -1, -2), 10)),
            (((-3,) * 2, (-1,), 10)),
            (((-3,) * 2, (-1, -2), 10)),
            (
                (
                    (-3,) * 2,
                    (
                        -1,
                        -1,
                    ),
                    10,
                )
            ),
            (((-3,) * 2, (-1, -1, -2), 10)),
            (((-3,) * 2, (-1, -1, -1), 10)),
            (((-3,) * 2, (-1, -1, -1, -2), 10)),
            (((-3,) * 2, (-1, -1, -1, -1), 10)),
            (((-3,) * 2, (-1, -1, -1, -1, -2), 10)),
            (((-3,) * 3, (-1, -2), 10)),
            (((-3,) * 4, (-1, -2), 10)),
            (((-3,) * 5, (-1, -2), 10)),
            (((-3,) * 6, (-1, -2), 10)),
            (((-3,) * 7, (-1, -2), 10)),
            (((-3,) * 8, (-1, -2), 10)),
        ],
    )
    def test_residues(ZPK):
        print("ZPK: ", ZPK)
>       r_sci, zpk_sci = ZPK2residues_scipy(ZPK)

../../src/wield/control/fitting/SISO/test/residues/test_residues.py:80: 
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 

ZPK = ((-3, -3), (-1, -1, -2), 10), F_nyquist_Hz = None

    def ZPK2residues_scipy(
        ZPK,
        F_nyquist_Hz=None,
    ):
        """
        Useful for testing
        """
        residue_list = []
        b, a = scisig.zpk2tf(*ZPK)
        if F_nyquist_Hz is None:
            r, p, k = scisig.residue(b, a)
        else:
            r, p, k = scisig.residuez(b, a)

        # some indexing tricks to change the output to the form above
        same = p[1:] == p[:-1]
        same_adj = np.concatenate([[False], same, [False]])
        same_shift = ~(same_adj[1:] | same_adj[:-1])
        same_starts = ~same_adj[:-1] & same_adj[1:]
        same_ends = same_adj[:-1] & ~same_adj[1:]
        # the addition of same_adj puts all of the non-multiple back in
        for idx_start, idx_end in zip(
            np.argwhere(same_starts | same_shift), np.argwhere(same_ends | same_shift)
        ):
            idx_start = int(idx_start)
            idx_end = int(idx_end)
            pole = p[idx_start]
            res = r[idx_start : idx_end + 1]
            residue_list.append((pole,) + tuple(res))

        if len(k) < 2:
>           return residue_list, ((), (), k[0])
E           IndexError: index 0 is out of bounds for axis 0 with size 0

../../src/wield/control/fitting/SISO/representations/residues.py:310: IndexError
test_residues[ZPK18]
output
ZPK:  ((-3, -3), (-1, -1), 10)
r_sci:  [(-1.0, 40.0, 40.0)]
r_std:  [(-1, 40.0, 40.0)]

zpk_sci:  ((), (), 10)
zpk_std:  ((), (), 10)
ZPK recomp:  (((-2.999999942861552-1.6816987138699693e-08j), (-3.000000057138449+1.6816988246404208e-08j)), (-1, -1), (10+0j))
test_residues[ZPK17]
output
ZPK:  ((-3, -3), (-1, -2), 10)
r_sci:  [(-1.0, 40.0), (-2.0, -10.0)]
r_std:  [(-2, -10.0), (-1, 40.0)]

zpk_sci:  ((), (), 10)
zpk_std:  ((), (), 10)
ZPK recomp:  (((-3.0000000426031335-2.9225507791608152e-08j), (-2.999999957396867+2.9225507208028186e-08j)), (-2, -1), (10+0j))
test_residues[ZPK12]
output
ZPK:  ((-3,), (-1, -1, -1), 10)
captured errors:
ZPK = ((-3,), (-1, -1, -1), 10)

    @pytest.mark.parametrize(
        "ZPK",
        [
            (((), (-1,), 10)),
            (((), (-1, -2), 10)),
            (
                (
                    (),
                    (
                        -1,
                        -1,
                    ),
                    10,
                )
            ),
            (((), (-1, -1, -2), 10)),
            (((), (-1, -1, -1), 10)),
            (((), (-1, -1, -1, -2), 10)),
            (((), (-1, -1, -1, -1), 10)),
            (((), (-1, -1, -1, -1, -2), 10)),
            (((-3,) * 1, (-1,), 10)),
            (((-3,) * 1, (-1, -2), 10)),
            (
                (
                    (-3,) * 1,
                    (
                        -1,
                        -1,
                    ),
                    10,
                )
            ),
            (((-3,) * 1, (-1, -1, -2), 10)),
            (((-3,) * 1, (-1, -1, -1), 10)),
            (((-3,) * 1, (-1, -1, -1, -2), 10)),
            (((-3,) * 1, (-1, -1, -1, -1), 10)),
            (((-3,) * 1, (-1, -1, -1, -1, -2), 10)),
            (((-3,) * 2, (-1,), 10)),
            (((-3,) * 2, (-1, -2), 10)),
            (
                (
                    (-3,) * 2,
                    (
                        -1,
                        -1,
                    ),
                    10,
                )
            ),
            (((-3,) * 2, (-1, -1, -2), 10)),
            (((-3,) * 2, (-1, -1, -1), 10)),
            (((-3,) * 2, (-1, -1, -1, -2), 10)),
            (((-3,) * 2, (-1, -1, -1, -1), 10)),
            (((-3,) * 2, (-1, -1, -1, -1, -2), 10)),
            (((-3,) * 3, (-1, -2), 10)),
            (((-3,) * 4, (-1, -2), 10)),
            (((-3,) * 5, (-1, -2), 10)),
            (((-3,) * 6, (-1, -2), 10)),
            (((-3,) * 7, (-1, -2), 10)),
            (((-3,) * 8, (-1, -2), 10)),
        ],
    )
    def test_residues(ZPK):
        print("ZPK: ", ZPK)
>       r_sci, zpk_sci = ZPK2residues_scipy(ZPK)

../../src/wield/control/fitting/SISO/test/residues/test_residues.py:80: 
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 

ZPK = ((-3,), (-1, -1, -1), 10), F_nyquist_Hz = None

    def ZPK2residues_scipy(
        ZPK,
        F_nyquist_Hz=None,
    ):
        """
        Useful for testing
        """
        residue_list = []
        b, a = scisig.zpk2tf(*ZPK)
        if F_nyquist_Hz is None:
            r, p, k = scisig.residue(b, a)
        else:
            r, p, k = scisig.residuez(b, a)

        # some indexing tricks to change the output to the form above
        same = p[1:] == p[:-1]
        same_adj = np.concatenate([[False], same, [False]])
        same_shift = ~(same_adj[1:] | same_adj[:-1])
        same_starts = ~same_adj[:-1] & same_adj[1:]
        same_ends = same_adj[:-1] & ~same_adj[1:]
        # the addition of same_adj puts all of the non-multiple back in
        for idx_start, idx_end in zip(
            np.argwhere(same_starts | same_shift), np.argwhere(same_ends | same_shift)
        ):
            idx_start = int(idx_start)
            idx_end = int(idx_end)
            pole = p[idx_start]
            res = r[idx_start : idx_end + 1]
            residue_list.append((pole,) + tuple(res))

        if len(k) < 2:
>           return residue_list, ((), (), k[0])
E           IndexError: index 0 is out of bounds for axis 0 with size 0

../../src/wield/control/fitting/SISO/representations/residues.py:310: IndexError
test_residues[ZPK11]
output
ZPK:  ((-3,), (-1, -1, -2), 10)
captured errors:
ZPK = ((-3,), (-1, -1, -2), 10)

    @pytest.mark.parametrize(
        "ZPK",
        [
            (((), (-1,), 10)),
            (((), (-1, -2), 10)),
            (
                (
                    (),
                    (
                        -1,
                        -1,
                    ),
                    10,
                )
            ),
            (((), (-1, -1, -2), 10)),
            (((), (-1, -1, -1), 10)),
            (((), (-1, -1, -1, -2), 10)),
            (((), (-1, -1, -1, -1), 10)),
            (((), (-1, -1, -1, -1, -2), 10)),
            (((-3,) * 1, (-1,), 10)),
            (((-3,) * 1, (-1, -2), 10)),
            (
                (
                    (-3,) * 1,
                    (
                        -1,
                        -1,
                    ),
                    10,
                )
            ),
            (((-3,) * 1, (-1, -1, -2), 10)),
            (((-3,) * 1, (-1, -1, -1), 10)),
            (((-3,) * 1, (-1, -1, -1, -2), 10)),
            (((-3,) * 1, (-1, -1, -1, -1), 10)),
            (((-3,) * 1, (-1, -1, -1, -1, -2), 10)),
            (((-3,) * 2, (-1,), 10)),
            (((-3,) * 2, (-1, -2), 10)),
            (
                (
                    (-3,) * 2,
                    (
                        -1,
                        -1,
                    ),
                    10,
                )
            ),
            (((-3,) * 2, (-1, -1, -2), 10)),
            (((-3,) * 2, (-1, -1, -1), 10)),
            (((-3,) * 2, (-1, -1, -1, -2), 10)),
            (((-3,) * 2, (-1, -1, -1, -1), 10)),
            (((-3,) * 2, (-1, -1, -1, -1, -2), 10)),
            (((-3,) * 3, (-1, -2), 10)),
            (((-3,) * 4, (-1, -2), 10)),
            (((-3,) * 5, (-1, -2), 10)),
            (((-3,) * 6, (-1, -2), 10)),
            (((-3,) * 7, (-1, -2), 10)),
            (((-3,) * 8, (-1, -2), 10)),
        ],
    )
    def test_residues(ZPK):
        print("ZPK: ", ZPK)
>       r_sci, zpk_sci = ZPK2residues_scipy(ZPK)

../../src/wield/control/fitting/SISO/test/residues/test_residues.py:80: 
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 

ZPK = ((-3,), (-1, -1, -2), 10), F_nyquist_Hz = None

    def ZPK2residues_scipy(
        ZPK,
        F_nyquist_Hz=None,
    ):
        """
        Useful for testing
        """
        residue_list = []
        b, a = scisig.zpk2tf(*ZPK)
        if F_nyquist_Hz is None:
            r, p, k = scisig.residue(b, a)
        else:
            r, p, k = scisig.residuez(b, a)

        # some indexing tricks to change the output to the form above
        same = p[1:] == p[:-1]
        same_adj = np.concatenate([[False], same, [False]])
        same_shift = ~(same_adj[1:] | same_adj[:-1])
        same_starts = ~same_adj[:-1] & same_adj[1:]
        same_ends = same_adj[:-1] & ~same_adj[1:]
        # the addition of same_adj puts all of the non-multiple back in
        for idx_start, idx_end in zip(
            np.argwhere(same_starts | same_shift), np.argwhere(same_ends | same_shift)
        ):
            idx_start = int(idx_start)
            idx_end = int(idx_end)
            pole = p[idx_start]
            res = r[idx_start : idx_end + 1]
            residue_list.append((pole,) + tuple(res))

        if len(k) < 2:
>           return residue_list, ((), (), k[0])
E           IndexError: index 0 is out of bounds for axis 0 with size 0

../../src/wield/control/fitting/SISO/representations/residues.py:310: IndexError
test_residues[ZPK1]
output
ZPK:  ((), (-1, -2), 10)
captured errors:
ZPK = ((), (-1, -2), 10)

    @pytest.mark.parametrize(
        "ZPK",
        [
            (((), (-1,), 10)),
            (((), (-1, -2), 10)),
            (
                (
                    (),
                    (
                        -1,
                        -1,
                    ),
                    10,
                )
            ),
            (((), (-1, -1, -2), 10)),
            (((), (-1, -1, -1), 10)),
            (((), (-1, -1, -1, -2), 10)),
            (((), (-1, -1, -1, -1), 10)),
            (((), (-1, -1, -1, -1, -2), 10)),
            (((-3,) * 1, (-1,), 10)),
            (((-3,) * 1, (-1, -2), 10)),
            (
                (
                    (-3,) * 1,
                    (
                        -1,
                        -1,
                    ),
                    10,
                )
            ),
            (((-3,) * 1, (-1, -1, -2), 10)),
            (((-3,) * 1, (-1, -1, -1), 10)),
            (((-3,) * 1, (-1, -1, -1, -2), 10)),
            (((-3,) * 1, (-1, -1, -1, -1), 10)),
            (((-3,) * 1, (-1, -1, -1, -1, -2), 10)),
            (((-3,) * 2, (-1,), 10)),
            (((-3,) * 2, (-1, -2), 10)),
            (
                (
                    (-3,) * 2,
                    (
                        -1,
                        -1,
                    ),
                    10,
                )
            ),
            (((-3,) * 2, (-1, -1, -2), 10)),
            (((-3,) * 2, (-1, -1, -1), 10)),
            (((-3,) * 2, (-1, -1, -1, -2), 10)),
            (((-3,) * 2, (-1, -1, -1, -1), 10)),
            (((-3,) * 2, (-1, -1, -1, -1, -2), 10)),
            (((-3,) * 3, (-1, -2), 10)),
            (((-3,) * 4, (-1, -2), 10)),
            (((-3,) * 5, (-1, -2), 10)),
            (((-3,) * 6, (-1, -2), 10)),
            (((-3,) * 7, (-1, -2), 10)),
            (((-3,) * 8, (-1, -2), 10)),
        ],
    )
    def test_residues(ZPK):
        print("ZPK: ", ZPK)
>       r_sci, zpk_sci = ZPK2residues_scipy(ZPK)

../../src/wield/control/fitting/SISO/test/residues/test_residues.py:80: 
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 

ZPK = ((), (-1, -2), 10), F_nyquist_Hz = None

    def ZPK2residues_scipy(
        ZPK,
        F_nyquist_Hz=None,
    ):
        """
        Useful for testing
        """
        residue_list = []
        b, a = scisig.zpk2tf(*ZPK)
        if F_nyquist_Hz is None:
            r, p, k = scisig.residue(b, a)
        else:
            r, p, k = scisig.residuez(b, a)

        # some indexing tricks to change the output to the form above
        same = p[1:] == p[:-1]
        same_adj = np.concatenate([[False], same, [False]])
        same_shift = ~(same_adj[1:] | same_adj[:-1])
        same_starts = ~same_adj[:-1] & same_adj[1:]
        same_ends = same_adj[:-1] & ~same_adj[1:]
        # the addition of same_adj puts all of the non-multiple back in
        for idx_start, idx_end in zip(
            np.argwhere(same_starts | same_shift), np.argwhere(same_ends | same_shift)
        ):
            idx_start = int(idx_start)
            idx_end = int(idx_end)
            pole = p[idx_start]
            res = r[idx_start : idx_end + 1]
            residue_list.append((pole,) + tuple(res))

        if len(k) < 2:
>           return residue_list, ((), (), k[0])
E           IndexError: index 0 is out of bounds for axis 0 with size 0

../../src/wield/control/fitting/SISO/representations/residues.py:310: IndexError
test_residues[ZPK6]
output
ZPK:  ((), (-1, -1, -1, -1), 10)
captured errors:
ZPK = ((), (-1, -1, -1, -1), 10)

    @pytest.mark.parametrize(
        "ZPK",
        [
            (((), (-1,), 10)),
            (((), (-1, -2), 10)),
            (
                (
                    (),
                    (
                        -1,
                        -1,
                    ),
                    10,
                )
            ),
            (((), (-1, -1, -2), 10)),
            (((), (-1, -1, -1), 10)),
            (((), (-1, -1, -1, -2), 10)),
            (((), (-1, -1, -1, -1), 10)),
            (((), (-1, -1, -1, -1, -2), 10)),
            (((-3,) * 1, (-1,), 10)),
            (((-3,) * 1, (-1, -2), 10)),
            (
                (
                    (-3,) * 1,
                    (
                        -1,
                        -1,
                    ),
                    10,
                )
            ),
            (((-3,) * 1, (-1, -1, -2), 10)),
            (((-3,) * 1, (-1, -1, -1), 10)),
            (((-3,) * 1, (-1, -1, -1, -2), 10)),
            (((-3,) * 1, (-1, -1, -1, -1), 10)),
            (((-3,) * 1, (-1, -1, -1, -1, -2), 10)),
            (((-3,) * 2, (-1,), 10)),
            (((-3,) * 2, (-1, -2), 10)),
            (
                (
                    (-3,) * 2,
                    (
                        -1,
                        -1,
                    ),
                    10,
                )
            ),
            (((-3,) * 2, (-1, -1, -2), 10)),
            (((-3,) * 2, (-1, -1, -1), 10)),
            (((-3,) * 2, (-1, -1, -1, -2), 10)),
            (((-3,) * 2, (-1, -1, -1, -1), 10)),
            (((-3,) * 2, (-1, -1, -1, -1, -2), 10)),
            (((-3,) * 3, (-1, -2), 10)),
            (((-3,) * 4, (-1, -2), 10)),
            (((-3,) * 5, (-1, -2), 10)),
            (((-3,) * 6, (-1, -2), 10)),
            (((-3,) * 7, (-1, -2), 10)),
            (((-3,) * 8, (-1, -2), 10)),
        ],
    )
    def test_residues(ZPK):
        print("ZPK: ", ZPK)
>       r_sci, zpk_sci = ZPK2residues_scipy(ZPK)

../../src/wield/control/fitting/SISO/test/residues/test_residues.py:80: 
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 

ZPK = ((), (-1, -1, -1, -1), 10), F_nyquist_Hz = None

    def ZPK2residues_scipy(
        ZPK,
        F_nyquist_Hz=None,
    ):
        """
        Useful for testing
        """
        residue_list = []
        b, a = scisig.zpk2tf(*ZPK)
        if F_nyquist_Hz is None:
            r, p, k = scisig.residue(b, a)
        else:
            r, p, k = scisig.residuez(b, a)

        # some indexing tricks to change the output to the form above
        same = p[1:] == p[:-1]
        same_adj = np.concatenate([[False], same, [False]])
        same_shift = ~(same_adj[1:] | same_adj[:-1])
        same_starts = ~same_adj[:-1] & same_adj[1:]
        same_ends = same_adj[:-1] & ~same_adj[1:]
        # the addition of same_adj puts all of the non-multiple back in
        for idx_start, idx_end in zip(
            np.argwhere(same_starts | same_shift), np.argwhere(same_ends | same_shift)
        ):
            idx_start = int(idx_start)
            idx_end = int(idx_end)
            pole = p[idx_start]
            res = r[idx_start : idx_end + 1]
            residue_list.append((pole,) + tuple(res))

        if len(k) < 2:
>           return residue_list, ((), (), k[0])
E           IndexError: index 0 is out of bounds for axis 0 with size 0

../../src/wield/control/fitting/SISO/representations/residues.py:310: IndexError
test_residues[ZPK3]
output
ZPK:  ((), (-1, -1, -2), 10)
captured errors:
ZPK = ((), (-1, -1, -2), 10)

    @pytest.mark.parametrize(
        "ZPK",
        [
            (((), (-1,), 10)),
            (((), (-1, -2), 10)),
            (
                (
                    (),
                    (
                        -1,
                        -1,
                    ),
                    10,
                )
            ),
            (((), (-1, -1, -2), 10)),
            (((), (-1, -1, -1), 10)),
            (((), (-1, -1, -1, -2), 10)),
            (((), (-1, -1, -1, -1), 10)),
            (((), (-1, -1, -1, -1, -2), 10)),
            (((-3,) * 1, (-1,), 10)),
            (((-3,) * 1, (-1, -2), 10)),
            (
                (
                    (-3,) * 1,
                    (
                        -1,
                        -1,
                    ),
                    10,
                )
            ),
            (((-3,) * 1, (-1, -1, -2), 10)),
            (((-3,) * 1, (-1, -1, -1), 10)),
            (((-3,) * 1, (-1, -1, -1, -2), 10)),
            (((-3,) * 1, (-1, -1, -1, -1), 10)),
            (((-3,) * 1, (-1, -1, -1, -1, -2), 10)),
            (((-3,) * 2, (-1,), 10)),
            (((-3,) * 2, (-1, -2), 10)),
            (
                (
                    (-3,) * 2,
                    (
                        -1,
                        -1,
                    ),
                    10,
                )
            ),
            (((-3,) * 2, (-1, -1, -2), 10)),
            (((-3,) * 2, (-1, -1, -1), 10)),
            (((-3,) * 2, (-1, -1, -1, -2), 10)),
            (((-3,) * 2, (-1, -1, -1, -1), 10)),
            (((-3,) * 2, (-1, -1, -1, -1, -2), 10)),
            (((-3,) * 3, (-1, -2), 10)),
            (((-3,) * 4, (-1, -2), 10)),
            (((-3,) * 5, (-1, -2), 10)),
            (((-3,) * 6, (-1, -2), 10)),
            (((-3,) * 7, (-1, -2), 10)),
            (((-3,) * 8, (-1, -2), 10)),
        ],
    )
    def test_residues(ZPK):
        print("ZPK: ", ZPK)
>       r_sci, zpk_sci = ZPK2residues_scipy(ZPK)

../../src/wield/control/fitting/SISO/test/residues/test_residues.py:80: 
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 

ZPK = ((), (-1, -1, -2), 10), F_nyquist_Hz = None

    def ZPK2residues_scipy(
        ZPK,
        F_nyquist_Hz=None,
    ):
        """
        Useful for testing
        """
        residue_list = []
        b, a = scisig.zpk2tf(*ZPK)
        if F_nyquist_Hz is None:
            r, p, k = scisig.residue(b, a)
        else:
            r, p, k = scisig.residuez(b, a)

        # some indexing tricks to change the output to the form above
        same = p[1:] == p[:-1]
        same_adj = np.concatenate([[False], same, [False]])
        same_shift = ~(same_adj[1:] | same_adj[:-1])
        same_starts = ~same_adj[:-1] & same_adj[1:]
        same_ends = same_adj[:-1] & ~same_adj[1:]
        # the addition of same_adj puts all of the non-multiple back in
        for idx_start, idx_end in zip(
            np.argwhere(same_starts | same_shift), np.argwhere(same_ends | same_shift)
        ):
            idx_start = int(idx_start)
            idx_end = int(idx_end)
            pole = p[idx_start]
            res = r[idx_start : idx_end + 1]
            residue_list.append((pole,) + tuple(res))

        if len(k) < 2:
>           return residue_list, ((), (), k[0])
E           IndexError: index 0 is out of bounds for axis 0 with size 0

../../src/wield/control/fitting/SISO/representations/residues.py:310: IndexError
test_residues[ZPK22]
output
ZPK:  ((-3, -3), (-1, -1, -1, -1), 10)
captured errors:
ZPK = ((-3, -3), (-1, -1, -1, -1), 10)

    @pytest.mark.parametrize(
        "ZPK",
        [
            (((), (-1,), 10)),
            (((), (-1, -2), 10)),
            (
                (
                    (),
                    (
                        -1,
                        -1,
                    ),
                    10,
                )
            ),
            (((), (-1, -1, -2), 10)),
            (((), (-1, -1, -1), 10)),
            (((), (-1, -1, -1, -2), 10)),
            (((), (-1, -1, -1, -1), 10)),
            (((), (-1, -1, -1, -1, -2), 10)),
            (((-3,) * 1, (-1,), 10)),
            (((-3,) * 1, (-1, -2), 10)),
            (
                (
                    (-3,) * 1,
                    (
                        -1,
                        -1,
                    ),
                    10,
                )
            ),
            (((-3,) * 1, (-1, -1, -2), 10)),
            (((-3,) * 1, (-1, -1, -1), 10)),
            (((-3,) * 1, (-1, -1, -1, -2), 10)),
            (((-3,) * 1, (-1, -1, -1, -1), 10)),
            (((-3,) * 1, (-1, -1, -1, -1, -2), 10)),
            (((-3,) * 2, (-1,), 10)),
            (((-3,) * 2, (-1, -2), 10)),
            (
                (
                    (-3,) * 2,
                    (
                        -1,
                        -1,
                    ),
                    10,
                )
            ),
            (((-3,) * 2, (-1, -1, -2), 10)),
            (((-3,) * 2, (-1, -1, -1), 10)),
            (((-3,) * 2, (-1, -1, -1, -2), 10)),
            (((-3,) * 2, (-1, -1, -1, -1), 10)),
            (((-3,) * 2, (-1, -1, -1, -1, -2), 10)),
            (((-3,) * 3, (-1, -2), 10)),
            (((-3,) * 4, (-1, -2), 10)),
            (((-3,) * 5, (-1, -2), 10)),
            (((-3,) * 6, (-1, -2), 10)),
            (((-3,) * 7, (-1, -2), 10)),
            (((-3,) * 8, (-1, -2), 10)),
        ],
    )
    def test_residues(ZPK):
        print("ZPK: ", ZPK)
>       r_sci, zpk_sci = ZPK2residues_scipy(ZPK)

../../src/wield/control/fitting/SISO/test/residues/test_residues.py:80: 
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 

ZPK = ((-3, -3), (-1, -1, -1, -1), 10), F_nyquist_Hz = None

    def ZPK2residues_scipy(
        ZPK,
        F_nyquist_Hz=None,
    ):
        """
        Useful for testing
        """
        residue_list = []
        b, a = scisig.zpk2tf(*ZPK)
        if F_nyquist_Hz is None:
            r, p, k = scisig.residue(b, a)
        else:
            r, p, k = scisig.residuez(b, a)

        # some indexing tricks to change the output to the form above
        same = p[1:] == p[:-1]
        same_adj = np.concatenate([[False], same, [False]])
        same_shift = ~(same_adj[1:] | same_adj[:-1])
        same_starts = ~same_adj[:-1] & same_adj[1:]
        same_ends = same_adj[:-1] & ~same_adj[1:]
        # the addition of same_adj puts all of the non-multiple back in
        for idx_start, idx_end in zip(
            np.argwhere(same_starts | same_shift), np.argwhere(same_ends | same_shift)
        ):
            idx_start = int(idx_start)
            idx_end = int(idx_end)
            pole = p[idx_start]
            res = r[idx_start : idx_end + 1]
            residue_list.append((pole,) + tuple(res))

        if len(k) < 2:
>           return residue_list, ((), (), k[0])
E           IndexError: index 0 is out of bounds for axis 0 with size 0

../../src/wield/control/fitting/SISO/representations/residues.py:310: IndexError
test_residues[ZPK15]
output
ZPK:  ((-3,), (-1, -1, -1, -1, -2), 10)
captured errors:
ZPK = ((-3,), (-1, -1, -1, -1, -2), 10)

    @pytest.mark.parametrize(
        "ZPK",
        [
            (((), (-1,), 10)),
            (((), (-1, -2), 10)),
            (
                (
                    (),
                    (
                        -1,
                        -1,
                    ),
                    10,
                )
            ),
            (((), (-1, -1, -2), 10)),
            (((), (-1, -1, -1), 10)),
            (((), (-1, -1, -1, -2), 10)),
            (((), (-1, -1, -1, -1), 10)),
            (((), (-1, -1, -1, -1, -2), 10)),
            (((-3,) * 1, (-1,), 10)),
            (((-3,) * 1, (-1, -2), 10)),
            (
                (
                    (-3,) * 1,
                    (
                        -1,
                        -1,
                    ),
                    10,
                )
            ),
            (((-3,) * 1, (-1, -1, -2), 10)),
            (((-3,) * 1, (-1, -1, -1), 10)),
            (((-3,) * 1, (-1, -1, -1, -2), 10)),
            (((-3,) * 1, (-1, -1, -1, -1), 10)),
            (((-3,) * 1, (-1, -1, -1, -1, -2), 10)),
            (((-3,) * 2, (-1,), 10)),
            (((-3,) * 2, (-1, -2), 10)),
            (
                (
                    (-3,) * 2,
                    (
                        -1,
                        -1,
                    ),
                    10,
                )
            ),
            (((-3,) * 2, (-1, -1, -2), 10)),
            (((-3,) * 2, (-1, -1, -1), 10)),
            (((-3,) * 2, (-1, -1, -1, -2), 10)),
            (((-3,) * 2, (-1, -1, -1, -1), 10)),
            (((-3,) * 2, (-1, -1, -1, -1, -2), 10)),
            (((-3,) * 3, (-1, -2), 10)),
            (((-3,) * 4, (-1, -2), 10)),
            (((-3,) * 5, (-1, -2), 10)),
            (((-3,) * 6, (-1, -2), 10)),
            (((-3,) * 7, (-1, -2), 10)),
            (((-3,) * 8, (-1, -2), 10)),
        ],
    )
    def test_residues(ZPK):
        print("ZPK: ", ZPK)
>       r_sci, zpk_sci = ZPK2residues_scipy(ZPK)

../../src/wield/control/fitting/SISO/test/residues/test_residues.py:80: 
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 

ZPK = ((-3,), (-1, -1, -1, -1, -2), 10), F_nyquist_Hz = None

    def ZPK2residues_scipy(
        ZPK,
        F_nyquist_Hz=None,
    ):
        """
        Useful for testing
        """
        residue_list = []
        b, a = scisig.zpk2tf(*ZPK)
        if F_nyquist_Hz is None:
            r, p, k = scisig.residue(b, a)
        else:
            r, p, k = scisig.residuez(b, a)

        # some indexing tricks to change the output to the form above
        same = p[1:] == p[:-1]
        same_adj = np.concatenate([[False], same, [False]])
        same_shift = ~(same_adj[1:] | same_adj[:-1])
        same_starts = ~same_adj[:-1] & same_adj[1:]
        same_ends = same_adj[:-1] & ~same_adj[1:]
        # the addition of same_adj puts all of the non-multiple back in
        for idx_start, idx_end in zip(
            np.argwhere(same_starts | same_shift), np.argwhere(same_ends | same_shift)
        ):
            idx_start = int(idx_start)
            idx_end = int(idx_end)
            pole = p[idx_start]
            res = r[idx_start : idx_end + 1]
            residue_list.append((pole,) + tuple(res))

        if len(k) < 2:
>           return residue_list, ((), (), k[0])
E           IndexError: index 0 is out of bounds for axis 0 with size 0

../../src/wield/control/fitting/SISO/representations/residues.py:310: IndexError
test_residues[ZPK13]
output
ZPK:  ((-3,), (-1, -1, -1, -2), 10)
captured errors:
ZPK = ((-3,), (-1, -1, -1, -2), 10)

    @pytest.mark.parametrize(
        "ZPK",
        [
            (((), (-1,), 10)),
            (((), (-1, -2), 10)),
            (
                (
                    (),
                    (
                        -1,
                        -1,
                    ),
                    10,
                )
            ),
            (((), (-1, -1, -2), 10)),
            (((), (-1, -1, -1), 10)),
            (((), (-1, -1, -1, -2), 10)),
            (((), (-1, -1, -1, -1), 10)),
            (((), (-1, -1, -1, -1, -2), 10)),
            (((-3,) * 1, (-1,), 10)),
            (((-3,) * 1, (-1, -2), 10)),
            (
                (
                    (-3,) * 1,
                    (
                        -1,
                        -1,
                    ),
                    10,
                )
            ),
            (((-3,) * 1, (-1, -1, -2), 10)),
            (((-3,) * 1, (-1, -1, -1), 10)),
            (((-3,) * 1, (-1, -1, -1, -2), 10)),
            (((-3,) * 1, (-1, -1, -1, -1), 10)),
            (((-3,) * 1, (-1, -1, -1, -1, -2), 10)),
            (((-3,) * 2, (-1,), 10)),
            (((-3,) * 2, (-1, -2), 10)),
            (
                (
                    (-3,) * 2,
                    (
                        -1,
                        -1,
                    ),
                    10,
                )
            ),
            (((-3,) * 2, (-1, -1, -2), 10)),
            (((-3,) * 2, (-1, -1, -1), 10)),
            (((-3,) * 2, (-1, -1, -1, -2), 10)),
            (((-3,) * 2, (-1, -1, -1, -1), 10)),
            (((-3,) * 2, (-1, -1, -1, -1, -2), 10)),
            (((-3,) * 3, (-1, -2), 10)),
            (((-3,) * 4, (-1, -2), 10)),
            (((-3,) * 5, (-1, -2), 10)),
            (((-3,) * 6, (-1, -2), 10)),
            (((-3,) * 7, (-1, -2), 10)),
            (((-3,) * 8, (-1, -2), 10)),
        ],
    )
    def test_residues(ZPK):
        print("ZPK: ", ZPK)
>       r_sci, zpk_sci = ZPK2residues_scipy(ZPK)

../../src/wield/control/fitting/SISO/test/residues/test_residues.py:80: 
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 

ZPK = ((-3,), (-1, -1, -1, -2), 10), F_nyquist_Hz = None

    def ZPK2residues_scipy(
        ZPK,
        F_nyquist_Hz=None,
    ):
        """
        Useful for testing
        """
        residue_list = []
        b, a = scisig.zpk2tf(*ZPK)
        if F_nyquist_Hz is None:
            r, p, k = scisig.residue(b, a)
        else:
            r, p, k = scisig.residuez(b, a)

        # some indexing tricks to change the output to the form above
        same = p[1:] == p[:-1]
        same_adj = np.concatenate([[False], same, [False]])
        same_shift = ~(same_adj[1:] | same_adj[:-1])
        same_starts = ~same_adj[:-1] & same_adj[1:]
        same_ends = same_adj[:-1] & ~same_adj[1:]
        # the addition of same_adj puts all of the non-multiple back in
        for idx_start, idx_end in zip(
            np.argwhere(same_starts | same_shift), np.argwhere(same_ends | same_shift)
        ):
            idx_start = int(idx_start)
            idx_end = int(idx_end)
            pole = p[idx_start]
            res = r[idx_start : idx_end + 1]
            residue_list.append((pole,) + tuple(res))

        if len(k) < 2:
>           return residue_list, ((), (), k[0])
E           IndexError: index 0 is out of bounds for axis 0 with size 0

../../src/wield/control/fitting/SISO/representations/residues.py:310: IndexError
test_residues[ZPK16]
output
ZPK:  ((-3, -3), (-1,), 10)
r_sci:  [(-1.0, 40.0)]
r_std:  [(-1, 40.0)]

zpk_sci:  (((-5.000000000000001+0j),), (), (10+0j))
zpk_std:  (((-5.000000000000001+0j),), (), (10+0j))
ZPK recomp:  (((-0.17157287525381004-8.881943853189462e-18j), (-5.828427124746192+0j)), (-1,), (10+0j))
test_residues[ZPK29]
output
ZPK:  ((-3, -3, -3, -3, -3, -3, -3, -3), (-1, -2), 10)
r_sci:  [(-1.0, 2560.0), (-2.0, -10.0)]
r_std:  [(-2, -10.0), (-1, 2560.0)]

zpk_sci:  (((-3.617116345386272-2.1787096830033477j), (-1.7780132294879458-1.7673740213675706j), (-5.104870425125819-0.9665282941544592j), (-5.104870425125726+0.9665282941544675j), (-1.7780132294879432+1.7673740213675706j), (-3.6171163453862993+2.178709683003345j)), (), (10+0j))
zpk_std:  (((-3.617116345386272-2.1787096830033477j), (-1.7780132294879458-1.7673740213675706j), (-5.104870425125819-0.9665282941544592j), (-5.104870425125726+0.9665282941544675j), (-1.7780132294879432+1.7673740213675706j), (-3.6171163453862993+2.178709683003345j)), (), (10+0j))
ZPK recomp:  (((-2.9972822779720887-0.04657400820877118j), (-3.031791559253008-0.03507272246387658j), (-2.9658599118822013-0.030594650387809334j), (-3.0475148159646097-0.001547857779190978j), (-2.954649558463338+0.0017707372585336336j), (-3.033916731829531+0.03275534197404717j), (-2.968427631274626+0.032908843462590355j), (-3.0005575133605924+0.04635431614447862j)), (-2, -1), (10+0j))
test_residues[ZPK7]
output
ZPK:  ((), (-1, -1, -1, -1, -2), 10)
captured errors:
ZPK = ((), (-1, -1, -1, -1, -2), 10)

    @pytest.mark.parametrize(
        "ZPK",
        [
            (((), (-1,), 10)),
            (((), (-1, -2), 10)),
            (
                (
                    (),
                    (
                        -1,
                        -1,
                    ),
                    10,
                )
            ),
            (((), (-1, -1, -2), 10)),
            (((), (-1, -1, -1), 10)),
            (((), (-1, -1, -1, -2), 10)),
            (((), (-1, -1, -1, -1), 10)),
            (((), (-1, -1, -1, -1, -2), 10)),
            (((-3,) * 1, (-1,), 10)),
            (((-3,) * 1, (-1, -2), 10)),
            (
                (
                    (-3,) * 1,
                    (
                        -1,
                        -1,
                    ),
                    10,
                )
            ),
            (((-3,) * 1, (-1, -1, -2), 10)),
            (((-3,) * 1, (-1, -1, -1), 10)),
            (((-3,) * 1, (-1, -1, -1, -2), 10)),
            (((-3,) * 1, (-1, -1, -1, -1), 10)),
            (((-3,) * 1, (-1, -1, -1, -1, -2), 10)),
            (((-3,) * 2, (-1,), 10)),
            (((-3,) * 2, (-1, -2), 10)),
            (
                (
                    (-3,) * 2,
                    (
                        -1,
                        -1,
                    ),
                    10,
                )
            ),
            (((-3,) * 2, (-1, -1, -2), 10)),
            (((-3,) * 2, (-1, -1, -1), 10)),
            (((-3,) * 2, (-1, -1, -1, -2), 10)),
            (((-3,) * 2, (-1, -1, -1, -1), 10)),
            (((-3,) * 2, (-1, -1, -1, -1, -2), 10)),
            (((-3,) * 3, (-1, -2), 10)),
            (((-3,) * 4, (-1, -2), 10)),
            (((-3,) * 5, (-1, -2), 10)),
            (((-3,) * 6, (-1, -2), 10)),
            (((-3,) * 7, (-1, -2), 10)),
            (((-3,) * 8, (-1, -2), 10)),
        ],
    )
    def test_residues(ZPK):
        print("ZPK: ", ZPK)
>       r_sci, zpk_sci = ZPK2residues_scipy(ZPK)

../../src/wield/control/fitting/SISO/test/residues/test_residues.py:80: 
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 

ZPK = ((), (-1, -1, -1, -1, -2), 10), F_nyquist_Hz = None

    def ZPK2residues_scipy(
        ZPK,
        F_nyquist_Hz=None,
    ):
        """
        Useful for testing
        """
        residue_list = []
        b, a = scisig.zpk2tf(*ZPK)
        if F_nyquist_Hz is None:
            r, p, k = scisig.residue(b, a)
        else:
            r, p, k = scisig.residuez(b, a)

        # some indexing tricks to change the output to the form above
        same = p[1:] == p[:-1]
        same_adj = np.concatenate([[False], same, [False]])
        same_shift = ~(same_adj[1:] | same_adj[:-1])
        same_starts = ~same_adj[:-1] & same_adj[1:]
        same_ends = same_adj[:-1] & ~same_adj[1:]
        # the addition of same_adj puts all of the non-multiple back in
        for idx_start, idx_end in zip(
            np.argwhere(same_starts | same_shift), np.argwhere(same_ends | same_shift)
        ):
            idx_start = int(idx_start)
            idx_end = int(idx_end)
            pole = p[idx_start]
            res = r[idx_start : idx_end + 1]
            residue_list.append((pole,) + tuple(res))

        if len(k) < 2:
>           return residue_list, ((), (), k[0])
E           IndexError: index 0 is out of bounds for axis 0 with size 0

../../src/wield/control/fitting/SISO/representations/residues.py:310: IndexError
test_residues[ZPK23]
output
ZPK:  ((-3, -3), (-1, -1, -1, -1, -2), 10)
captured errors:
ZPK = ((-3, -3), (-1, -1, -1, -1, -2), 10)

    @pytest.mark.parametrize(
        "ZPK",
        [
            (((), (-1,), 10)),
            (((), (-1, -2), 10)),
            (
                (
                    (),
                    (
                        -1,
                        -1,
                    ),
                    10,
                )
            ),
            (((), (-1, -1, -2), 10)),
            (((), (-1, -1, -1), 10)),
            (((), (-1, -1, -1, -2), 10)),
            (((), (-1, -1, -1, -1), 10)),
            (((), (-1, -1, -1, -1, -2), 10)),
            (((-3,) * 1, (-1,), 10)),
            (((-3,) * 1, (-1, -2), 10)),
            (
                (
                    (-3,) * 1,
                    (
                        -1,
                        -1,
                    ),
                    10,
                )
            ),
            (((-3,) * 1, (-1, -1, -2), 10)),
            (((-3,) * 1, (-1, -1, -1), 10)),
            (((-3,) * 1, (-1, -1, -1, -2), 10)),
            (((-3,) * 1, (-1, -1, -1, -1), 10)),
            (((-3,) * 1, (-1, -1, -1, -1, -2), 10)),
            (((-3,) * 2, (-1,), 10)),
            (((-3,) * 2, (-1, -2), 10)),
            (
                (
                    (-3,) * 2,
                    (
                        -1,
                        -1,
                    ),
                    10,
                )
            ),
            (((-3,) * 2, (-1, -1, -2), 10)),
            (((-3,) * 2, (-1, -1, -1), 10)),
            (((-3,) * 2, (-1, -1, -1, -2), 10)),
            (((-3,) * 2, (-1, -1, -1, -1), 10)),
            (((-3,) * 2, (-1, -1, -1, -1, -2), 10)),
            (((-3,) * 3, (-1, -2), 10)),
            (((-3,) * 4, (-1, -2), 10)),
            (((-3,) * 5, (-1, -2), 10)),
            (((-3,) * 6, (-1, -2), 10)),
            (((-3,) * 7, (-1, -2), 10)),
            (((-3,) * 8, (-1, -2), 10)),
        ],
    )
    def test_residues(ZPK):
        print("ZPK: ", ZPK)
>       r_sci, zpk_sci = ZPK2residues_scipy(ZPK)

../../src/wield/control/fitting/SISO/test/residues/test_residues.py:80: 
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 

ZPK = ((-3, -3), (-1, -1, -1, -1, -2), 10), F_nyquist_Hz = None

    def ZPK2residues_scipy(
        ZPK,
        F_nyquist_Hz=None,
    ):
        """
        Useful for testing
        """
        residue_list = []
        b, a = scisig.zpk2tf(*ZPK)
        if F_nyquist_Hz is None:
            r, p, k = scisig.residue(b, a)
        else:
            r, p, k = scisig.residuez(b, a)

        # some indexing tricks to change the output to the form above
        same = p[1:] == p[:-1]
        same_adj = np.concatenate([[False], same, [False]])
        same_shift = ~(same_adj[1:] | same_adj[:-1])
        same_starts = ~same_adj[:-1] & same_adj[1:]
        same_ends = same_adj[:-1] & ~same_adj[1:]
        # the addition of same_adj puts all of the non-multiple back in
        for idx_start, idx_end in zip(
            np.argwhere(same_starts | same_shift), np.argwhere(same_ends | same_shift)
        ):
            idx_start = int(idx_start)
            idx_end = int(idx_end)
            pole = p[idx_start]
            res = r[idx_start : idx_end + 1]
            residue_list.append((pole,) + tuple(res))

        if len(k) < 2:
>           return residue_list, ((), (), k[0])
E           IndexError: index 0 is out of bounds for axis 0 with size 0

../../src/wield/control/fitting/SISO/representations/residues.py:310: IndexError
test_residues[ZPK26]
output
ZPK:  ((-3, -3, -3, -3, -3), (-1, -2), 10)
r_sci:  [(-1.0, 320.0), (-2.0, -10.0)]
r_std:  [(-2, -10.0), (-1, 320.0)]

zpk_sci:  (((-3.221613367802889-2.4119820164233126j), (-5.556773264394224-7.181755190543981e-15j), (-3.221613367802892+2.4119820164233188j)), (), (10+0j))
zpk_std:  (((-3.221613367802889-2.4119820164233126j), (-5.556773264394224-7.181755190543981e-15j), (-3.221613367802892+2.4119820164233188j)), (), (10+0j))
ZPK recomp:  (((-3.2267064380587147-2.8520766031747837j), (-6.008686783276857-1.021405182655144e-14j), (-0.5204092238658515-3.9207414408749636e-16j), (-2.017491116739846+1.9449750141414914e-15j), (-3.2267064380587276+2.8520766031747957j)), (-2, -1), (10+0j))
test_residues[ZPK2]
output
ZPK:  ((), (-1, -1), 10)
captured errors:
ZPK = ((), (-1, -1), 10)

    @pytest.mark.parametrize(
        "ZPK",
        [
            (((), (-1,), 10)),
            (((), (-1, -2), 10)),
            (
                (
                    (),
                    (
                        -1,
                        -1,
                    ),
                    10,
                )
            ),
            (((), (-1, -1, -2), 10)),
            (((), (-1, -1, -1), 10)),
            (((), (-1, -1, -1, -2), 10)),
            (((), (-1, -1, -1, -1), 10)),
            (((), (-1, -1, -1, -1, -2), 10)),
            (((-3,) * 1, (-1,), 10)),
            (((-3,) * 1, (-1, -2), 10)),
            (
                (
                    (-3,) * 1,
                    (
                        -1,
                        -1,
                    ),
                    10,
                )
            ),
            (((-3,) * 1, (-1, -1, -2), 10)),
            (((-3,) * 1, (-1, -1, -1), 10)),
            (((-3,) * 1, (-1, -1, -1, -2), 10)),
            (((-3,) * 1, (-1, -1, -1, -1), 10)),
            (((-3,) * 1, (-1, -1, -1, -1, -2), 10)),
            (((-3,) * 2, (-1,), 10)),
            (((-3,) * 2, (-1, -2), 10)),
            (
                (
                    (-3,) * 2,
                    (
                        -1,
                        -1,
                    ),
                    10,
                )
            ),
            (((-3,) * 2, (-1, -1, -2), 10)),
            (((-3,) * 2, (-1, -1, -1), 10)),
            (((-3,) * 2, (-1, -1, -1, -2), 10)),
            (((-3,) * 2, (-1, -1, -1, -1), 10)),
            (((-3,) * 2, (-1, -1, -1, -1, -2), 10)),
            (((-3,) * 3, (-1, -2), 10)),
            (((-3,) * 4, (-1, -2), 10)),
            (((-3,) * 5, (-1, -2), 10)),
            (((-3,) * 6, (-1, -2), 10)),
            (((-3,) * 7, (-1, -2), 10)),
            (((-3,) * 8, (-1, -2), 10)),
        ],
    )
    def test_residues(ZPK):
        print("ZPK: ", ZPK)
>       r_sci, zpk_sci = ZPK2residues_scipy(ZPK)

../../src/wield/control/fitting/SISO/test/residues/test_residues.py:80: 
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 

ZPK = ((), (-1, -1), 10), F_nyquist_Hz = None

    def ZPK2residues_scipy(
        ZPK,
        F_nyquist_Hz=None,
    ):
        """
        Useful for testing
        """
        residue_list = []
        b, a = scisig.zpk2tf(*ZPK)
        if F_nyquist_Hz is None:
            r, p, k = scisig.residue(b, a)
        else:
            r, p, k = scisig.residuez(b, a)

        # some indexing tricks to change the output to the form above
        same = p[1:] == p[:-1]
        same_adj = np.concatenate([[False], same, [False]])
        same_shift = ~(same_adj[1:] | same_adj[:-1])
        same_starts = ~same_adj[:-1] & same_adj[1:]
        same_ends = same_adj[:-1] & ~same_adj[1:]
        # the addition of same_adj puts all of the non-multiple back in
        for idx_start, idx_end in zip(
            np.argwhere(same_starts | same_shift), np.argwhere(same_ends | same_shift)
        ):
            idx_start = int(idx_start)
            idx_end = int(idx_end)
            pole = p[idx_start]
            res = r[idx_start : idx_end + 1]
            residue_list.append((pole,) + tuple(res))

        if len(k) < 2:
>           return residue_list, ((), (), k[0])
E           IndexError: index 0 is out of bounds for axis 0 with size 0

../../src/wield/control/fitting/SISO/representations/residues.py:310: IndexError
test_residues[ZPK28]
output
ZPK:  ((-3, -3, -3, -3, -3, -3, -3), (-1, -2), 10)
r_sci:  [(-1.0, 1280.0), (-2.0, -10.0)]
r_std:  [(-2, -10.0), (-1, 1280.0)]

zpk_sci:  (((-2.0497031281572244-1.9885736236906268j), (-4.262180836313279-1.9659549789141488j), (-5.376232071058982+2.6480096098364158e-14j), (-4.2621808363132985+1.9659549789141266j), (-2.049703128157218+1.9885736236906317j)), (), (10+0j))
zpk_std:  (((-2.0497031281572244-1.9885736236906268j), (-4.262180836313279-1.9659549789141488j), (-5.376232071058982+2.6480096098364158e-14j), (-4.2621808363132985+1.9659549789141266j), (-2.049703128157218+1.9885736236906317j)), (), (10+0j))
ZPK recomp:  (((-1.9138433922460387-2.2209844989292526j), (-4.402051461335901-2.2020719292245423j), (-2.004047199734962-6.868627224127691e-15j), (-0.7107876001758108+9.150816562910063e-16j), (-5.65337549292537+7.327471962526033e-14j), (-4.40205146133589+2.202071929224482j), (-1.913843392246034+2.220984498929251j)), (-2, -1), (10+0j))
test_residues[ZPK25]
output
ZPK:  ((-3, -3, -3, -3), (-1, -2), 10)
r_sci:  [(-1.0, 160.0), (-2.0, -10.0)]
r_std:  [(-2, -10.0), (-1, 160.0)]

zpk_sci:  (((-4.5-2.17944947177034j), (-4.499999999999997+2.1794494717703388j)), (), (10+0j))
zpk_std:  (((-4.5-2.17944947177034j), (-4.499999999999997+2.1794494717703388j)), (), (10+0j))
ZPK recomp:  (((-3.000248187227096-0.00048638352367337296j), (-2.9995137092024513-0.0002482151326452242j), (-3.0004864114265555+0.000248279965512741j), (-2.9997516921439047+0.0004863186908069564j)), (-2, -1), (10+0j))
test_residues[ZPK24]
output
ZPK:  ((-3, -3, -3), (-1, -2), 10)
r_sci:  [(-1.0, 80.0), (-2.0, -10.0)]
r_std:  [(-2, -10.0), (-1, 80.0)]

zpk_sci:  (((-6+0j),), (), (10+0j))
zpk_std:  (((-6+0j),), (), (10+0j))
ZPK recomp:  (((-2.0888211923537545-6.416617623794963e-16j), (0.2019117766787086-6.585875615226833e-17j), (-7.113090584324958+8.881784197001252e-16j)), (-2, -1), (10+0j))
test_residues[ZPK4]
output
ZPK:  ((), (-1, -1, -1), 10)
captured errors:
ZPK = ((), (-1, -1, -1), 10)

    @pytest.mark.parametrize(
        "ZPK",
        [
            (((), (-1,), 10)),
            (((), (-1, -2), 10)),
            (
                (
                    (),
                    (
                        -1,
                        -1,
                    ),
                    10,
                )
            ),
            (((), (-1, -1, -2), 10)),
            (((), (-1, -1, -1), 10)),
            (((), (-1, -1, -1, -2), 10)),
            (((), (-1, -1, -1, -1), 10)),
            (((), (-1, -1, -1, -1, -2), 10)),
            (((-3,) * 1, (-1,), 10)),
            (((-3,) * 1, (-1, -2), 10)),
            (
                (
                    (-3,) * 1,
                    (
                        -1,
                        -1,
                    ),
                    10,
                )
            ),
            (((-3,) * 1, (-1, -1, -2), 10)),
            (((-3,) * 1, (-1, -1, -1), 10)),
            (((-3,) * 1, (-1, -1, -1, -2), 10)),
            (((-3,) * 1, (-1, -1, -1, -1), 10)),
            (((-3,) * 1, (-1, -1, -1, -1, -2), 10)),
            (((-3,) * 2, (-1,), 10)),
            (((-3,) * 2, (-1, -2), 10)),
            (
                (
                    (-3,) * 2,
                    (
                        -1,
                        -1,
                    ),
                    10,
                )
            ),
            (((-3,) * 2, (-1, -1, -2), 10)),
            (((-3,) * 2, (-1, -1, -1), 10)),
            (((-3,) * 2, (-1, -1, -1, -2), 10)),
            (((-3,) * 2, (-1, -1, -1, -1), 10)),
            (((-3,) * 2, (-1, -1, -1, -1, -2), 10)),
            (((-3,) * 3, (-1, -2), 10)),
            (((-3,) * 4, (-1, -2), 10)),
            (((-3,) * 5, (-1, -2), 10)),
            (((-3,) * 6, (-1, -2), 10)),
            (((-3,) * 7, (-1, -2), 10)),
            (((-3,) * 8, (-1, -2), 10)),
        ],
    )
    def test_residues(ZPK):
        print("ZPK: ", ZPK)
>       r_sci, zpk_sci = ZPK2residues_scipy(ZPK)

../../src/wield/control/fitting/SISO/test/residues/test_residues.py:80: 
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 

ZPK = ((), (-1, -1, -1), 10), F_nyquist_Hz = None

    def ZPK2residues_scipy(
        ZPK,
        F_nyquist_Hz=None,
    ):
        """
        Useful for testing
        """
        residue_list = []
        b, a = scisig.zpk2tf(*ZPK)
        if F_nyquist_Hz is None:
            r, p, k = scisig.residue(b, a)
        else:
            r, p, k = scisig.residuez(b, a)

        # some indexing tricks to change the output to the form above
        same = p[1:] == p[:-1]
        same_adj = np.concatenate([[False], same, [False]])
        same_shift = ~(same_adj[1:] | same_adj[:-1])
        same_starts = ~same_adj[:-1] & same_adj[1:]
        same_ends = same_adj[:-1] & ~same_adj[1:]
        # the addition of same_adj puts all of the non-multiple back in
        for idx_start, idx_end in zip(
            np.argwhere(same_starts | same_shift), np.argwhere(same_ends | same_shift)
        ):
            idx_start = int(idx_start)
            idx_end = int(idx_end)
            pole = p[idx_start]
            res = r[idx_start : idx_end + 1]
            residue_list.append((pole,) + tuple(res))

        if len(k) < 2:
>           return residue_list, ((), (), k[0])
E           IndexError: index 0 is out of bounds for axis 0 with size 0

../../src/wield/control/fitting/SISO/representations/residues.py:310: IndexError
test_residues[ZPK14]
output
ZPK:  ((-3,), (-1, -1, -1, -1), 10)
captured errors:
ZPK = ((-3,), (-1, -1, -1, -1), 10)

    @pytest.mark.parametrize(
        "ZPK",
        [
            (((), (-1,), 10)),
            (((), (-1, -2), 10)),
            (
                (
                    (),
                    (
                        -1,
                        -1,
                    ),
                    10,
                )
            ),
            (((), (-1, -1, -2), 10)),
            (((), (-1, -1, -1), 10)),
            (((), (-1, -1, -1, -2), 10)),
            (((), (-1, -1, -1, -1), 10)),
            (((), (-1, -1, -1, -1, -2), 10)),
            (((-3,) * 1, (-1,), 10)),
            (((-3,) * 1, (-1, -2), 10)),
            (
                (
                    (-3,) * 1,
                    (
                        -1,
                        -1,
                    ),
                    10,
                )
            ),
            (((-3,) * 1, (-1, -1, -2), 10)),
            (((-3,) * 1, (-1, -1, -1), 10)),
            (((-3,) * 1, (-1, -1, -1, -2), 10)),
            (((-3,) * 1, (-1, -1, -1, -1), 10)),
            (((-3,) * 1, (-1, -1, -1, -1, -2), 10)),
            (((-3,) * 2, (-1,), 10)),
            (((-3,) * 2, (-1, -2), 10)),
            (
                (
                    (-3,) * 2,
                    (
                        -1,
                        -1,
                    ),
                    10,
                )
            ),
            (((-3,) * 2, (-1, -1, -2), 10)),
            (((-3,) * 2, (-1, -1, -1), 10)),
            (((-3,) * 2, (-1, -1, -1, -2), 10)),
            (((-3,) * 2, (-1, -1, -1, -1), 10)),
            (((-3,) * 2, (-1, -1, -1, -1, -2), 10)),
            (((-3,) * 3, (-1, -2), 10)),
            (((-3,) * 4, (-1, -2), 10)),
            (((-3,) * 5, (-1, -2), 10)),
            (((-3,) * 6, (-1, -2), 10)),
            (((-3,) * 7, (-1, -2), 10)),
            (((-3,) * 8, (-1, -2), 10)),
        ],
    )
    def test_residues(ZPK):
        print("ZPK: ", ZPK)
>       r_sci, zpk_sci = ZPK2residues_scipy(ZPK)

../../src/wield/control/fitting/SISO/test/residues/test_residues.py:80: 
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 

ZPK = ((-3,), (-1, -1, -1, -1), 10), F_nyquist_Hz = None

    def ZPK2residues_scipy(
        ZPK,
        F_nyquist_Hz=None,
    ):
        """
        Useful for testing
        """
        residue_list = []
        b, a = scisig.zpk2tf(*ZPK)
        if F_nyquist_Hz is None:
            r, p, k = scisig.residue(b, a)
        else:
            r, p, k = scisig.residuez(b, a)

        # some indexing tricks to change the output to the form above
        same = p[1:] == p[:-1]
        same_adj = np.concatenate([[False], same, [False]])
        same_shift = ~(same_adj[1:] | same_adj[:-1])
        same_starts = ~same_adj[:-1] & same_adj[1:]
        same_ends = same_adj[:-1] & ~same_adj[1:]
        # the addition of same_adj puts all of the non-multiple back in
        for idx_start, idx_end in zip(
            np.argwhere(same_starts | same_shift), np.argwhere(same_ends | same_shift)
        ):
            idx_start = int(idx_start)
            idx_end = int(idx_end)
            pole = p[idx_start]
            res = r[idx_start : idx_end + 1]
            residue_list.append((pole,) + tuple(res))

        if len(k) < 2:
>           return residue_list, ((), (), k[0])
E           IndexError: index 0 is out of bounds for axis 0 with size 0

../../src/wield/control/fitting/SISO/representations/residues.py:310: IndexError