def test_nyquist_encirclements():
    # Example 14.14: effect of friction in a cart-pendulum system
    s = ct.tf('s')
    sys = (0.02 * s**3 - 0.1 * s) / (s**4 + s**3 + s**2 + 0.25 * s + 0.04)

    plt.figure()
    count = ct.nyquist_plot(sys)
    plt.title("Stable system; encirclements = %d" % count)
    assert _Z(sys) == count + _P(sys)

    plt.figure()
    count = ct.nyquist_plot(sys * 3)
    plt.title("Unstable system; encirclements = %d" % count)
    assert _Z(sys * 3) == count + _P(sys * 3)

    # System with pole at the origin
    sys = ct.tf([3], [1, 2, 2, 1, 0])

    plt.figure()
    count = ct.nyquist_plot(sys)
    plt.title("Pole at the origin; encirclements = %d" % count)
    assert _Z(sys) == count + _P(sys)

    # Non-integer number of encirclements
    plt.figure()
    sys = 1 / (s**2 + s + 1)
    with pytest.warns(UserWarning, match="encirclements was a non-integer"):
        count = ct.nyquist_plot(sys, omega_limits=[0.5, 1e3])
    with pytest.warns(None) as records:
        count = ct.nyquist_plot(sys,
                                omega_limits=[0.5, 1e3],
                                encirclement_threshold=0.2)
    assert len(records) == 0
    plt.title("Non-integer number of encirclements [%g]" % count)
Beispiel #2
0
def exercise_1():
    # system transfer function
    num = [1, 2]
    den = [1, 1, 5, 2]

    # create system
    sys_1 = system_1()

    # nyquist plot
    plt.figure()
    ctl.nyquist_plot([sys_1])

    # plot circle
    t = np.linspace(0, 2 * np.pi, 100)
    plt.plot(np.cos(t), np.sin(t))

    # save plot
    plt.savefig("plots/nyquist_plot.png")
    plt.clf()
    plt.figure()

    # bode plot
    ctl.bode_plot([sys_1], dB=True)

    # save plot
    plt.savefig("plots/bode_plot.png")
    plt.clf()
def test_nyquist_exceptions():
    # MIMO not implemented
    sys = ct.rss(2, 2, 2)
    with pytest.raises(ct.exception.ControlMIMONotImplemented,
                       match="only supports SISO"):
        ct.nyquist_plot(sys)

    # Legacy keywords for arrow size
    sys = ct.rss(2, 1, 1)
    with pytest.warns(FutureWarning, match="use `arrow_size` instead"):
        ct.nyquist_plot(sys, arrow_width=8, arrow_length=6)

    # Unknown arrow keyword
    with pytest.raises(ValueError, match="unsupported arrow location"):
        ct.nyquist_plot(sys, arrows='uniform')

    # Bad value for indent direction
    sys = ct.tf([1], [1, 0, 1])
    with pytest.raises(ValueError, match="unknown value for indent"):
        ct.nyquist_plot(sys, indent_direction='up')

    # Discrete time system sampled above Nyquist frequency
    sys = ct.drss(2, 1, 1)
    sys.dt = 0.01
    with pytest.warns(UserWarning, match="above Nyquist"):
        ct.nyquist_plot(sys, np.logspace(-2, 3))
Beispiel #4
0
def test_nyquist_fbs_examples():
    s = ct.tf('s')
    """Run through various examples from FBS2e to compare plots"""
    plt.figure()
    plt.title("Figure 10.4: L(s) = 1.4 e^{-s}/(s+1)^2")
    sys = ct.tf([1.4], [1, 2, 1]) * ct.tf(*ct.pade(1, 4))
    count = ct.nyquist_plot(sys)
    assert _Z(sys) == count + _P(sys)

    plt.figure()
    plt.title("Figure 10.4: L(s) = 1/(s + a)^2 with a = 0.6")
    sys = 1 / (s + 0.6)**3
    count = ct.nyquist_plot(sys)
    assert _Z(sys) == count + _P(sys)

    plt.figure()
    plt.title("Figure 10.6: L(s) = 1/(s (s+1)^2) - pole at the origin")
    sys = 1 / (s * (s + 1)**2)
    count = ct.nyquist_plot(sys)
    assert _Z(sys) == count + _P(sys)

    plt.figure()
    plt.title("Figure 10.10: L(s) = 3 (s+6)^2 / (s (s+1)^2)")
    sys = 3 * (s + 6)**2 / (s * (s + 1)**2)
    count = ct.nyquist_plot(sys)
    assert _Z(sys) == count + _P(sys)

    plt.figure()
    plt.title("Figure 10.10: L(s) = 3 (s+6)^2 / (s (s+1)^2) [zoom]")
    count = ct.nyquist_plot(sys, omega_limits=[1.5, 1e3])
    # Frequency limits for zoom give incorrect encirclement count
    # assert _Z(sys) == count + _P(sys)
    assert count == -1
def test_nyquist_indent_im():
    """Test system with poles on the imaginary axis."""
    sys = ct.tf([1, 1], [1, 0, 1])

    # Imaginary poles with standard indentation
    plt.figure()
    count = ct.nyquist_plot(sys)
    plt.title("Imaginary poles; encirclements = %d" % count)
    assert _Z(sys) == count + _P(sys)

    # Imaginary poles with indentation to the left
    plt.figure()
    count = ct.nyquist_plot(sys, indent_direction='left', label_freq=300)
    plt.title("Imaginary poles; indent_direction='left'; encirclements = %d" %
              count)
    assert _Z(sys) == count + _P(sys, indent='left')

    # Imaginary poles with no indentation
    plt.figure()
    with pytest.warns(UserWarning, match="encirclements does not match"):
        count = ct.nyquist_plot(sys,
                                np.linspace(0, 1e3, 1000),
                                indent_direction='none')
    plt.title("Imaginary poles; indent_direction='none'; encirclements = %d" %
              count)
    assert _Z(sys) == count + _P(sys)
Beispiel #6
0
def question3(OLTF, gainHz, plot=True):
    print(spacer + "Question 3" + spacer)

    Kp = gainHz[0]
    print("\t Kp is {}".format(Kp))

    OLTF = OLTF * Kp

    plt.figure("Q3 - Nyquist plot")
    ct.nyquist_plot(OLTF, plot=True)
    if plot: plt.show()

    return OLTF
Beispiel #7
0
def winding_number_condition(plant_1: TransferFunction,
                             plant_2: TransferFunction) -> bool:
    """
        :param plant_1: Transferfunction of linearized SISO plant
        :param plant_2: Transferfunction of linearized SISO plant

        returns: True if plant_1 and plant_2 satisfy the winding number condition. (False if not)
    """

    plant_2_c = conjugate_plant(plant_2)

    def f(x):
        p = abs(evalfr(1 + plant_2_c * plant_1, 1j * x))
        return p

    min_obj = minimize_scalar(f, method="golden")
    if f(min_obj.x) == 0:
        return False

    wno = nyquist_plot(1 + plant_2_c * plant_1)
    eta_0 = 0
    eta_1 = 0
    eta_2 = 0
    plant_1_poles = plant_1.pole()
    plant_2_poles = plant_2.pole()
    for p in plant_1_poles:
        if np.real(p) > 0:
            eta_1 = eta_1 + 1
    for p in plant_2_poles:
        if np.real(p) > 0:
            eta_2 = eta_2 + 1
        if np.real(p) == 0:
            eta_0 = eta_0 + 1
    return wno + eta_1 - eta_2 - eta_0 == 0
def test_linestyle_checks():
    sys = ct.rss(2, 1, 1)

    # Things that should work
    ct.nyquist_plot(sys, primary_style=['-', '-'], mirror_style=['-', '-'])
    ct.nyquist_plot(sys, mirror_style=None)

    with pytest.raises(ValueError, match="invalid 'primary_style'"):
        ct.nyquist_plot(sys, primary_style=False)

    with pytest.raises(ValueError, match="invalid 'mirror_style'"):
        ct.nyquist_plot(sys, mirror_style=0.2)

    # If only one line style is given use, the default value for the other
    # TODO: for now, just make sure the signature works; no correct check yet
    with pytest.warns(PendingDeprecationWarning, match="single string"):
        ct.nyquist_plot(sys, primary_style=':', mirror_style='-.')
def test_nyquist_legacy():
    ct.use_legacy_defaults('0.9.1')

    # Example that generated a warning using earlier defaults
    s = ct.tf('s')
    sys = (0.02 * s**3 - 0.1 * s) / (s**4 + s**3 + s**2 + 0.25 * s + 0.04)

    with pytest.warns(UserWarning, match="indented contour may miss"):
        count = ct.nyquist_plot(sys)
def test_nyquist_indent():
    # FBS Figure 10.10
    s = ct.tf('s')
    sys = 3 * (s+6)**2 / (s * (s+1)**2)
    # poles: [-1, -1, 0]

    plt.figure();
    count = ct.nyquist_plot(sys)
    plt.title("Pole at origin; indent_radius=default")
    assert _Z(sys) == count + _P(sys)

    # first value of default omega vector was 0.1, replaced by 0. for contour
    # indent_radius is larger than 0.1 -> no extra quater circle around origin
    count, contour = ct.nyquist_plot(sys, plot=False, indent_radius=.1007,
                                     return_contour=True)
    np.testing.assert_allclose(contour[0], .1007+0.j)
    # second value of omega_vector is larger than indent_radius: not indented
    assert np.all(contour.real[2:] == 0.)

    plt.figure();
    count, contour = ct.nyquist_plot(sys, indent_radius=0.01,
                                     return_contour=True)
    plt.title("Pole at origin; indent_radius=0.01; encirclements = %d" % count)
    assert _Z(sys) == count + _P(sys)
    # indent radius is smaller than the start of the default omega vector
    # check that a quarter circle around the pole at origin has been added.
    np.testing.assert_allclose(contour[:50].real**2 + contour[:50].imag**2,
                               0.01**2)

    plt.figure();
    count = ct.nyquist_plot(sys, indent_direction='left')
    plt.title(
        "Pole at origin; indent_direction='left'; encirclements = %d" % count)
    assert _Z(sys) == count + _P(sys, indent='left')

    # System with poles on the imaginary axis
    sys = ct.tf([1, 1], [1, 0, 1])

    # Imaginary poles with standard indentation
    plt.figure();
    count = ct.nyquist_plot(sys)
    plt.title("Imaginary poles; encirclements = %d" % count)
    assert _Z(sys) == count + _P(sys)

    # Imaginary poles with indentation to the left
    plt.figure();
    count = ct.nyquist_plot(sys, indent_direction='left', label_freq=300)
    plt.title(
        "Imaginary poles; indent_direction='left'; encirclements = %d" % count)
    assert _Z(sys) == count + _P(sys, indent='left')

    # Imaginary poles with no indentation
    plt.figure();
    count = ct.nyquist_plot(
        sys, np.linspace(0, 1e3, 1000), indent_direction='none')
    plt.title(
        "Imaginary poles; indent_direction='none'; encirclements = %d" % count)
    assert _Z(sys) == count + _P(sys)
Beispiel #11
0
def test_nyquist_indent_do(indentsys):
    plt.figure()
    count, contour = ct.nyquist_plot(indentsys,
                                     indent_radius=0.01,
                                     return_contour=True)
    plt.title("Pole at origin; indent_radius=0.01; encirclements = %d" % count)
    assert _Z(indentsys) == count + _P(indentsys)
    # indent radius is smaller than the start of the default omega vector
    # check that a quarter circle around the pole at origin has been added.
    np.testing.assert_allclose(contour[:50].real**2 + contour[:50].imag**2,
                               0.01**2)
Beispiel #12
0
def test_nyquist_indent_dont(indentsys):
    # first value of default omega vector was 0.1, replaced by 0. for contour
    # indent_radius is larger than 0.1 -> no extra quater circle around origin
    with pytest.warns(UserWarning, match="encirclements does not match"):
        count, contour = ct.nyquist_plot(indentsys,
                                         omega=[0, 0.2, 0.3, 0.4],
                                         indent_radius=.1007,
                                         plot=False,
                                         return_contour=True)
    np.testing.assert_allclose(contour[0], .1007 + 0.j)
    # second value of omega_vector is larger than indent_radius: not indented
    assert np.all(contour.real[2:] == 0.)
Beispiel #13
0
def test_nyquist_encirclements():
    # Example 14.14: effect of friction in a cart-pendulum system
    s = ct.tf('s')
    sys = (0.02 * s**3 - 0.1 * s) / (s**4 + s**3 + s**2 + 0.25 * s + 0.04)

    plt.figure()
    count = ct.nyquist_plot(sys)
    plt.title("Stable system; encirclements = %d" % count)
    assert _Z(sys) == count + _P(sys)

    plt.figure()
    count = ct.nyquist_plot(sys * 3)
    plt.title("Unstable system; encirclements = %d" % count)
    assert _Z(sys * 3) == count + _P(sys * 3)

    # System with pole at the origin
    sys = ct.tf([3], [1, 2, 2, 1, 0])

    plt.figure()
    count = ct.nyquist_plot(sys)
    plt.title("Pole at the origin; encirclements = %d" % count)
    assert _Z(sys) == count + _P(sys)
Beispiel #14
0
def test_nyquist_exceptions():
    # MIMO not implemented
    sys = ct.rss(2, 2, 2)
    with pytest.raises(ct.exception.ControlMIMONotImplemented,
                       match="only supports SISO"):
        ct.nyquist_plot(sys)

    # Legacy keywords for arrow size
    sys = ct.rss(2, 1, 1)
    with pytest.warns(FutureWarning, match="use `arrow_size` instead"):
        ct.nyquist_plot(sys, arrow_width=8, arrow_length=6)

    # Discrete time system sampled above Nyquist frequency
    sys = ct.drss(2, 1, 1)
    sys.dt = 0.01
    with pytest.warns(UserWarning, match="above Nyquist"):
        ct.nyquist_plot(sys, np.logspace(-2, 3))
Beispiel #15
0
def test_nyquist_indent():
    # FBS Figure 10.10
    s = ct.tf('s')
    sys = 3 * (s + 6)**2 / (s * (s + 1)**2)

    plt.figure()
    count = ct.nyquist_plot(sys)
    plt.title("Pole at origin; indent_radius=default")
    assert _Z(sys) == count + _P(sys)

    plt.figure()
    count = ct.nyquist_plot(sys, indent_radius=0.01)
    plt.title("Pole at origin; indent_radius=0.01; encirclements = %d" % count)
    assert _Z(sys) == count + _P(sys)

    plt.figure()
    count = ct.nyquist_plot(sys, indent_direction='left')
    plt.title("Pole at origin; indent_direction='left'; encirclements = %d" %
              count)
    assert _Z(sys) == count + _P(sys, indent='left')

    # System with poles on the imaginary axis
    sys = ct.tf([1, 1], [1, 0, 1])

    # Imaginary poles with standard indentation
    plt.figure()
    count = ct.nyquist_plot(sys)
    plt.title("Imaginary poles; encirclements = %d" % count)
    assert _Z(sys) == count + _P(sys)

    # Imaginary poles with indentation to the left
    plt.figure()
    count = ct.nyquist_plot(sys, indent_direction='left', label_freq=300)
    plt.title("Imaginary poles; indent_direction='left'; encirclements = %d" %
              count)
    assert _Z(sys) == count + _P(sys, indent='left')

    # Imaginary poles with no indentation
    plt.figure()
    count = ct.nyquist_plot(sys,
                            np.linspace(0, 1e3, 1000),
                            indent_direction='none')
    plt.title("Imaginary poles; indent_direction='none'; encirclements = %d" %
              count)
    assert _Z(sys) == count + _P(sys)
Beispiel #16
0
# Replot the phase by hand
ax.semilogx([1e-4, 1e3], [-180, -180], 'k-')
ax.semilogx(w, np.squeeze(phase), 'b-')
ax.axis([1e-4, 1e3, -360, 0])
plt.xlabel('Frequency [deg]')
plt.ylabel('Phase [deg]')
# plt.set(gca, 'YTick', [-360, -270, -180, -90, 0])
# plt.set(gca, 'XTick', [10^-4, 10^-2, 1, 100])

#
# Nyquist plot for complete design
#
plt.figure(7)
plt.clf()
ct.nyquist_plot(L, (0.0001, 1000))

# Add a box in the region we are going to expand
plt.plot([-2, -2, 1, 1, -2], [-4, 4, 4, -4, -4], 'r-')

# Expanded region
plt.figure(8)
plt.clf()
ct.nyquist_plot(L)
plt.axis([-2, 1, -4, 4])

# set up the color
color = 'b'

# Add arrows to the plot
# H1 = L.evalfr(0.4); H2 = L.evalfr(0.41);
Beispiel #17
0
def test_nyquist_indent_left(indentsys):
    plt.figure()
    count = ct.nyquist_plot(indentsys, indent_direction='left')
    plt.title("Pole at origin; indent_direction='left'; encirclements = %d" %
              count)
    assert _Z(indentsys) == count + _P(indentsys, indent='left')
Beispiel #18
0
def test_nyquist_indent_default(indentsys):
    plt.figure()
    count = ct.nyquist_plot(indentsys)
    plt.title("Pole at origin; indent_radius=default")
    assert _Z(indentsys) == count + _P(indentsys)
Beispiel #19
0
def test_nyquist_arrows(arrows):
    sys = ct.tf([1.4], [1, 2, 1]) * ct.tf(*ct.pade(1, 4))
    plt.figure()
    plt.title("L(s) = 1.4 e^{-s}/(s+1)^2 / arrows = %s" % arrows)
    count = ct.nyquist_plot(sys, arrows=arrows)
    assert _Z(sys) == count + _P(sys)
Beispiel #20
0
# Compute the estimator gain using eigenvalue placement
wo = 20
zo = 0.707
eigs = np.roots([1, 2 * zo * wo, wo**2])
L = np.transpose(ct.place(np.transpose(A), np.transpose(C), eigs))
print("L = ", np.squeeze(L))

# Construct an output-based controller for the system
C1 = ct.ss2tf(ct.StateSpace(A - B @ K - L @ C, L, K, 0))
print("C(s) = ", C1)

# Compute the loop transfer function and plot Nyquist, Bode
L1 = P * C1
plt.figure()
ct.nyquist_plot(L1, np.logspace(0.5, 3, 500))
plt.figure()
ct.bode_plot(L1, np.logspace(-1, 3, 500))

# In[ ]:

# Modified control law
wc = 10
zc = 2.6
eigs = np.roots([1, 2 * zc * wc, wc**2])
K = ct.place(A, B, eigs)
kr = np.real(1 / clsys(0))
print("K = ", np.squeeze(K))

# Construct an output-based controller for the system
C2 = ct.ss2tf(ct.StateSpace(A - B @ K - L @ C, L, K, 0))
Beispiel #21
0
#
# Running this script in python (or better ipython) will show a collection of
# figures that should all look OK on the screeen.
#

# Start by clearing existing figures
plt.close('all')

print("Nyquist examples from FBS")
test_nyquist_fbs_examples()

print("Arrow test")
test_nyquist_arrows(None)
test_nyquist_arrows(1)
test_nyquist_arrows(3)
test_nyquist_arrows([0.1, 0.5, 0.9])

print("Stability checks")
test_nyquist_encirclements()

print("Indentation checks")
test_nyquist_indent()

print("Unusual Nyquist plot")
sys = ct.tf([1], [1, 3, 2]) * ct.tf([1], [1, 0, 1])
plt.figure()
plt.title("Poles: %s" %
          np.array2string(sys.pole(), precision=2, separator=','))
count = ct.nyquist_plot(sys)
assert _Z(sys) == count + _P(sys)
Beispiel #22
0
    test_nyquist_arrows([0.1, 0.5, 0.9])

    print("Stability checks")
    test_nyquist_encirclements()

    print("Indentation checks")
    s = ct.tf('s')
    indentsys = 3 * (s + 6)**2 / (s * (s + 1)**2)
    test_nyquist_indent_default(indentsys)
    test_nyquist_indent_do(indentsys)
    test_nyquist_indent_left(indentsys)

    # Generate a figuring showing effects of different parameters
    sys = 3 * (s + 6)**2 / (s * (s**2 + 1e-4 * s + 1))
    plt.figure()
    ct.nyquist_plot(sys)
    ct.nyquist_plot(sys, max_curve_magnitude=15)
    ct.nyquist_plot(sys, indent_radius=1e-6, max_curve_magnitude=25)

    print("Unusual Nyquist plot")
    sys = ct.tf([1], [1, 3, 2]) * ct.tf([1], [1, 0, 1])
    plt.figure()
    plt.title("Poles: %s" %
              np.array2string(sys.poles(), precision=2, separator=','))
    count = ct.nyquist_plot(sys)
    assert _Z(sys) == count + _P(sys)

    print("Discrete time systems")
    sys = ct.c2d(sys, 0.01)
    plt.figure()
    plt.title("Discrete-time; poles: %s" %
Beispiel #23
0
def nyquis(W):
    plt.figure(1)
    con.nyquist_plot(W)
    plt.grid()
    plt.show()
Beispiel #24
0
def test_nyquist_basic():
    # Simple Nyquist plot
    sys = ct.rss(5, 1, 1)
    N_sys = ct.nyquist_plot(sys)
    assert _Z(sys) == N_sys + _P(sys)

    # Unstable system
    sys = ct.tf([10], [1, 2, 2, 1])
    N_sys = ct.nyquist_plot(sys)
    assert _Z(sys) > 0
    assert _Z(sys) == N_sys + _P(sys)

    # Multiple systems - return value is final system
    sys1 = ct.rss(3, 1, 1)
    sys2 = ct.rss(4, 1, 1)
    sys3 = ct.rss(5, 1, 1)
    counts = ct.nyquist_plot([sys1, sys2, sys3])
    for N_sys, sys in zip(counts, [sys1, sys2, sys3]):
        assert _Z(sys) == N_sys + _P(sys)

    # Nyquist plot with poles at the origin, omega specified
    sys = ct.tf([1], [1, 3, 2]) * ct.tf([1], [1, 0])
    omega = np.linspace(0, 1e2, 100)
    count, contour = ct.nyquist_plot(sys, omega, return_contour=True)
    np.testing.assert_array_equal(contour[contour.real < 0],
                                  omega[contour.real < 0])

    # Make sure things match at unmodified frequencies
    np.testing.assert_almost_equal(
        contour[contour.real == 0],
        1j * np.linspace(0, 1e2, 100)[contour.real == 0])

    # Make sure that we can turn off frequency modification
    count, contour_indented = ct.nyquist_plot(sys,
                                              np.linspace(1e-4, 1e2, 100),
                                              return_contour=True)
    assert not all(contour_indented.real == 0)
    count, contour = ct.nyquist_plot(sys,
                                     np.linspace(1e-4, 1e2, 100),
                                     return_contour=True,
                                     indent_direction='none')
    np.testing.assert_almost_equal(contour, 1j * np.linspace(1e-4, 1e2, 100))

    # Nyquist plot with poles at the origin, omega unspecified
    sys = ct.tf([1], [1, 3, 2]) * ct.tf([1], [1, 0])
    count, contour = ct.nyquist_plot(sys, return_contour=True)
    assert _Z(sys) == count + _P(sys)

    # Nyquist plot with poles at the origin, return contour
    sys = ct.tf([1], [1, 3, 2]) * ct.tf([1], [1, 0])
    count, contour = ct.nyquist_plot(sys, return_contour=True)
    assert _Z(sys) == count + _P(sys)

    # Nyquist plot with poles on imaginary axis, omega specified
    sys = ct.tf([1], [1, 3, 2]) * ct.tf([1], [1, 0, 1])
    count = ct.nyquist_plot(sys, np.linspace(1e-3, 1e1, 1000))
    assert _Z(sys) == count + _P(sys)

    # Nyquist plot with poles on imaginary axis, omega specified, with contour
    sys = ct.tf([1], [1, 3, 2]) * ct.tf([1], [1, 0, 1])
    count, contour = ct.nyquist_plot(sys,
                                     np.linspace(1e-3, 1e1, 1000),
                                     return_contour=True)
    assert _Z(sys) == count + _P(sys)

    # Nyquist plot with poles on imaginary axis, return contour
    sys = ct.tf([1], [1, 3, 2]) * ct.tf([1], [1, 0, 1])
    count, contour = ct.nyquist_plot(sys, return_contour=True)
    assert _Z(sys) == count + _P(sys)

    # Nyquist plot with poles at the origin and on imaginary axis
    sys = ct.tf([1], [1, 3, 2]) * ct.tf([1], [1, 0, 1]) * ct.tf([1], [1, 0])
    count, contour = ct.nyquist_plot(sys, return_contour=True)
    assert _Z(sys) == count + _P(sys)
Beispiel #25
0
def test_discrete_nyquist():
    # Make sure we can handle discrete time systems with negative poles
    sys = ct.tf(1, [1, -0.1], dt=1) * ct.tf(1, [1, 0.1], dt=1)
    ct.nyquist_plot(sys)
Beispiel #26
0
def test_nyquist_basic():
    # Simple Nyquist plot
    sys = ct.rss(5, 1, 1)
    N_sys = ct.nyquist_plot(sys)
    assert _Z(sys) == N_sys + _P(sys)

    # Previously identified bug
    #
    # This example has an open loop pole at -0.06 and a closed loop pole at
    # 0.06, so if you use an indent_radius of larger than 0.12, then the
    # encirclements computed by nyquist_plot() will not properly predict
    # stability.  A new warning messages was added to catch this case.
    #
    A = np.array(
        [[-3.56355873, -1.22980795, -1.5626527, -0.4626829, -0.16741484],
         [-8.52361371, -3.60331459, -3.71574266, -0.43839201, 0.41893656],
         [-2.50458726, -0.72361335, -1.77795489, -0.4038419, 0.52451147],
         [-0.281183, 0.23391825, 0.19096003, -0.9771515, 0.66975606],
         [-3.04982852, -1.1091943, -1.40027242, -0.1974623, -0.78930791]])
    B = np.array([[-0.], [-1.42827213], [0.76806551], [-1.07987454], [0.]])
    C = np.array([[-0., 0.35557249, 0.35941791, -0., -1.42320969]])
    D = np.array([[0]])
    sys = ct.ss(A, B, C, D)

    # With a small indent_radius, all should be fine
    N_sys = ct.nyquist_plot(sys, indent_radius=0.001)
    assert _Z(sys) == N_sys + _P(sys)

    # With a larger indent_radius, we get a warning message + wrong answer
    with pytest.warns(UserWarning, match="contour may miss closed loop pole"):
        N_sys = ct.nyquist_plot(sys, indent_radius=0.2)
        assert _Z(sys) != N_sys + _P(sys)

    # Unstable system
    sys = ct.tf([10], [1, 2, 2, 1])
    N_sys = ct.nyquist_plot(sys)
    assert _Z(sys) > 0
    assert _Z(sys) == N_sys + _P(sys)

    # Multiple systems - return value is final system
    sys1 = ct.rss(3, 1, 1)
    sys2 = ct.rss(4, 1, 1)
    sys3 = ct.rss(5, 1, 1)
    counts = ct.nyquist_plot([sys1, sys2, sys3])
    for N_sys, sys in zip(counts, [sys1, sys2, sys3]):
        assert _Z(sys) == N_sys + _P(sys)

    # Nyquist plot with poles at the origin, omega specified
    sys = ct.tf([1], [1, 3, 2]) * ct.tf([1], [1, 0])
    omega = np.linspace(0, 1e2, 100)
    count, contour = ct.nyquist_plot(sys, omega, return_contour=True)
    np.testing.assert_array_equal(contour[contour.real < 0],
                                  omega[contour.real < 0])

    # Make sure things match at unmodified frequencies
    np.testing.assert_almost_equal(
        contour[contour.real == 0],
        1j * np.linspace(0, 1e2, 100)[contour.real == 0])

    #
    # Make sure that we can turn off frequency modification
    #
    # Start with a case where indentation should occur
    count, contour_indented = ct.nyquist_plot(sys,
                                              np.linspace(1e-4, 1e2, 100),
                                              indent_radius=1e-2,
                                              return_contour=True)
    assert not all(contour_indented.real == 0)
    with pytest.warns(UserWarning, match="encirclements does not match"):
        count, contour = ct.nyquist_plot(sys,
                                         np.linspace(1e-4, 1e2, 100),
                                         indent_radius=1e-2,
                                         return_contour=True,
                                         indent_direction='none')
    np.testing.assert_almost_equal(contour, 1j * np.linspace(1e-4, 1e2, 100))

    # Nyquist plot with poles at the origin, omega unspecified
    sys = ct.tf([1], [1, 3, 2]) * ct.tf([1], [1, 0])
    count, contour = ct.nyquist_plot(sys, return_contour=True)
    assert _Z(sys) == count + _P(sys)

    # Nyquist plot with poles at the origin, return contour
    sys = ct.tf([1], [1, 3, 2]) * ct.tf([1], [1, 0])
    count, contour = ct.nyquist_plot(sys, return_contour=True)
    assert _Z(sys) == count + _P(sys)

    # Nyquist plot with poles on imaginary axis, omega specified
    # (can miss encirclements due to the imaginary poles at +/- 1j)
    sys = ct.tf([1], [1, 3, 2]) * ct.tf([1], [1, 0, 1])
    with pytest.warns(UserWarning, match="does not match") as records:
        count = ct.nyquist_plot(sys, np.linspace(1e-3, 1e1, 1000))
    if len(records) == 0:
        assert _Z(sys) == count + _P(sys)

    # Nyquist plot with poles on imaginary axis, omega specified, with contour
    sys = ct.tf([1], [1, 3, 2]) * ct.tf([1], [1, 0, 1])
    with pytest.warns(UserWarning, match="does not match") as records:
        count, contour = ct.nyquist_plot(sys,
                                         np.linspace(1e-3, 1e1, 1000),
                                         return_contour=True)
    if len(records) == 0:
        assert _Z(sys) == count + _P(sys)

    # Nyquist plot with poles on imaginary axis, return contour
    sys = ct.tf([1], [1, 3, 2]) * ct.tf([1], [1, 0, 1])
    count, contour = ct.nyquist_plot(sys, return_contour=True)
    assert _Z(sys) == count + _P(sys)

    # Nyquist plot with poles at the origin and on imaginary axis
    sys = ct.tf([1], [1, 3, 2]) * ct.tf([1], [1, 0, 1]) * ct.tf([1], [1, 0])
    count, contour = ct.nyquist_plot(sys, return_contour=True)
    assert _Z(sys) == count + _P(sys)
print("poles: ", G.pole())
print("zeros: ",G.zero())

number_asymptotes=len(G.pole())-len(G.zero())

print("number of asymptotes: ",number_asymptotes)

centroid=(G.pole().sum()-G.zero().sum())/number_asymptotes

print("centroid: ",centroid)

print("angle(s) of deperture:")

for i in range(number_asymptotes):
    theta=(((2*i)+1)/number_asymptotes)*180
    print(theta)

gm, pm, wg, wp = ctl.margin(G)

print("Gain margin:", gm)
print("Phase margin:", pm)

plt.figure()
ctl.rlocus(G)
plt.figure()
ctl.bode(G,dB=True)
plt.show()
plt.figure()
ctl.nyquist_plot(G)
plt.show()
Beispiel #28
0
plt.xlabel('Frequency [Hz]')
plt.ylabel('Phase [Deg]')
# plt.title('Frequency Response - Comparison')
plt.legend()

con.pzmap(sysc, title='Cont System Laplace plane')

con.pzmap(sysd, title='Discrete System Z plane')
if sysd.isdtime():
    cir_phase = np.linspace(0, 2 * np.pi, 500)
    plt.plot(np.real(np.exp(1j * cir_phase)), np.imag(np.exp(1j * cir_phase)),
             'r--')
    plt.axis('equal')

plt.figure()
real, imag, freq = con.nyquist_plot(sysc)
scale = K / 2 + 1
plt.axis([-scale, scale, -scale, scale])
plt.title('Nyquist plot discrete')

# plt.figure()
rlist, klist = con.root_locus(sysc, grid=True)
plt.title('Root Locus cont')

plt.figure()
real, imag, freq = con.nyquist_plot(T * sysd, omega=w)
scale = K / 2 + 1
plt.axis([-scale, scale, -scale, scale])
plt.title('Nyquist plot discrete')

# plt.figure()
Beispiel #29
0
def nyquis(W):
    plt.grid()
    c.nyquist_plot(W)
    plt.show()
Beispiel #30
0
plt.rcParams["font.variant"] = 'normal'
plt.rcParams["font.weight"] = 'normal'
plt.rcParams["font.stretch"] = 'normal'
plt.rcParams["font.size"] = '11'

# diagrama de Nyquist
fig = plt.figure()

num = [0.5]
den = [1, 0.5, 1, 0]
system = tf(num, den)
w1 = np.linspace(0.11, 10, 1000)
w2 = np.linspace(0.14, 10, 1000)
w3 = np.linspace(0.17, 10, 1000)
print(system)
[re1, Im1, freq1] = control.nyquist_plot(system, w2, label="Unitary")
[re2, Im2, freq2] = control.nyquist_plot(0.8 * system,
                                         w1,
                                         color='r',
                                         label="Small gain")
[re3, Im3, freq3] = control.nyquist_plot(1.2 * system,
                                         w3,
                                         color='k',
                                         label="Large gain")
plt.clf()
plt.close()

fig = plt.figure()
fig = fig.add_subplot(111)
fig.set(title='Nyquist Plot')
plt.xlabel('Re(s)')