def __init__(self, sysIn, Name, Tab=None, systemInput=None): self.sys = sysIn self.Name = Name self.Tab = Tab self.systemInput = systemInput # Generate LaTeX of tf: Ys, Xs = control.tfdata(self.sys) Ys, Xs = Ys[0][0], Xs[0][0] Gs = "Eq(G(s),(" YStr = [] i = len(Ys) - 1 while i >= 0: if Ys[len(Ys) - i - 1] != 0: if i == 0: s = "{}".format(Ys[len(Ys) - i - 1]) else: s = "{}*s**({})".format(Ys[len(Ys) - i - 1], i) YStr.append(s) i -= 1 Gs += "+".join(YStr) Gs += ")/(" XStr = [] i = len(Xs) - 1 while i >= 0: if Xs[len(Xs) - i - 1] != 0: if i == 0: s = "{}".format(Xs[len(Xs) - i - 1]) else: s = "{}*s**({})".format(Xs[len(Xs) - i - 1], i) XStr.append(s) i -= 1 Gs += "+".join(XStr) Gs += "))" Gs = AF.number_shaver(Gs) Sys_Gs = parse_expr(Gs, evaluate=False) Sys_Gs_LaTeX = sympy.latex(Sys_Gs) self.Sys_Gs_LaTeX_L = r"$\displaystyle " self.Sys_Gs_LaTeX_N = "$" self.Sys_Gs_LaTeX_L += Sys_Gs_LaTeX self.Sys_Gs_LaTeX_N += Sys_Gs_LaTeX self.Sys_Gs_LaTeX_L += "$" self.Sys_Gs_LaTeX_N += "$" # Generate LaTeX of ss: try: A, B, C, D = control.ssdata(self.sys) self.Order = A.shape[0] x_vec = [] x_vec_diff = [] i = 1 while i <= self.Order: x_vec.append("x_{}(t)".format(i)) x_vec_diff.append("diff(x_{}(t),t)".format(i)) i += 1 x_vec = str(sympy.Matrix(x_vec)) x_vec_diff = str(sympy.Matrix(x_vec_diff)) A, B = AF.number_shaver(str(sympy.Matrix(A))), AF.number_shaver( str(sympy.Matrix(B))) C, D = AF.number_shaver(str(sympy.Matrix(C))), AF.number_shaver( str(sympy.Matrix(D))) self.SSx_LaTeX = AF.LaTeX("Eq(" + x_vec_diff + "," + A + "*" + x_vec + "+" + B + "*u(t))") self.SSy_LaTeX = AF.LaTeX("Eq(y(t)," + C + "*" + x_vec + "+" + D + "*u(t))") self.Sys_SS_LaTeX_L = r"$\displaystyle " + self.SSx_LaTeX + "$\n" + r"$\displaystyle " + self.SSy_LaTeX + "$" self.Sys_SS_LaTeX_N = "$" + self.SSx_LaTeX + "$\n$" + self.SSy_LaTeX + "$" except common_exceptions: NC(lvl=2, msg="Could not create LaTeX for state space", exc=sys.exc_info(), input=self.sys, func="SystemClass.__init__", win="System Control Window") self.SSx_LaTeX = "ERROR" self.SSy_LaTeX = "ERROR" self.Sys_SS_LaTeX_L = "ERROR" self.Sys_SS_LaTeX_N = "ERROR" # Combine LaTeX of ss and tf: self.CheckStability() try: self.Sys_LaTeX_L = "System: ${}$ \nBIBO-Stable: ${}$\nTransfer Function:\n".format( AF.LaTeX(AF.AstusParse(self.Name)), self.BIBOStabel ) + self.Sys_Gs_LaTeX_L + "\nState Space:\n" + self.Sys_SS_LaTeX_L self.Sys_LaTeX_N = "System: ${}$ \nBIBO-Stable: ${}$\nTransfer Function:\n".format( AF.LaTeX(AF.AstusParse(self.Name)), self.BIBOStabel ) + self.Sys_Gs_LaTeX_N + "\nState Space:\n" + self.Sys_SS_LaTeX_N except common_exceptions: NC(1, "Invalid Name (Could not convert name to LaTeX)", exc=sys.exc_info(), func="SystemClass.__init__", input=self.Name, win="System Control Window") raise Exception("Invalid Name (Could not convert name to LaTeX)")
def Display(self, sys1, Use_LaTeX=False, T=None, X0=0.0, U=0.0, Ufunc=""): """ Retrun value compatible as argument to init NC \n sys1 = System \n Use_LaTeX = bool \n T = Time steps at which the input is defined; values must be evenly spaced. \n X0 = Initial condition \n U = Input array giving input at each time T used for "Forced Response"-plot \n Ufunc = string (Name of the function that created U) """ try: with warnings.catch_warnings(): warnings.simplefilter("ignore") for i in self.canvas.p_plot_LIST: i.clear() Torig = T Uorig = U try: if T == None: syst = control.timeresp._get_ss_simo(sys1) T = scipy.signal.ltisys._default_response_times( syst.A, 500) # If U not given try to create using Ufunc. If Ufunc not given or creation failed set U and Ufunc to 0 if U == 0.0: if Ufunc != "": try: Function = parse_expr(AF.AstusParse(Ufunc)) s = sympy.symbols('s') evalfunc = sympy.lambdify( s, Function, modules=['numpy', 'sympy']) U = evalfunc(T) U = np.asarray(U) if type(U) == int or type( U) == float or U.shape == ( ): #This also catches the case exp(x) U = np.full_like(T, U) if U.shape != T.shape: raise Exception("Dimensions do not match") except common_exceptions: NC(2, "Could not interpret u(s)", exc=sys.exc_info(), input=Ufunc, win=self.window().windowTitle(), func=str(self.objectName()) + ".Display") Ufunc = "" if Ufunc == "": Ufunc = "0" except common_exceptions: NC(1, "Could not calculate time steps", exc=sys.exc_info(), input=sys1, win=self.window().windowTitle(), func=str(self.objectName()) + ".Display") self.Curr_Sys_LaTeX = str(sys1) #TODO: MAKE PROPER LaTeX self.Curr_Sys = (sys1, Torig, X0, Uorig, Ufunc, self.Curr_Sys_LaTeX) self.canvas.p_bode_plot_1.set_label('control-bode-magnitude') self.canvas.p_bode_plot_2.set_label('control-bode-phase') except common_exceptions: NC(1, "Could not prepare the control display", exc=sys.exc_info(), input=sys1, win=self.window().windowTitle(), func=str(self.objectName()) + ".Display") self.UseTeX(False) return try: # 0 oT, y = control.step_response(sys1, number_of_samples=500, T=T, X0=X0) self.canvas.p_step_response.plot( oT, y, c=App().PenColours["Red"].color().name(0)) except common_exceptions: NC(1, "Could not plot step response", exc=sys.exc_info(), input=sys1, win=self.window().windowTitle(), func=str(self.objectName()) + ".Display") self.canvas.p_step_response.set_title("N/A") try: # 1 oT, y = control.impulse_response(sys1, number_of_samples=500, T=T, X0=X0) self.canvas.p_impulse_response.plot( oT, y, c=App().PenColours["Red"].color().name(0)) except common_exceptions: NC(1, "Could not plot impulse response", exc=sys.exc_info(), input=sys1, win=self.window().windowTitle(), func=str(self.objectName()) + ".Display") self.canvas.p_impulse_response.set_title("N/A") try: # 2 oT, y, xout = control.forced_response(sys1, T=T, X0=X0, U=U) # pylint: disable=unused-variable self.canvas.p_forced_response.plot( oT, y, c=App().PenColours["Red"].color().name(0)) except common_exceptions: NC(1, "Could not plot forced response", exc=sys.exc_info(), input=sys1, win=self.window().windowTitle(), func=str(self.objectName()) + ".Display") self.canvas.p_forced_response.set_title("N/A") try: # 3+4 plt.figure( self.canvas.fig.number ) # set figure to current that .gfc() in control.bode_plot can find it control.bode_plot(sys1, dB=True, omega_num=500, App=App()) except common_exceptions: NC(1, "Could not generate Bode plot", exc=sys.exc_info(), input=sys1, win=self.window().windowTitle(), func=str(self.objectName()) + ".Display") self.canvas.p_bode_plot_1.set_title("N/A") try: # 5 plt.sca(self.canvas.p_nyquist_plot) control.nyquist_plot(sys1, number_of_samples=500, App=App()) except common_exceptions: NC(1, "Could not generate Nyquist plot", exc=sys.exc_info(), input=sys1, win=self.window().windowTitle(), func=str(self.objectName()) + ".Display") self.canvas.p_nyquist_plot.set_title("N/A") try: # 6 plt.sca(self.canvas.p_nichols_plot) control.nichols_plot(sys1, number_of_samples=500) except common_exceptions: NC(1, "Could not generate Nichols plot", exc=sys.exc_info(), input=sys1, win=self.window().windowTitle(), func=str(self.objectName()) + ".Display") self.canvas.p_nichols_plot.set_title("N/A") try: # 7 poles, zeros = control.pzmap(sys1, Plot=False) if len(poles) > 0: self.canvas.p_pzmap.scatter( np.real(poles), np.imag(poles), s=50, marker='x', c=App().PenColours["Red"].color().name(0)) if len(zeros) > 0: self.canvas.p_pzmap.scatter( np.real(zeros), np.imag(zeros), s=25, marker='o', c=App().PenColours["Orange"].color().name(0)) self.canvas.p_pzmap.grid(True) except common_exceptions: NC(1, "Could not generate pole-zero-map", exc=sys.exc_info(), input=sys1, win=self.window().windowTitle(), func=str(self.objectName()) + ".Display") self.canvas.p_pzmap.set_title("N/A") try: # 8 #plt.sca(self.canvas.p_root_locus) #control.rlocus(sys1) control.root_locus_AMaDiA(sys1, self.canvas.p_root_locus, App=App()) self.canvas.p_root_locus.grid(True) except common_exceptions: NC(1, "Could not generate root locus plot", exc=sys.exc_info(), input=sys1, win=self.window().windowTitle(), func=str(self.objectName()) + ".Display") self.canvas.p_root_locus.set_title("N/A") # 9 + Plot self.SetColour() # Set Colour, Titles, etc... and the Display self.UseTeX(False)
def Plot(self, system, PlotName): """ Plot the plot "Plotname" """ ret = False self.FuncLabel = "" Titles = MplCanvas_CONTROL.Titles (sys1, T, X0, U, Ufunc, Curr_Sys_LaTeX) = system # pylint: disable=unused-variable try: if T == None: syst = control.timeresp._get_ss_simo(sys1) T = scipy.signal.ltisys._default_response_times(syst.A, 5000) except common_exceptions: pass self.clear() # Plot the Plot try: if PlotName == Titles[0]: oT, y = control.step_response(sys1, number_of_samples=5000, T=T, X0=X0) self.canvas.ax.plot(oT, y) elif PlotName == Titles[1]: oT, y = control.impulse_response(sys1, number_of_samples=5000, T=T, X0=X0) self.canvas.ax.plot(oT, y) elif PlotName == Titles[2]: # If U not given try to create using Ufunc. If Ufunc not given or creation failed set U and Ufunc to 0 if U == 0.0: if Ufunc != "": try: Function = parse_expr(AF.AstusParse(Ufunc)) s = sympy.symbols('s') evalfunc = sympy.lambdify( s, Function, modules=['numpy', 'sympy']) U = evalfunc(T) U = np.asarray(U) if type(U) == int or type( U) == float or U.shape == ( ): #This also catches the case exp(s) U = np.full_like(T, U) if U.shape != T.shape: raise Exception("Dimensions do not match") except common_exceptions: NC(2, "Could not interpret u(s)", exc=sys.exc_info(), input=Ufunc, win=self.window().windowTitle(), func=str(self.objectName()) + ".Plot") Ufunc = "" if Ufunc == "": Ufunc = "0" self.FuncLabel = "u(s) = " + Ufunc oT, y, xout = control.forced_response(sys1, T=T, X0=X0, U=U) # pylint: disable=unused-variable self.canvas.ax.plot(oT, y, label="Response") self.canvas.ax.plot(T, U, label="Input Function: u(s) = " + Ufunc) elif PlotName == Titles[3] or PlotName == Titles[ 4] or PlotName == " ": self.Bode = True self.canvas.ax1 = self.canvas.ax.twinx() self.canvas.ax1.axis('off') self.canvas.ax1.axis('on') self.canvas.ax.set_label('control-bode-magnitude') self.canvas.ax1.set_label('control-bode-phase') plt.figure(self.canvas.fig.number) control.bode_plot(sys1, dB=True, omega_num=5000, Dense_Phase_Major_Ticks=True, margins=True, App=App()) elif PlotName == Titles[5]: plt.sca(self.canvas.ax) control.nyquist_plot(sys1, number_of_samples=5000, App=App()) self.FuncLabel = "Nyquist" elif PlotName == Titles[6]: plt.sca(self.canvas.ax) control.nichols_plot(sys1, number_of_samples=5000) elif PlotName == Titles[7]: poles, zeros = control.pzmap(sys1, Plot=False) if len(poles) > 0: self.canvas.ax.scatter( np.real(poles), np.imag(poles), s=50, marker='x', c=App().PenColours["Red"].color().name(0)) if len(zeros) > 0: self.canvas.ax.scatter( np.real(zeros), np.imag(zeros), s=25, marker='o', c=App().PenColours["Orange"].color().name(0)) self.canvas.ax.grid(True) elif PlotName == Titles[8]: control.root_locus_AMaDiA(sys1, self.canvas.ax, App=App()) self.canvas.ax.grid(True) self.canvas.ax.legend() else: # LaTeX Display (Uses Title as display string) # This can currently not occur #NC(2,"The system display can not be magnified yet",input=sys1,win=self.window().windowTitle(),func=str(self.objectName())+".Plot") return False # Get Plotname if PlotName == Titles[3] or PlotName == Titles[ 4] or PlotName == " ": self.Title = Titles[3] else: self.Title = PlotName #Colour everything and draw it ret = self.SetColour() self.lim_y_0 = self.canvas.ax.get_ylim() self.lim_x_0 = self.canvas.ax.get_xlim() self.scale_y_0 = self.canvas.ax.get_yscale() self.scale_x_0 = self.canvas.ax.get_xscale() if self.Bode: self.lim_y_1 = self.canvas.ax1.get_ylim() self.lim_x_1 = self.canvas.ax1.get_xlim() self.scale_y_1 = self.canvas.ax1.get_yscale() self.scale_x_1 = self.canvas.ax1.get_xscale() else: self.lim_y_1 = None self.lim_x_1 = None self.scale_y_1 = None self.scale_x_1 = None self.lim_scale_setting = True except common_exceptions: NC(1, "Could not plot {}".format(str(PlotName)), exc=sys.exc_info(), input="System:\n{}\n\nPlot: {}".format(str(sys1), str(PlotName)), win=self.window().windowTitle(), func=str(self.objectName()) + ".Plot") self.UseTeX(False) return False self.UseTeX(False) return ret
def ControlSystems_1_System_Save(self): Tab = self.ControlSystems_1_System_tabWidget.currentIndex() sys1 = None try: NameInvalid = False Name = AF.AstusParse( self.ControlSystems_1_NameInput.text()).strip() if Name == "" or " " in Name: #IMPROVE: Better checks for System Name!!! NameInvalid = True if NameInvalid: NC(1, "System Name Invalid", func="AMaDiA_Control_Window.ControlSystems_1_System_Save", win=self.windowTitle(), input=Name) return False if Tab == 0: #Autoarrange Transfer Function # Parse the input and find out the coefficients of the powers of s systemInput = (self.ControlSystems_1_System_4ATF_Ys.text(), self.ControlSystems_1_System_4ATF_Xs.text()) s = sympy.symbols("s") # FEATURE: check if s or z is in systemInput and create a time discrete system if it is z and add a field to THIS TAB to set the Abtastzeit try: success = False mult = 0 Yt = "(" + self.ControlSystems_1_System_4ATF_Ys.text( ) + ")" Xt = "(" + self.ControlSystems_1_System_4ATF_Xs.text( ) + ")" termsY, termsX = "Fail", "Fail" while not success: try: Ys_s = sympy.expand( parse_expr(AF.AstusParse(Yt)).doit().evalf()) print(type(Ys_s), Ys_s) if type(Ys_s) == type(parse_expr("1/s")): pass Ys_r = sympy.poly(Ys_s, s) termsY = Ys_r.all_terms() Xs_s = sympy.expand( parse_expr(AF.AstusParse(Xt)).doit().evalf()) Xs_r = sympy.poly(Xs_s, s) termsX = Xs_r.all_terms() success = True except: Yt += "*s" Xt += "*s" mult += 1 if mult > 20: NC(msg="Could not normalize", exc=sys.exc_info(), func= "AMaDiA_Control_Window.ControlSystems_1_System_Save", win=self.windowTitle(), input="Input:{}\nX:{}\nY:{}".format( self.ControlSystems_1_System_4ATF_Ys. text(), str(termsY), str(termsX))) return False temp_list_y = [] temp_list_x = [] for i in termsY: temp_list_y.append(int(i[0][0])) for i in termsX: temp_list_x.append(int(i[0][0])) while min(temp_list_y) < 0 or min(temp_list_x) < 0: Yt += "*s" Xt += "*s" Ys_r = sympy.poly( sympy.expand( parse_expr(AF.AstusParse(Yt)).doit().evalf()), s) termsY = Ys_r.all_terms() Xs_r = sympy.poly( sympy.expand( parse_expr(AF.AstusParse(Xt)).doit().evalf()), s) termsX = Xs_r.all_terms() temp_list_y = [] temp_list_x = [] for i in termsY: temp_list_y.append(int(i[0][0])) for i in termsX: temp_list_x.append(int(i[0][0])) mult += 1 if mult > 20: raise Exception( "Could not normalize\nX:{}\nY:{}".format( str(termsY), str(termsX))) Ys = [] for i in termsY: Ys.append(float(i[1])) print(Ys) except common_exceptions: NC(msg="Error in Y(s)", exc=sys.exc_info(), func= "AMaDiA_Control_Window.ControlSystems_1_System_Save", win=self.windowTitle(), input=self.ControlSystems_1_System_4ATF_Ys.text()) return False try: Xs = [] for i in termsX: Xs.append(float(i[1])) print(Xs) except common_exceptions: NC(msg="Error in X(s)", exc=sys.exc_info(), func= "AMaDiA_Control_Window.ControlSystems_1_System_Save", win=self.windowTitle(), input=self.ControlSystems_1_System_4ATF_Xs.text()) return False sys1 = control.tf(Ys, Xs) elif Tab == 1: #Transfer Ys, YsI = [], [] Xs, XsI = [], [] MError = "" for j in range(self.ControlSystems_1_System_1TF_tableWidget. columnCount()): try: if self.ControlSystems_1_System_1TF_tableWidget.item( 0, j ) != None and self.ControlSystems_1_System_1TF_tableWidget.item( 0, j).text().strip() != "": Ys.append( float( parse_expr( AF.AstusParse( self. ControlSystems_1_System_1TF_tableWidget .item(0, j).text(), True)).doit().evalf())) else: Ys.append(0) except common_exceptions: MError += "Could not add item to System at ({},{}). Inserting a Zero instead. ".format( 1, j + 1) #MError += ExceptionOutput(sys.exc_info()) MError += "\n" Ys.append(0) try: if self.ControlSystems_1_System_1TF_tableWidget.item( 1, j ) != None and self.ControlSystems_1_System_1TF_tableWidget.item( 1, j).text().strip() != "": Xs.append( float( parse_expr( AF.AstusParse( self. ControlSystems_1_System_1TF_tableWidget .item(1, j).text(), True)).doit().evalf())) else: Xs.append(0) except common_exceptions: MError += "Could not add item to System at ({},{}). Inserting a Zero instead. ".format( 2, j + 1) #MError += ExceptionOutput(sys.exc_info()) MError += "\n" Xs.append(0) YsI.append(Ys[j]) XsI.append(Xs[j]) systemInput = ( YsI, XsI, self.ControlSystems_1_System_1TF_tableWidget.columnCount() - 1) if MError != "": NC(2, MError, func= "AMaDiA_Control_Window.ControlSystems_1_System_Save", win=self.windowTitle(), input="X(s) = {}\nY(s) = {}".format(str(Xs), str(Ys))) # Remove empty leading entries while Ys[0] == 0: Ys.pop(0) while Xs[0] == 0: Xs.pop(0) #print(Ys,r"/",Xs) sys1 = control.tf(Ys, Xs) elif Tab == 2: #State System A, B, C, D = [], [], [], [] # Loading A MError = "" for i in range(self.ControlSystems_1_System_2SS_A_tableWidget. rowCount()): A.append([]) for j in range( self.ControlSystems_1_System_2SS_A_tableWidget. columnCount()): try: if self.ControlSystems_1_System_2SS_A_tableWidget.item( i, j ) != None and self.ControlSystems_1_System_2SS_A_tableWidget.item( i, j).text().strip() != "": A[i].append( float( parse_expr( AF.AstusParse( self. ControlSystems_1_System_2SS_A_tableWidget .item(i, j).text(), False)).doit().evalf())) else: A[i].append(0) except common_exceptions: MError += "Could not add item to A at ({},{}). Inserting a Zero instead. ".format( i + 1, j + 1) MError += ExceptionOutput(sys.exc_info()) MError += "\n" A[i].append(0) # Loading B for j in range(self.ControlSystems_1_System_2SS_B_tableWidget. rowCount()): try: if self.ControlSystems_1_System_2SS_B_tableWidget.item( j, 0 ) != None and self.ControlSystems_1_System_2SS_B_tableWidget.item( j, 0).text().strip() != "": B.append([ float( parse_expr( AF.AstusParse( self. ControlSystems_1_System_2SS_B_tableWidget .item(j, 0).text(), False)).doit().evalf()) ]) else: B.append([0]) except common_exceptions: MError += "Could not add item to B at ({},{}). Inserting a Zero instead. ".format( j + 1, 1) MError += ExceptionOutput(sys.exc_info()) MError += "\n" B.append([0]) # Loading C for j in range(self.ControlSystems_1_System_2SS_C_tableWidget. columnCount()): try: if self.ControlSystems_1_System_2SS_C_tableWidget.item( 0, j ) != None and self.ControlSystems_1_System_2SS_C_tableWidget.item( 0, j).text().strip() != "": C.append( float( parse_expr( AF.AstusParse( self. ControlSystems_1_System_2SS_C_tableWidget .item(0, j).text(), False)).doit().evalf())) else: C.append(0) except common_exceptions: MError += "Could not add item to C at ({},{}). Inserting a Zero instead. ".format( 1, j + 1) MError += ExceptionOutput(sys.exc_info()) MError += "\n" C.append(0) # Loading D for i in range(self.ControlSystems_1_System_2SS_D_tableWidget. rowCount()): D.append([]) for j in range( self.ControlSystems_1_System_2SS_D_tableWidget. columnCount()): try: if self.ControlSystems_1_System_2SS_D_tableWidget.item( i, j ) != None and self.ControlSystems_1_System_2SS_D_tableWidget.item( i, j).text().strip() != "": D[i].append( float( parse_expr( AF.AstusParse( self. ControlSystems_1_System_2SS_D_tableWidget .item(i, j).text(), False)).doit().evalf())) else: D[i].append(0) except common_exceptions: MError += "Could not add item to D at ({},{}). Inserting a Zero instead. ".format( i + 1, j + 1) MError += ExceptionOutput(sys.exc_info()) MError += "\n" D[i].append(0) # Send Errors if MError != "": NC(2, MError, func= "AMaDiA_Control_Window.ControlSystems_1_System_Save", win=self.windowTitle(), input="A:\n{}\n\nB:\n{}\n\nC:\n{}\n\nD:\n{}".format( str(A), str(B), str(C), str(D))) # Creating System systemInput = (A, B, C, D) sys1 = control.ss(A, B, C, D) elif Tab == 3: #ODE raise Exception("ODE Input is not implemented yet") else: # Can not occur... raise Exception( "Tab {} in Control->Input Tab is unknown".format(str(Tab))) sysObject = SystemClass(sys1, Name, Tab, systemInput) self.ControlSystems_1_System_Display_LaTeX(sysObject) self.ControlSystems_1_SystemList.addItem(sysObject.Item()) # TODO: Deal with duplicated names # REMINDER: Save duplicate in other list item to prevent accidental overwrites # REMINDER: Save deleted items in other list item to prevent accidental deletions print(sys1) return sysObject except common_exceptions: NC(exc=sys.exc_info(), func="AMaDiA_Control_Window.ControlSystems_1_System_Save", win=self.windowTitle(), input="Control->Input Tab Number = {}\nSystem: {}".format( str(Tab), str(sys1))) return False