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)
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))
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)
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
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)
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)
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.)
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)
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))
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)
# 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);
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')
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)
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)
# 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))
# # 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)
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" %
def nyquis(W): plt.figure(1) con.nyquist_plot(W) plt.grid() plt.show()
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)
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)
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()
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()
def nyquis(W): plt.grid() c.nyquist_plot(W) plt.show()
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)')