def bodeclosedloop(G, K, w_start=-2, w_end=2, axlim=None, points=1000, margin=False): """ Shows the bode plot for a controller model Parameters ---------- G : tf Plant transfer function. K : tf Controller transfer function. margin : boolean Show the cross over frequencies on the plot (optional). """ if axlim is None: axlim = [None, None, None, None] plt.gcf().set_facecolor('white') w = numpy.logspace(w_start, w_end, points) L = G(1j * w) * K(1j * w) S = utils.feedback(1, L) T = utils.feedback(L, 1) plt.subplot(2, 1, 1) plt.loglog(w, abs(L)) plt.loglog(w, abs(S)) plt.loglog(w, abs(T)) plt.axis(axlim) plt.grid() plt.ylabel("Magnitude") plt.legend(["L", "S", "T"]) if margin: plt.plot(w, 1 / numpy.sqrt(2) * numpy.ones(len(w)), linestyle='dotted') plt.subplot(2, 1, 2) plt.semilogx(w, utils.phase(L, deg=True)) plt.semilogx(w, utils.phase(S, deg=True)) plt.semilogx(w, utils.phase(T, deg=True)) plt.axis(axlim) plt.grid() plt.ylabel("Phase") plt.xlabel("Frequency [rad/s]")
def bodeclosedloop(G, K, w_start=-2, w_end=2, axlim=None, points=1000, margin=False): """ Shows the bode plot for a controller model Parameters ---------- G : tf Plant transfer function. K : tf Controller transfer function. margin : boolean Show the cross over frequencies on the plot (optional). """ if axlim is None: axlim = [None, None, None, None] plt.gcf().set_facecolor('white') w = numpy.logspace(w_start, w_end, points) L = G(1j*w) * K(1j*w) S = utils.feedback(1, L) T = utils.feedback(L, 1) plt.subplot(2, 1, 1) plt.loglog(w, abs(L)) plt.loglog(w, abs(S)) plt.loglog(w, abs(T)) plt.axis(axlim) plt.grid() plt.ylabel("Magnitude") plt.legend(["L", "S", "T"]) if margin: plt.plot(w, 1/numpy.sqrt(2) * numpy.ones(len(w)), linestyle='dotted') plt.subplot(2, 1, 2) plt.semilogx(w, utils.phase(L, deg=True)) plt.semilogx(w, utils.phase(S, deg=True)) plt.semilogx(w, utils.phase(T, deg=True)) plt.axis(axlim) plt.grid() plt.ylabel("Phase") plt.xlabel("Frequency [rad/s]")
import matplotlib.pyplot as plt import numpy as np from utils import feedback, tf # Process model of G with various Controller Gains s = tf([1, 0], 1) G = 3 * (-2 * s + 1) / ((10 * s + 1) * (5 * s + 1)) tspan = np.linspace(0, 50, 100) # calculate the time domain response Ks = [0.5, 1.5, 2, 2.5] for K in Ks: T = feedback(G * K, 1) [t, y] = T.step(0, tspan) plt.plot(t, y) plt.legend(["Kc = %1.1f" % K for K in Ks]) plt.xlabel('Time [s]') plt.show()
[t, y] = f.step() plt.title('Figure 2.8') plt.xlabel('Time [s]') plt.plot(t, y) plt.figure() # Bode magnitude and phase plot - Figure 2.14 w = np.logspace(-2, 1, 1000) s = w*1j K = Kc*(1+1/(Tauc*s)) G = 3*(-2*(s)+1)/((10*s+1)*(5*s+1)) L = G*K S = feedback(1, L) T = feedback(L, 1) plt.subplot(2, 1, 1) plt.loglog(w, abs(L)) plt.loglog(w, abs(S)) plt.loglog(w, abs(T)) plt.ylabel("Magnitude") plt.legend(["L", "S", "T"], bbox_to_anchor=(0, 1.01, 1, 0), loc=3, ncol=3) plt.subplot(2, 1, 2) plt.semilogx(w, phase(L, deg=True)) plt.semilogx(w, phase(S, deg=True)) plt.semilogx(w, phase(T, deg=True)) plt.ylabel("Phase") plt.xlabel("Frequency [rad/s]")
The example used here is the same as in the reference """ # First example in reference to demonstrate working of tf object # Define s as tf to enable its use as a variable s = tf([1, 0]) # Define the transfer functions F = tf(1, [1, 1]) G = tf(100, [1, 5, 100]) C = 20*(s**2 + s + 60) / s / (s**2 + 40*s + 400) S = tf(10, [1, 10]) T = F * feedback(G*C, S) # This is the same figure as in the reference tf_step(T, 6) # Assign names to lines as in second example F.u = 'r'; F.y = 'uF' C.u = 'e'; C.y = 'uC' G.u = 'u'; G.y = 'ym' S.u = 'ym'; S.y = 'y' # There must be a better way to call the name of an object if the object has
# closed-loop transfer function L = G * K # magnitude and phase of L plt.figure('Figure 2.19') bode(L, -2, 1) # From the figure we can calculate w180 # w180 = 0.44 GM, PM, wc, wb, wbt, valid = marginsclosedloop(L) print('GM:', np.round(GM, 2)) print('PM:', np.round(PM * np.pi / 180, 2), "rad or", np.round(PM, 2), "deg") print('wb:', np.round(wb, 2)) print('wc:', np.round(wc, 2)) print('wbt:', np.round(wbt, 4)) # Response to step in reference for loop shaping design # y = Tr, r(t) = 1 for t > 0 # u = KSr, r(t) = 1 for t > 0 plt.figure('Figure 2.20') T = feedback(L, 1) S = feedback(1, L) u = K * S step_response_plot(T, u, 50, 0) # magnitude and phase of K plt.figure('Figure 2.21') bode(K, -2, 1) plt.show()
from utilsplot import step_response_plot from utils import feedback, tf s = tf([1, 0], 1) Kd = 0.5 G = 5 / ((10 * s + 1) * (s - 1)) Gd = Kd / ((s + 1) * (0.2 * s + 1)) K = 0.04 / s * ((10 * s + 1)**2) / ((0.1 * s + 1)**2) L = G * K # Transfer function between disturbance and output y S = feedback(1, L) * Gd # Transfer function between disturbance and controller input u Gu = -S * K plt.figure('Figure 5.16 (a)') plt.subplot(1, 2, 1) w = np.logspace(-2, 1, 1000) wi = w * 1j plt.loglog(w, np.abs(G(wi))) plt.loglog(w, np.abs(Gd(wi))) plt.axhline(1, color='black', linestyle=':') plt.title('(a) $|G|$ & $|G_d|$ with $k_d$=0.5') plt.xlabel('Frequency [rad/s]') plt.ylabel('Magnitude')
def freq_step_response_plot(G, K, Kc, t_end=50, freqtype='S', w_start=-2, w_end=2, axlim=None, points=1000): """ A subplot function for both the frequency response and step response for a controlled plant Parameters ---------- G : tf Plant transfer function. K : tf Controller transfer function. Kc : integer Controller constant. t_end : integer Time period which the step response should occur. freqtype : string (optional) Type of function to plot: ======== ================================== freqtype Type of function to plot ======== ================================== S Sensitivity function T Complementary sensitivity function L Loop function ======== ================================== Returns ------- Plot : matplotlib figure """ _, w, axlim = df.frequency_plot_setup(axlim, w_start, w_end, points) plt.subplot(1, 2, 1) # Controllers transfer function with various controller gains Ks = [(kc * K) for kc in Kc] Ts = [utils.feedback(G * Kss, 1) for Kss in Ks] if freqtype == 'S': Fs = [(1 - Tss) for Tss in Ts] plt.title('(a) Sensitivity function') plt.ylabel('Magnitude $|S|$') elif freqtype == 'T': Fs = Ts plt.title('(a) Complementary sensitivity function') plt.ylabel('Magnitude $|T|$') else: # freqtype=='L' Fs = [(G * Kss) for Kss in Ks] plt.title('(a) Loop function') plt.ylabel('Magnitude $|L|$') wi = w * 1j i = 0 for F in Fs: plt.loglog(w, abs(F(wi)), label='Kc={d%s}=' % Kc[i]) i += 1 plt.axis(axlim) plt.grid(b=None, which='both', axis='both') plt.xlabel('Frequency [rad/unit time]') plt.legend(["Kc = %1.2f" % k for k in Kc], loc=4) plt.subplot(1, 2, 2) plt.title('(b) Response to step in reference') tspan = numpy.linspace(0, t_end, points) for T in Ts: [t, y] = T.step(0, tspan) plt.plot(t, y) plt.plot(tspan, 0 * numpy.ones(points), ls='--') plt.plot(tspan, 1 * numpy.ones(points), ls='--') plt.axis(axlim) plt.xlabel('Time') plt.ylabel('$y(t)$')
The example used here is the same as in the reference """ # First example in reference to demonstrate working of tf object # Define s as tf to enable its use as a variable s = tf([1, 0]) # Define the transfer functions F = tf(1, [1, 1]) G = tf(100, [1, 5, 100]) C = 20 * (s**2 + s + 60) / s / (s**2 + 40 * s + 400) S = tf(10, [1, 10]) T = F * feedback(G * C, S) # This is NOT the same figure as in the reference t, y = tf_step(T, 6) plt.plot(t, y) plt.xlabel('Time') plt.ylabel('y(t)') plt.show() #utilsplot.step(T, t_end = 6) # Assign names to lines as in second example F.u = 'r' F.y = 'uF' C.u = 'e' C.y = 'uC' G.u = 'u' G.y = 'ym'
import matplotlib.pyplot as plt import numpy as np from utils import tf, feedback # Process model transfer function s = tf([1, 0]) G = (-s + 1) / (s + 1) # Controllers transfer function with various controller gains Ks = [Kc * ((s + 1) / s) * (1 / (0.05 * s + 1)) for Kc in [0.2, 0.5, 0.8]] # Complementary sensitivity transfer functions Ts = [feedback(G * K, 1) for K in Ks] plt.figure("Figure 5.7") w = np.logspace(-2, 2, 1000) wi = w * 1j plt.subplot(1, 2, 1) plt.title("(a) Sensitivity function") for T in Ts: S = 1 - T plt.loglog(w, abs(S(wi))) plt.xlabel("Frequency [rad/s]") plt.ylabel("Magnitude |S|") plt.legend(["Kc=0.2", "Kc=0.5", "Kc=0.8"], bbox_to_anchor=(0, 1.03, 1, 0), loc=3, ncol=3) plt.subplot(1, 2, 2) plt.title("(b) Response to step in reference") tspan = np.linspace(0, 5, 100) for T in Ts: [t, y] = T.step(0, tspan)
import matplotlib.pyplot as plt import numpy as np from utils import feedback, tf # Process model of G with various Controller Gains s = tf([1, 0], 1) G = 3 * (-2 * s + 1) / ((10 * s + 1) * (5 * s + 1)) tspan = np.linspace(0, 50, 100) plt.figure('Figure 2.6') plt.title('Effect of proportional gain Kc on closed loop response') # calculate the time domain response Ks = [0.5, 1.5, 2, 2.5, 3.0] for K in Ks: T = feedback(G * K, 1) [t, y] = T.step(0, tspan) if K >= 3.0: plt.plot(t, y, '-.') else: plt.plot(t, y) plt.legend(["Kc = %1.1f" % K for K in Ks]) plt.xlabel('Time [s]') plt.ylim(-0.5, 2.5) plt.show()
from utils import tf, feedback, tf_step import utilsplot import matplotlib.pyplot as plt import numpy as np s = tf([1,0], 1) G = 200/((10*s + 1)*(0.05*s + 1)**2) Gd = 100/(10*s + 1) wc = 10 K = wc*(10*s + 1)*(0.1*s + 1)/(200*s*(0.01*s + 1)) L = G*K t = np.linspace(0, 3) Sd = (1/(1 + G*K))*Gd T = feedback(L, 1) [t,y] = tf_step(T, 3) plt.figure('Figure 2.22') plt.subplot(1, 2, 1) plt.plot(t, y) plt.title('Tracking Response') plt.ylabel('y(t)') plt.xlabel('Time (s)') plt.ylim([0, 1.5]) [t,yd] = Sd.step(0, t) plt.subplot(1, 2, 2) plt.plot(t, yd) plt.ylabel('y(t)') plt.xlabel('Time (s)')
import matplotlib.pyplot as plt import numpy as np from utils import tf, feedback # Process model transfer function s = tf([1, 0]) G = (-s + 1)/(s + 1) # Controllers transfer function with various controller gains Ks = [Kc * ((s + 1)/s) * (1 / (0.05 * s + 1)) for Kc in [0.2, 0.5, 0.8]] # Complementary sensitivity transfer functions Ts = [feedback(G * K, 1) for K in Ks] plt.figure('Figure 5.7') w = np.logspace(-2, 2, 1000) wi = w * 1j plt.subplot(1, 2, 1) plt.title('(a) Sensitivity function') for T in Ts: S = 1 - T plt.loglog(w, abs(S(wi))) plt.xlabel('Frequency [rad/s]') plt.ylabel('Magnitude |S|') plt.legend(["Kc=0.2", "Kc=0.5", "Kc=0.8"], bbox_to_anchor=(0, 1.03, 1, 0), loc=3, ncol=3) plt.subplot(1, 2, 2) plt.title('(b) Response to step in reference') tspan = np.linspace(0, 5, 100)
#magnitude and phase plt.subplot(2, 1, 1) plt.loglog(w, abs(L(wi))) plt.loglog(w, np.ones_like(w)) plt.ylabel('Magnitude') plt.subplot(2, 1, 2) plt.semilogx(w, phase(L(wi), deg=True)) plt.semilogx(w, -180*np.ones_like(w)) plt.ylabel('Phase') plt.xlabel('frequency (rad/s)') plt.figure() # From the figure we can calculate GM and PM, # cross-over frequency wc and w180 # results:GM = 1/0.354 = 2.82 # PM = -125.3 + 180 = 54 degC # w180 = 0.44 # wc = 0.15 #Response to step in reference for loop shaping design #y = Tr, r(t) = 1 for t > 0 T = feedback(L, 1) tspan = np.linspace(0, 50, 100) [t, y] = T.step(0, tspan) plt.plot(t, y) plt.xlabel('Time (s)') plt.grid() plt.show()
def freq_step_response_plot(G, K, Kc, t_end=50, freqtype='S', w_start=-2, w_end=2, axlim=None, points=1000): """ A subplot function for both the frequency response and step response for a controlled plant Parameters ---------- G : tf Plant transfer function. K : tf Controller transfer function. Kc : integer Controller constant. t_end : integer Time period which the step response should occur. freqtype : string (optional) Type of function to plot: ======== ================================== freqtype Type of function to plot ======== ================================== S Sensitivity function T Complementary sensitivity function L Loop function ======== ================================== Returns ------- Plot : matplotlib figure """ _, w, axlim = df.frequency_plot_setup(axlim, w_start, w_end, points) plt.subplot(1, 2, 1) # Controllers transfer function with various controller gains Ks = [(kc * K) for kc in Kc] Ts = [utils.feedback(G * Kss, 1) for Kss in Ks] if freqtype == 'S': Fs = [(1 - Tss) for Tss in Ts] plt.title('(a) Sensitivity function') plt.ylabel('Magnitude $|S|$') elif freqtype == 'T': Fs = Ts plt.title('(a) Complementary sensitivity function') plt.ylabel('Magnitude $|T|$') else: # freqtype=='L' Fs = [(G*Kss) for Kss in Ks] plt.title('(a) Loop function') plt.ylabel('Magnitude $|L|$') wi = w * 1j i = 0 for F in Fs: plt.loglog(w, abs(F(wi)), label='Kc={d%s}=' % Kc[i]) i += 1 plt.axis(axlim) plt.grid(b=None, which='both', axis='both') plt.xlabel('Frequency [rad/unit time]') plt.legend(["Kc = %1.2f" % k for k in Kc],loc=4) plt.subplot(1, 2, 2) plt.title('(b) Response to step in reference') tspan = numpy.linspace(0, t_end, points) for T in Ts: [t, y] = T.step(0, tspan) plt.plot(t, y) plt.plot(tspan, 0 * numpy.ones(points), ls='--') plt.plot(tspan, 1 * numpy.ones(points), ls='--') plt.axis(axlim) plt.xlabel('Time') plt.ylabel('$y(t)$')
from utilsplot import step_response_plot from utils import feedback, tf s = tf([1, 0], 1) Kd = 0.5 G = 5/((10*s + 1)*(s - 1)) Gd = Kd/((s + 1)*(0.2*s + 1)) K = 0.04/s * ((10*s + 1)**2)/((0.1*s + 1)**2) L = G * K # Transfer function between disturbance and output y S = feedback(1, L)*Gd # Transfer function between disturbance and controller input u Gu = -S*K plt.figure('Figure 5.16 (a)') plt.subplot(1, 2, 1) w = np.logspace(-2, 1, 1000) wi = w*1j plt.loglog(w, np.abs(G(wi))) plt.loglog(w, np.abs(Gd(wi))) plt.axhline(1, color='black', linestyle=':') plt.title('(a) $|G|$ & $|G_d|$ with $k_d$=0.5') plt.xlabel('Frequency [rad/s]') plt.ylabel('Magnitude')
s = tf([1, 0]) #Figure 5.8 G = (-s + 1)/(s + 1) Kcs = [0.1, 0.5, 0.9] K = -1*s/((1 + 0.02*s)*(1 + 0.05*s)) plt.figure('Figure 5.8') utilsplot.freq_step_response_plot(G, K, Kcs, 0.2, 'S') # Plot negative step response t = np.linspace(0, 0.2, 1000) u1 = np.ones(500) u2 = np.zeros(500) u = np.hstack((u1, u2)) plt.figure('Figure 5.8(b)') plt.title('(b) Response to step in reference') for Kc in Kcs: K2 = Kc * K T = feedback(G * K2, 1) tout, y, _ = T.lsim(u, t) plt.plot(tout, y) plt.plot(tout, u, color='black', linestyle='--', linewidth=0.25) plt.legend(["Kc = %1.1f" % Kc for Kc in Kcs]) plt.ylabel('y(t)') plt.xlabel('Time [s]') plt.show()