def ref_perfect_const_plot(G, R, wr, w_start=-2, w_end=2, axlim=None, points=1000, plot_type='all'): """ Use these plots to determine the constraints for perfect control in terms of combined reference changes. Equation 6.52 (p241) calculates the minimal requirement for input saturation to check in terms of set point tracking. A more tighter bounds is calculated with equation 6.53 (p241). Parameters ---------- G : tf Plant transfer function. R : numpy matrix (n x n) Reference changes (usually diagonal with all elements larger than 1) wr : float Frequency up to witch reference tracking is required type_eq : string Type of plot: ========= ================================== plot_type Type of plot ========= ================================== minimal Minimal requirement, equation 6.52 tighter Tighter requirement, equation 6.53 allo All requirements ========= ================================== Returns ------- Plot : matplotlib figure Note ---- All the plots in this function needs to be larger than 1 for perfect control, otherwise input saturation will occur. """ s, w, axlim = df.frequency_plot_setup(axlim, w_start, w_end, points) lab1 = '$\sigma_{min} (G(jw))$' bound1 = [utils.sigmas(G(si), 'min') for si in s] lab2 = '$\sigma_{min} (R^{-1}G(jw))$' bound2 = [utils.sigmas(numpy.linalg.pinv(R) * G(si), 'min') for si in s] if plot_type == 'all': plt.loglog(w, bound1, label=lab1) plt.loglog(w, bound2, label=lab2) elif plot_type == 'minimal': plt.loglog(w, bound1, label=lab1) elif plot_type == 'tighter': plt.loglog(w, bound2, label=lab2) else: raise ValueError('Invalid plot_type parameter.') mm = bound1 + bound2 + [1] # ensures that whole graph is visible plt.loglog([wr, wr], [0.5 * numpy.min(mm), 5 * numpy.max(mm)], 'r', ls=':', label='Ref tracked') plt.loglog([w[0], w[-1]], [1, 1], 'r', label='Bound') plt.legend()
def uncertAnalisys(): #Aditive uncertainty Function ============================== def WA(s): K = 9 ta1 = 1./0.35 Wa = K/((ta1*s + 1)) return(np.abs(Wa)) #Multiplicative uncertainty Function ======================= def WM(s): tm1 = 1./0.09 tm2 = 1./0.25 Wm = (tm1*s + 0.2)/((tm2*s + 1)) return(np.abs(Wm)) def M(s): Ma = -WA(s) * Kc(s) * S(s) Mm = -WM(s) * T(s) return(Ma, Mm) w = np.logspace(-3,0,1000) Mat = np.zeros((len(w))) Mmt = np.zeros((len(w))) Su = np.zeros((len(w))) Tu = np.zeros((len(w))) WI = np.zeros((len(w))) for i in range(len(w)): Ma, Mm = M(w[i]*1j) Mat[i] = utils.sigmas(Ma)[0] Mmt[i] = utils.sigmas(Mm)[0] WI[i] = np.abs(WM(w[i]*1j)) Su[i] = utils.sigmas(S(w[i]*1j))[0] Tu[i] = utils.sigmas(T(w[i]*1j))[0] plt.figure(8) plt.clf() plt.subplot(211) plt.semilogx(w, Mmt, 'r-', label = 'Multiplicative W$_O$') plt.semilogx(w, Mat, 'b-', label = 'Additive W$_A$') plt.axvline(wB_, color='blue', ls=':', lw='2') plt.text(wB_*1.1, np.max(Mmt)*0.9, 'req wB', color='blue') plt.axhline(1.0, color='blue', ls = ':', lw='2') plt.ylabel('Magnitude') plt.xlabel('Frequency [rad/s)]') plt.axis([None, None, None, None]) plt.grid(True) plt.legend(loc='upper left', fontsize = 12, ncol=5) plt.subplot(212) plt.loglog(w, Tu, 'r-') plt.loglog(w, 1/WI, 'k:', lw='2') plt.ylabel('Magnitude') plt.xlabel('Frequency [rad/s)]') plt.axis([None, None, None, None]) plt.text(0.2, np.max(Tu), '|T|$_{(not RS)}$', color='red') # plt.text(0.11, np.max(Tu)*0.4, '|T|$_{(RS)}$', color='green') plt.text(0.01, 5, '1/|W$_I$|') plt.grid(True) fig = plt.gcf() BG = fig.patch BG.set_facecolor('white') fig.subplots_adjust(bottom=0.2) fig.subplots_adjust(top=0.9) fig.subplots_adjust(left=0.2) fig.subplots_adjust(right=0.9)
def subbode(A, text, crossover, labB, labP): Sv = numpy.zeros((len(w), dim), dtype=complex) f = False wA = 0 for i in range(len(w)): Sv[i, :] = utils.sigmas(G(s[i])) if not f: if (labB == 'wC' and Sv[i, -1] < 1) or (labB == 'wB' and Sv[i, 0] > 0.707): wA = w[i] f = True ymin = numpy.min(Sv[:, -1]) if not sv_all: plt.loglog(w, Sv[:, 0], 'b', label=('$\sigma_{max}(%s)$') % labP) plt.loglog(w, Sv[:, -1], 'g', label=('$\sigma_{min}(%s)$') % labP) else: for j in range(dim): plt.loglog(w, Sv[:, j], label=('$\sigma_{%s}(%s)$' % (j, labP))) plt.axhline(crossover, ls=':', lw=2, color='r') if text: plt.axvline(wA, ls=':', lw=2, color='r') plt.text(wA*1.1, ymin*1.1, labB, color='r') plt.axis(axlim) plt.grid() plt.xlabel('Frequency [rad/unit time]') plt.ylabel('$\sigma$') plt.legend() return wA
def input_acceptable_const_plot(G, Gd, w_start=-2, w_end=2, axlim=None, points=1000, modified=False): """ Subbplots for input constraints for accepatable control. Applies equation 6.55 (p241). Parameters ---------- G : numpy matrix Plant model. Gd : numpy matrix Plant disturbance model. modified : boolean If true, the arguments in the equation are change to :math:`\sigma_1 (G) + 1 \geq |u_i^H g_d|`. This is to avoid a negative log scale. Returns ------- Plot : matplotlib figure Note ---- This condition only holds for :math:`|u_i^H g_d|>1`. """ s, w, axlim = df.frequency_plot_setup(axlim, w_start, w_end, points) freqresp = [G(si) for si in s] sig = numpy.array([utils.sigmas(Gfr) for Gfr in freqresp]) one = numpy.ones(points) plot_No = 1 dimGd = numpy.shape(Gd(0))[1] dimG = numpy.shape(G(0))[0] acceptable_control = numpy.zeros((dimGd, dimG, points)) for j in range(dimGd): for i in range(dimG): for k in range(points): U, _, _ = utils.SVD(G(s[k])) acceptable_control[j, i, k] = numpy.abs(U[:, i].H * Gd(s[k])[:, j]) plt.subplot(dimG, dimGd, plot_No) if not modified: plt.loglog(w, sig[:, i], label=('$\sigma_%s$' % (i + 1))) plt.plot(w, acceptable_control[j, i] - one, label=('$|u_%s^H.g_{d%s}|-1$' % (i + 1, j + 1))) else: plt.loglog(w, sig[:, i] + one, label=('$\sigma_%s+1$' % (i + 1))) plt.plot(w, acceptable_control[j, i], label=('$|u_%s^H.g_{d%s}|$' % (i + 1, j + 1))) plt.loglog([w[0], w[-1]], [1, 1], 'r', ls=':', label='Applicable') plt.xlabel('Frequency [rad/unit time]') plt.grid(True) plt.axis(axlim) plt.legend() plot_No += 1
def subbode(A, text, crossover, labB, labP): Sv = numpy.zeros((len(w), dim), dtype=complex) f = False wA = 0 for i in range(len(w)): Sv[i, :] = utils.sigmas(G(s[i])) if not f: if ((labB == 'wC' and Sv[i, -1] < 1) or (labB == 'wB' and Sv[i, 0] > 0.707)): wA = w[i] f = True ymin = numpy.min(Sv[:, -1]) if not sv_all: plt.loglog(w, Sv[:, 0], 'b', label=('$\sigma_{max}(%s)$') % labP) plt.loglog(w, Sv[:, -1], 'g', label=('$\sigma_{min}(%s)$') % labP) else: for j in range(dim): plt.loglog(w, Sv[:, j], label=('$\sigma_{%s}(%s)$' % (j, labP))) plt.axhline(crossover, ls=':', lw=2, color='r') if text: plt.axvline(wA, ls=':', lw=2, color='r') plt.text(wA*1.1, ymin*1.1, labB, color='r') # This function does not seem to do anything, since axlim is a list of # none values. See doc_func.py.frequency_spot_setup # plt.axis(axlim) plt.grid() plt.xlabel('Frequency [rad/unit time]') plt.ylabel('$\sigma$') plt.legend(loc=legend_loc) return wA
def subbode(A, text, crossover, labB, labP): Sv = numpy.zeros((len(w), dim), dtype=complex) f = False wA = 0 for i in range(len(w)): Sv[i, :] = utils.sigmas(G(s[i])) if not f: if ((labB == 'wC' and Sv[i, -1] < 1) or (labB == 'wB' and Sv[i, 0] > 0.707)): wA = w[i] f = True ymin = numpy.min(Sv[:, -1]) if not sv_all: plt.loglog(w, Sv[:, 0], 'b', label=('$\sigma_{max}(%s)$') % labP) plt.loglog(w, Sv[:, -1], 'g', label=('$\sigma_{min}(%s)$') % labP) else: for j in range(dim): plt.loglog(w, Sv[:, j], label=('$\sigma_{%s}(%s)$' % (j, labP))) plt.axhline(crossover, ls=':', lw=2, color='r') if text: plt.axvline(wA, ls=':', lw=2, color='r') plt.text(wA * 1.1, ymin * 1.1, labB, color='r') plt.axis(axlim) plt.grid() plt.xlabel('Frequency [rad/unit time]') plt.ylabel('$\sigma$') plt.legend() return wA
def input_acceptable_const_plot(G, Gd, w_start=-2, w_end=2, axlim=None, points=1000, modified=False): """ Subplots for input constraints for acceptable control. Applies equation 6.55 (p241). Parameters ---------- G : numpy matrix Plant model. Gd : numpy matrix Plant disturbance model. modified : boolean If true, the arguments in the equation are changed to :math:`\sigma_1 (G) + 1 \geq |u_i^H g_d|`. This is to avoid a negative log scale. Returns ------- Plot : matplotlib figure Note ---- This condition only holds for :math:`|u_i^H g_d|>1`. """ s, w, axlim = df.frequency_plot_setup(axlim, w_start, w_end, points) freqresp = [G(si) for si in s] sig = numpy.array([utils.sigmas(Gfr) for Gfr in freqresp]) one = numpy.ones(points) plot_No = 1 dimGd = numpy.shape(Gd(0))[1] dimG = numpy.shape(G(0))[0] acceptable_control = numpy.zeros((dimGd, dimG, points)) for j in range(dimGd): for i in range(dimG): for k in range(points): U, _, _ = utils.SVD(G(s[k])) acceptable_control[j, i, k] = numpy.abs(U[:, i].H * Gd(s[k])[:, j]) plt.subplot(dimG, dimGd, plot_No) if not modified: plt.loglog(w, sig[:, i], label=('$\sigma_%s$' % (i + 1))) plt.plot(w, acceptable_control[j, i] - one, label=('$|u_%s^H.g_{d%s}|-1$' % (i + 1, j + 1))) else: plt.loglog(w, sig[:, i] + one, label=('$\sigma_%s+1$' % (i + 1))) plt.plot(w, acceptable_control[j, i], label=('$|u_%s^H.g_{d%s}|$' % (i + 1, j + 1))) plt.loglog([w[0], w[-1]], [1, 1], 'r', ls=':', label='Applicable') plt.xlabel('Frequency [rad/unit time]') plt.grid(True) plt.axis(axlim) plt.legend() plot_No += 1
def distRej(): w = np.logspace(-3,0,1000) S1 = np.zeros((len(w))) S2 = np.zeros((len(w))) Gd1 = np.zeros((len(w))) distCondNum = np.zeros((len(w))) condNum = np.zeros((len(w))) for i in range(len(w)): U, Sv, V = utils.SVD(S(w[i]*1j)) S1[i] = Sv[0] #S = 1/|L + 1| S2[i] = Sv[2] Gd1[i], distCondNum[i] = utils.distRej(G(w[i]*1j), Gd(w[i]*1j)) condNum[i] = utils.sigmas(G(w[i]*1j),)[0]*utils.sigmas(la.inv(G(w[i]*1j)))[0] plt.figure(5) plt.clf() plt.subplot(211) plt.loglog(w, S1, 'r-', label = 'max $\sigma$S') plt.loglog(w, S2, 'r-', alpha = 0.4, label = 'min $\sigma$S') plt.loglog(w, Gd1, 'k-', label = '1/||Gd||$_2$') plt.axvline(wB, color='green') plt.ylabel('Magnitude') plt.xlabel('Frequency [rad/s)]') plt.text(wB*1.1, 0.015, 'wB = %s rad/s'%(np.round(wB,3)), color='green') plt.axis([None, None, None, 10]) plt.grid(True) plt.legend(loc='upper left', fontsize = 12, ncol=5) fig = plt.gcf() BG = fig.patch BG.set_facecolor('white') plt.subplot(212) plt.semilogx(w, distCondNum, 'r-', label = 'Dist CondNum') plt.semilogx(w, condNum, 'k-', label = 'CondNum') plt.axvline(wB, color='green') plt.ylabel('Disturbance condtion number') plt.xlabel('Frequency [rad/s)]') plt.text(wB*1.1, 0.2, 'wB = %s rad/s'%(np.round(wB,3)), color='green') plt.axis([None, None, 0, None]) plt.legend(loc='upper left', fontsize = 12, ncol=5) plt.grid(True) fig = plt.gcf() BG = fig.patch BG.set_facecolor('white') fig.subplots_adjust(bottom=0.2) fig.subplots_adjust(top=0.9) fig.subplots_adjust(left=0.2) fig.subplots_adjust(right=0.9)
def sv_plot(G, axlim=None, w_start=-2, w_end=2, points=100): ''' Plot of Maximum and minimum singular values of a matirix Parameters ---------- G : numpy array plant model or sensitivity function Returns ------- fig(Max Min SV) : figure A figure of the maximum and minimum singular values of the matrix G Note ---- Can be used with the plant matrix G and the sensitivity function S for controlability analysis ''' if axlim is None: axlim = [None, None, None, None] w = numpy.logspace(w_start, w_end, points) s = w * 1j freqresp = map(G, s) plt.figure('Min Max SV') plt.clf() plt.gcf().set_facecolor('white') plt.semilogx(w, [utils.sigmas(Gfr)[0] for Gfr in freqresp], label=('$\sigma$$_{MAX}$'), color='blue') plt.semilogx(w, [utils.sigmas(Gfr)[-1] for Gfr in freqresp], label=('$\sigma$$_{MIN}$'), color='blue', alpha=0.5) plt.xlabel('Frequency (rad/unit time)') plt.axhline(1., color='red', ls=':') plt.legend() plt.show() return
def sv_plot(G, axlim=[None, None, None, None], w_start=-2, w_end=2, points=100): ''' Plot of Maximum and minimum singular values of a matirix Parameters ---------- G : numpy array plant model or sensitivity function Returns ------- fig(Max Min SV) : figure A figure of the maximum and minimum singular values of the matrix G Note ---- Can be used with the plant matrix G and the sensitivity function S for controlability analysis ''' w = numpy.logspace(w_start, w_end, points) s = w*1j freqresp = map(G, s) plt.figure('Min Max SV') plt.clf() plt.gcf().set_facecolor('white') plt.semilogx(w, [utils.sigmas(Gfr)[0] for Gfr in freqresp], label=('$\sigma$$_{MAX}$'), color='blue') plt.semilogx(w, [utils.sigmas(Gfr)[-1] for Gfr in freqresp], label=('$\sigma$$_{MIN}$'), color='blue', alpha=0.5) plt.xlabel('Frequency (rad/unit time)') plt.axhline(1., color='red', ls=':') plt.legend() plt.show() return
I = np.asmatrix(np.identity(2)) def G(s): """process transfer matrix""" return 1 / ((s ** 2) + a ** 2) * np.matrix([[s - a ** 2, a * (s + 1)], [-a * (s + 1), s - a ** 2]]) def K(s): """controller""" return I def T(s): """this is a special case where T_I(s)= T(s) """ return G(s) * K(s) * (I + G(s) * K(s)).I frequency = np.logspace(-3, 2, 1000) s = 1j * frequency max_singular_value_of_T = [max(utils.sigmas(T(si))) for si in s] mu_T = [max(np.abs(np.linalg.eigvals(T(si)))) for si in s] plt.loglog(frequency, max_singular_value_of_T, 'b') plt.loglog(frequency, mu_T, 'r') plt.legend(('max_singular_value(T)', 'mu(T)'), 'best', shadow=False) plt.xlabel('frequency') plt.ylabel('Magnitude') plt.show()
def dis_rejctn_plot(G, Gd, S, axlim=None, w_start=-2, w_end=2, points=100): ''' A subplot of disturbance conditition number to check for input saturation and a subplot of to see if the disturbances fall withing the bounds on the singular values of S. Parameters ---------- G : numpy array plant model Gd : numpy array plant disturbance model S : numpy array Sensitivity function Returns ------- fig(Condition number and performance objective) : figure A figure of the disturbance condition number and the bounds imposed by the singular values. Note ---- The disturbance condition number provides a measure of how a disturbance gd is aligned with the plant G. Alignment can vary between 1 and the condition number. For acceptable performance the singular values of S must fall below the inverse 2-norm of gd. ''' if axlim is None: axlim = [None, None, None, None] w = numpy.logspace(w_start, w_end, points) s = w * 1j dim = numpy.shape(G(0)) inv_norm_gd = numpy.zeros((dim[1], points)) condtn_nm_gd = numpy.zeros((dim[1], points)) for i in range(dim[1]): for k in range(points): inv_norm_gd[i, k], condtn_nm_gd[i, k] = utils.distRej( G(s[k]), Gd(s[k])[:, i]) s_min = [utils.sigmas(S(s[i]))[-1] for i in range(points)] s_max = [utils.sigmas(S(s[i]))[0] for i in range(points)] plt.figure('Condition number and performance objective') plt.clf() plt.gcf().set_facecolor('white') plt.subplot(2, 1, 1) for i in range(dim[1]): plt.loglog(w, condtn_nm_gd[i], label=('$\gamma$$_{d%s}$(G)' % (i + 1)), color='blue', alpha=((i + 1.) / dim[1])) plt.axhline(1., color='red', ls=':') plt.axis(axlim) plt.ylabel('$\gamma$$_d$(G)') plt.axhline(1., color='red', ls=':') plt.legend() plt.subplot(2, 1, 2) for i in range(dim[1]): plt.loglog(w, inv_norm_gd[i], label=('1/||g$_{d%s}$||$_2$' % (i + 1)), color='blue', alpha=((i + 1.) / dim[1])) plt.loglog(w, s_min, label=('$\sigma$$_{MIN}$'), color='green') plt.loglog(w, s_max, label=('$\sigma$$_{MAX}$'), color='green', alpha=0.5) plt.xlabel('Frequency (rad/unit time)') plt.ylabel('1/||g$_d$||$_2$') plt.axhline(1., color='red', ls=':') plt.legend() plt.show() return
def perfectControl(): #For perfect cotnrol w = np.logspace(-3,0,1000) Gd1 = np.zeros((len(w))) Gd2 = np.zeros((len(w))) Gd3 = np.zeros((len(w))) for i in range(len(w)): Gt = G(w[i]*1j) #Gt just a temp assignmnet for G Gdt = Gd(w[i]*1j) #Gdt just a temp assignmnet for Gd # Gd1[i] = la.norm(la.inv(Gt)*Gdt, ord=np.inf) Gd1[i] = utils.sigmas(la.inv(Gt)*Gdt)[0] Gd2[i] = utils.sigmas(la.inv(Gt)*Gdt)[1] Gd3[i] = utils.sigmas(la.inv(Gt)*Gdt)[2] plt.figure(6) plt.clf() plt.subplot(211) plt.semilogx(w, Gd1, 'r-', label = '|G$^{-1}$$_1$g$_d$|') plt.semilogx(w, Gd2, 'b-', label = '|G$^{-1}$$_2$g$_d$|') plt.semilogx(w, Gd3, 'k-', label = '|G$^{-1}$$_3$g$_d$|') plt.axvline(wB, color='green') plt.text(wB*1.1, np.max(Gd1), 'wB = %s rad/s'%(np.round(wB,3)), color='green') plt.ylabel('Magnitude') plt.xlabel('Frequency [rad/s)]') plt.axis([None, None, None, None]) plt.grid(True) plt.legend(loc='upper left', fontsize = 12, ncol=1) fig = plt.gcf() BG = fig.patch BG.set_facecolor('white') fig.subplots_adjust(bottom=0.2) fig.subplots_adjust(top=0.9) fig.subplots_adjust(left=0.2) fig.subplots_adjust(right=0.9) #For acceptable control S1 = np.zeros((len(w))) S2 = np.zeros((len(w))) S3 = np.zeros((len(w))) Gd1 = np.zeros((len(w))) Gd2 = np.zeros((len(w))) Gd3 = np.zeros((len(w))) for i in range(len(w)): U, Sv ,V = utils.SVD(G(w[i]*1j)) Gdt = Gd(w[i]*1j) #Gdt just a temp assignmnet for Gd S1[i] = Sv[0] S2[i] = Sv[1] S3[i] = Sv[2] Gd1[i] = np.max(np.abs(np.transpose(np.conj(U[0]))*Gdt) - 1) Gd2[i] = np.max(np.abs(np.transpose(np.conj(U[1]))*Gdt) - 1) Gd3[i] = np.max(np.abs(np.transpose(np.conj(U[2]))*Gdt) - 1) plt.subplot(212) plt.semilogx(w, S1, 'r-', label = '$\sigma$$_1$(G)') plt.semilogx(w, Gd1, 'r-', label = '|u$_1$$^H$g$_d$|', alpha = 0.4) plt.semilogx(w, S2, 'k-', label = '$\sigma$$_2$(G)') plt.semilogx(w, Gd2, 'k-', label = '|u$_2$$^H$g$_d$|', alpha = 0.4) plt.semilogx(w, S3, 'b-', label = '$\sigma$$_3$(G)') plt.semilogx(w, Gd3, 'b-', label = '|u$_3$$^H$g$_d$|', alpha = 0.4) plt.ylabel('Magnitude') plt.xlabel('Frequency [rad/s)]') plt.axis([None, None, None, None]) plt.grid(True) plt.legend(loc='upper right', fontsize = 12) fig = plt.gcf() BG = fig.patch BG.set_facecolor('white') fig.subplots_adjust(bottom=0.2) fig.subplots_adjust(top=0.9) fig.subplots_adjust(left=0.2) fig.subplots_adjust(right=0.9)
def dis_rejctn_plot(G, Gd, S=None, w_start=-2, w_end=2, axlim=None, points=1000): """ A subplot of disturbance condition number to check for input saturation (equation 6.43, p238). Two more subplots indicate if the disturbances fall withing the bounds of S, applying equations 6.45 and 6.46 (p239). Parameters ---------- G : numpy matrix Plant model. Gd : numpy matrix Plant disturbance model. S : numpy matrix Sensitivity function (optional, if available). # TODO test S condition Returns ------- Plot : matplotlib figure Note ---- The disturbance condition number provides a measure of how a disturbance gd is aligned with the plant G. Alignment can vary between 1 and the condition number. For acceptable performance the singular values of S must fall below the inverse 2-norm of gd. """ s, w, axlim = df.frequency_plot_setup(axlim, w_start, w_end, points) dim = numpy.shape(Gd(0))[1] # column count inv_norm_gd = numpy.zeros((dim, points)) # row count yd = numpy.zeros((dim, points, numpy.shape(Gd(0))[0]), dtype=complex) condtn_nm_gd = numpy.zeros((dim, points)) for i in range(dim): for k in range(points): inv_norm_gd[i, k], yd[i, k, :], condtn_nm_gd[i, k] = utils.distRej( G(s[k]), Gd(s[k])[:, i]) if S is None: sub = 2 else: sub = 3 # Equation 6.43 plt.subplot(sub, 1, 1) for i in range(dim): plt.loglog(w, condtn_nm_gd[i], label=('$\gamma_{d%s} (G)$' % (i + 1))) plt.axhline(1., color='red', ls=':') plt.axis(axlim) plt.xlabel('Frequency [rad/unit time]') plt.ylabel('$\gamma$$_d (G)$') plt.axhline(1., color='red', ls=':') plt.legend() # Equation 6.44 plt.subplot(sub, 1, 2) for i in range(dim): plt.loglog(w, inv_norm_gd[i], label=('$1/||g_{d%s}||_2$' % (i + 1))) if S is not None: S_yd = numpy.array([ numpy.linalg.norm(S(p) * yd[i, p, :].T, 2) for p in range(points) ]) plt.loglog(w, S_yd, label='$||Sy_d||_2$') plt.axis(axlim) plt.xlabel('Frequency [rad/unit time]') plt.legend() if S is not None: # subplot should not be repeated with S is not available # Equation 6.45 plt.subplot(3, 1, 3) for i in range(dim): plt.loglog(w, inv_norm_gd[i], label=('$1/||g_{d%s}||_2$' % (i + 1))) s_min = numpy.array( [utils.sigmas(S(s[p]), 'min') for p in range(points)]) s_max = numpy.array( [utils.sigmas(S(s[p]), 'max') for p in range(points)]) plt.loglog(w, s_min, label='$\sigma_{min}$') plt.loglog(w, s_max, label='$\sigma_{max}$') plt.axis(axlim) plt.xlabel('Frequency [rad/unit time]') plt.legend()
def cndtn_nm(G): return (utils.sigmas(G)[0] / utils.sigmas(G)[-1])
def dis_rejctn_plot(G, Gd, S=None, w_start=-2, w_end=2, axlim=None, points=1000): """ A subplot of disturbance condition number to check for input saturation (equation 6.43, p238). Two more subplots indicate if the disturbances fall withing the bounds of S, applying equations 6.45 and 6.46 (p239). Parameters ---------- G : numpy matrix Plant model. Gd : numpy matrix Plant disturbance model. S : numpy matrix Sensitivity function (optional, if available). # TODO test S condition Returns ------- Plot : matplotlib figure Note ---- The disturbance condition number provides a measure of how a disturbance gd is aligned with the plant G. Alignment can vary between 1 and the condition number. For acceptable performance the singular values of S must fall below the inverse 2-norm of gd. """ s, w, axlim = df.frequency_plot_setup(axlim, w_start, w_end, points) dim = numpy.shape(Gd(0))[1] # column count inv_norm_gd = numpy.zeros((dim, points)) yd = numpy.zeros((dim, points, numpy.shape(Gd(0))[0]), dtype=complex) # row count condtn_nm_gd = numpy.zeros((dim, points)) for i in range(dim): for k in range(points): inv_norm_gd[i, k], yd[i, k, :], condtn_nm_gd[i, k] = utils.distRej(G(s[k]), Gd(s[k])[:, i]) if S is None: sub = 2 else: sub = 3 # Equation 6.43 plt.subplot(sub, 1, 1) for i in range(dim): plt.loglog(w, condtn_nm_gd[i], label=('$\gamma_{d%s} (G)$' % (i+1))) plt.axhline(1., color='red', ls=':') plt.axis(axlim) plt.xlabel('Frequency [rad/unit time]') plt.ylabel('$\gamma$$_d (G)$') plt.axhline(1., color='red', ls=':') plt.legend() # Equation 6.44 plt.subplot(sub, 1, 2) for i in range(dim): plt.loglog(w, inv_norm_gd[i], label=('$1/||g_{d%s}||_2$' % (i+1))) if not S is None: S_yd = numpy.array([numpy.linalg.norm(S(p) * yd[i, p, :].T, 2) for p in range(points)]) plt.loglog(w, S_yd, label='$||Sy_d||_2$') plt.axis(axlim) plt.xlabel('Frequency [rad/unit time]') plt.legend() if S is not None: # this subplot should not be repeated with S is not available # Equation 6.45 plt.subplot(3, 1, 3) for i in range(dim): plt.loglog(w, inv_norm_gd[i], label=('$1/||g_{d%s}||_2$' % (i+1))) s_min = numpy.array([utils.sigmas(S(s[p]), 'min') for p in range(points)]) s_max = numpy.array([utils.sigmas(S(s[p]), 'max') for p in range(points)]) plt.loglog(w, s_min, label='$\sigma_{min}$') plt.loglog(w, s_max, label='$\sigma_{max}$') plt.axis(axlim) plt.xlabel('Frequency [rad/unit time]') plt.legend()
def condition_number(G): """Function to determine condition number""" sig = utils.sigmas(G) return max(sig) / min(sig)
def cndtn_nm(G): return utils.sigmas(G)[0]/utils.sigmas(G)[-1]
def maxsigma(G): return max(utils.sigmas(G))
def dis_rejctn_plot(G, Gd, S, axlim=[None, None, None, None], w_start=-2, w_end=2, points=100): ''' A subplot of disturbance conditition number to check for input saturation and a subplot of to see if the disturbances fall withing the bounds on the singular values of S. Parameters ---------- G : numpy array plant model Gd : numpy array plant disturbance model S : numpy array Sensitivity function Returns ------- fig(Condition number and performance objective) : figure A figure of the disturbance condition number and the bounds imposed by the singular values. Note ---- The disturbance condition number provides a measure of how a disturbance gd is aligned with the plant G. Alignment can vary between 1 and the condition number. For acceptable performance the singular values of S must fall below the inverse 2-norm of gd. ''' w = numpy.logspace(w_start, w_end, points) s = w*1j dim = numpy.shape(G(0)) inv_norm_gd = numpy.zeros((dim[1],points)) condtn_nm_gd = numpy.zeros((dim[1],points)) for i in range(dim[1]): for k in range(points): inv_norm_gd[i,k], condtn_nm_gd[i,k] = utils.distRej(G(s[k]), Gd(s[k])[:,i]) s_min = [utils.sigmas(S(s[i]))[-1] for i in range(points)] s_max = [utils.sigmas(S(s[i]))[0] for i in range(points)] plt.figure('Condition number and performance objective') plt.clf() plt.gcf().set_facecolor('white') plt.subplot(2,1,1) for i in range(dim[1]): plt.loglog(w, condtn_nm_gd[i], label=('$\gamma$$_{d%s}$(G)' % (i+1)), color='blue', alpha=((i+1.)/dim[1])) plt.axhline(1., color='red', ls=':') plt.axis(axlim) plt.ylabel('$\gamma$$_d$(G)') plt.axhline(1., color='red', ls=':') plt.legend() plt.subplot(2,1,2) for i in range(dim[1]): plt.loglog(w, inv_norm_gd[i], label=('1/||g$_{d%s}$||$_2$' % (i+1)), color='blue', alpha=((i+1.)/dim[1])) plt.loglog(w, s_min, label=('$\sigma$$_{MIN}$'), color='green') plt.loglog(w, s_max, label=('$\sigma$$_{MAX}$'), color='green', alpha = 0.5) plt.xlabel('Frequency (rad/unit time)') plt.ylabel('1/||g$_d$||$_2$') plt.axhline(1., color='red', ls=':') plt.legend() plt.show() return