Last active
September 26, 2020 21:34
-
-
Save carlos-adir/f66e581734c7a9b661b9f9211b8ce567 to your computer and use it in GitHub Desktop.
Ploting curves of Bode, Nichols and Nyquist using Tkinter as GUI and sympy to treat the expressions
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
########################## | |
# Ploting Control Graphs # | |
########################## | |
1. Esse é um código desenvolvido para fins de aprendizado, use-o conforme queira. Aproveite bem! | |
2. Para usa-lo, você precisa ter alguns requisitos instalados: | |
2.1) python3 - Linguagem de programação | |
2.2) numpy - Biblioteca de calculo do python | |
2.3) sympy - Biblioteca de calculo simbólico do python | |
2.4) control - Biblioteca para o calculo dos valores de ganho de fase, frequência e por aí vai. | |
2.5) tkinter - Biblioteca para fazer a parte gráfica, de interação com o usuário, com botões e entradas | |
2.6) matplotlib - Biblioteca para plotar os gráficos | |
Se você já instalar o Anaconda, que já vem com diversas bibliotecas dessas, você não encontrará nenhum problema. | |
3. Existem 3 variáveis no sistema, de nomes A, B e K nessa ordem. Você pode usa-las e alterar o valor como quiser. | |
Cada slider varia de 0 até 100, mas cada variável vai de 0 até 1. Ou seja, com o slider no 0, a variável vale 0, com o slider no 100, o slider vale 1. Com o slider no 50, a variável vale 0.5, e assim por diante. | |
Caso você precise de valores maiores, coloque na equação. Por exemplo, se precisar que slider varie de 0 até 50, então coloque A*50. | |
4. Se você clicar no exemplo do ultimo botão, ele colocará uma função de transferência qualquer. Você pode alterar os sliders e ver as alterações que acontece nos gráficos. Você também consegue alterar valores numéricos das funções. |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import tkinter as tk | |
import negocio | |
import numpy as np | |
import matplotlib.ticker as ticker | |
import gi | |
gi.require_version('Gtk', '3.0') | |
from gi.repository import Gtk | |
from matplotlib.figure import Figure | |
from matplotlib.backends.backend_gtk3agg import FigureCanvasGTK3Agg | |
from matplotlib.backends.backend_tkagg import ( | |
FigureCanvasTkAgg, NavigationToolbar2TkAgg) | |
# Implement the default Matplotlib key bindings. | |
from matplotlib.backend_bases import key_press_handler | |
from matplotlib.figure import Figure | |
def create_new_window(master, classe, *args): | |
Window = tk.Toplevel(master) | |
if classe == "BodeGain": | |
app = Window_BodeGainGraph(Window, args) | |
elif classe == "BodePhase": | |
app = Window_BodeGainPhase(Window, args) | |
elif classe == "Nichols": | |
app = Window_NicholsGraph(Window, args) | |
elif classe == "Nyquist": | |
app = Window_NyquistGraph(Window, args) | |
return app | |
class Window_Parameters: | |
def __init__(self, master): | |
self.master = master | |
self.frame_Entry = tk.Frame(self.master) | |
self.frame_Sliders = tk.Frame(self.master) | |
self.frame_Buttons = tk.Frame(self.master) | |
self.frame_Test = tk.Frame(self.master) | |
self.__init_Entry(self.frame_Entry) | |
self.__init_Sliders(self.frame_Sliders) | |
self.__init_Buttons(self.frame_Buttons) | |
self.__init_Test(self.frame_Test) | |
self.frame_Entry.pack() | |
self.frame_Sliders.pack() | |
self.frame_Buttons.pack() | |
self.frame_Test.pack() | |
self.master.title("Parameters") | |
def __init_Entry(self, frame): | |
######### Entry for Transfer function | |
if 1: # Numerador | |
tk.Label(frame, text="num: ").pack() | |
self.var_Numerator = tk.StringVar() | |
self.entry_Numerator = tk.Entry(frame, textvariable=self.var_Numerator, justify='center') | |
self.entry_Numerator.pack() | |
self.var_Numerator.trace('w', self.__changeEntry_Numerator) # The 'w' tells tkinter whenever somebody writes (updates) the variable, which would happen every time someone wrote something in the Entry widget, do __entryNumeratorFunctionChange. | |
if 1: # Denominator | |
tk.Label(frame, text="den: ").pack() | |
self.var_Denominator = tk.StringVar() | |
self.entry_Denominator = tk.Entry(frame, textvariable=self.var_Denominator, justify='center') | |
self.entry_Denominator.pack() | |
self.var_Denominator.trace('w', self.__changeEntry_Denominator) # The 'w' tells tkinter whenever somebody writes (updates) the variable, which would happen every time someone wrote something in the Entry widget, do __entryNumeratorFunctionChange. | |
def __init_Sliders(self, frame): | |
######### Sliders for variables | |
self.sliders = {} | |
for variable in negocio.slider_infos: | |
name = variable.get_name() | |
begin = variable.get_begin() | |
end = variable.get_end() | |
value = variable.get_value() | |
resolution = variable.get_resolution() | |
var = tk.DoubleVar() | |
slider = tk.Scale(frame, variable=var, from_=begin, to=end, resolution=resolution, orient=tk.HORIZONTAL) | |
slider.set(value) | |
slider.pack() | |
if name == "A": | |
func = self.__changeSlider_A | |
if name == "B": | |
func = self.__changeSlider_B | |
if name == "K": | |
func = self.__changeSlider_K | |
var.trace('w', func) | |
self.sliders[name] = (var, slider) | |
def __init_Buttons(self, frame): | |
######### Ploting Graphs | |
functions = {} | |
titles = {} | |
self.buttons = {} | |
names = ["BodeGain", "BodePhase", "Nichols", "Nyquist"] | |
functions["BodeGain"] = self.__changeButton_BodeGain | |
functions["BodePhase"] = self.__changeButton_BodePhase | |
functions["Nichols"] = self.__changeButton_Nichols | |
functions["Nyquist"] = self.__changeButton_Nyquist | |
titles["BodeGain"] = "Plot de " + str("BodeGain") | |
titles["BodePhase"] = "Plot de " + str("BodePhase") | |
titles["Nichols"] = "Plot de " + str("Nichols") | |
titles["Nyquist"] = "Plot de " + str("Nyquist") | |
for name in names: | |
self.buttons[name] = tk.Button(frame, text = titles[name], width = 25, | |
command = functions[name]) | |
self.buttons[name].pack() | |
def __init_Test(self, frame): | |
######### Test widget | |
if 1: # Button for Bode Gain Graph | |
self.button_Test = tk.Button(frame, text = 'Exemplo', width = 25, command = self.test_function) | |
self.button_Test.pack() | |
def __changeSlider_A(self, *args): | |
name = "A" | |
var, slider = self.sliders[name] | |
value = slider.get() | |
#print("type(A) = " + str(type(A)) + " A = " + str(A)) | |
manager.callbackA(value) | |
def __changeSlider_B(self, *args): | |
name = "B" | |
var, slider = self.sliders[name] | |
value = slider.get() | |
manager.callbackB(value) | |
def __changeSlider_K(self, *args): | |
name = "K" | |
var, slider = self.sliders[name] | |
value = slider.get() | |
manager.callbackK(value) | |
def __changeEntry_Numerator(self, *arg): | |
expr = self.entry_Numerator.get() | |
#print("Getting " + str(expr) + " from entry_Numerator") | |
manager.callbackNum(expr) | |
def __changeEntry_Denominator(self, *arg): | |
expr = self.entry_Denominator.get() | |
#print("Getting " + str(expr) + " from entry_Numerator") | |
manager.callbackDen(expr) | |
def set_stateEntry_Numerator(self, state): | |
if state == True: # Bom estado, correto, valido | |
self.entry_Numerator.config({"background": "#bbffbb"}) | |
else: | |
self.entry_Numerator.config({"background": "#ffbbbb"}) | |
def set_stateEntry_Denominator(self, state): | |
if state == True: # Bom estado, correto, valido | |
self.entry_Denominator.config({"background": "#bbffbb"}) | |
else: | |
self.entry_Denominator.config({"background": "#ffbbbb"}) | |
def __changeButton_BodeGain(self): | |
name = "BodeGain" | |
classe = classes[name] | |
if manager.can_new_window(name): | |
Window = tk.Toplevel(self.master) | |
app = classe(Window) | |
manager.set_app(name, app) | |
def __changeButton_BodePhase(self): | |
name = "BodePhase" | |
classe = classes[name] | |
if manager.can_new_window(name): | |
Window = tk.Toplevel(self.master) | |
app = classe(Window) | |
manager.set_app(name, app) | |
def __changeButton_Nichols(self): | |
name = "Nichols" | |
classe = classes[name] | |
if manager.can_new_window(name): | |
Window = tk.Toplevel(self.master) | |
app = classe(Window) | |
manager.set_app(name, app) | |
def __changeButton_Nyquist(self): | |
name = "Nyquist" | |
classe = classes[name] | |
if manager.can_new_window(name): | |
Window = tk.Toplevel(self.master) | |
app = classe(Window) | |
manager.set_app(name, app) | |
def test_function(self): | |
self.entry_Numerator.delete(0, tk.END) | |
self.entry_Numerator.insert(0, "1.2707*(1+s)*K") | |
self.entry_Denominator.delete(0, tk.END) | |
self.entry_Denominator.insert(0, "1.2707*(1+s)+(1+A*s)*(0.044212*s^2+0.41258*s+1)") | |
class Window_BodeGainGraph(Gtk.Window): | |
def __init__(self, master): | |
self.master = master | |
self.master.title("Bode Gain Graph") | |
self.frame = tk.Frame(self.master) | |
self.frame.pack() | |
self.x = np.logspace(-3, 3, 128) | |
self.y = np.log(self.x) | |
self.fig = Figure(figsize=(5, 4), dpi=100) | |
self.ax = self.fig.add_subplot(111) | |
self.lines, = self.ax.semilogx(self.x, self.y) | |
self.canvas = FigureCanvasTkAgg(self.fig, master=self.frame) # A tk.DrawingArea. | |
self.canvas.draw() | |
self.canvas.get_tk_widget().pack(side=tk.TOP, fill=tk.BOTH, expand=1) | |
self.toolbar = NavigationToolbar2TkAgg(self.canvas, self.frame) | |
self.toolbar.update() | |
self.canvas.get_tk_widget().pack(side=tk.TOP, fill=tk.BOTH, expand=1) | |
self.ax.set_xlim([10**(-4), 10**(4)]) | |
self.ax.yaxis.set_major_locator(ticker.MultipleLocator(20)) | |
self.ax.grid() | |
def update(self, w, gain, marginGain, marginPhase): | |
try: | |
mingain, maxgain = min(gain), max(gain) | |
if maxgain-mingain < 40: | |
dgain = 40 | |
else: | |
dgain = maxgain - mingain | |
ymin = mingain - dgain/4 | |
ymax = maxgain + dgain/4 | |
self.lines.set_xdata(w) | |
self.lines.set_ydata(gain) | |
self.canvas.draw_idle() | |
self.ax.set_ylim([ymin, ymax]) | |
except: | |
print("Problema no update do BodeGain") | |
def close_windows(self): | |
manager.set_app("BodeGain", None) | |
self.master.destroy() | |
class Window_BodePhaseGraph: | |
def __init__(self, master): | |
self.master = master | |
self.master.title("Bode Phase Graph") | |
self.frame = tk.Frame(self.master) | |
self.frame.pack() | |
self.x = np.logspace(-3, 3, 128) | |
self.y = np.log(self.x) | |
self.fig = Figure(figsize=(5, 4), dpi=100) | |
self.ax = self.fig.add_subplot(111) | |
self.lines, = self.ax.semilogx(self.x, self.y) | |
self.canvas = FigureCanvasTkAgg(self.fig, master=self.frame) # A tk.DrawingArea. | |
self.canvas.draw() | |
self.canvas.get_tk_widget().pack(side=tk.TOP, fill=tk.BOTH, expand=1) | |
self.toolbar = NavigationToolbar2TkAgg(self.canvas, self.frame) | |
self.toolbar.update() | |
self.canvas.get_tk_widget().pack(side=tk.TOP, fill=tk.BOTH, expand=1) | |
self.ax.set_xlim([10**(-4), 10**(4)]) | |
self.ax.yaxis.set_major_locator(ticker.MultipleLocator(45)) | |
self.ax.grid() | |
def update(self, w, phase, marginGain, marginPhase): | |
minphase, maxphase = min(phase), max(phase) | |
dphase = maxphase-minphase | |
self.lines.set_xdata(w) | |
self.lines.set_ydata(phase) | |
self.canvas.draw_idle() | |
self.ax.set_ylim([minphase-dphase/4, maxphase+dphase/4]) | |
def close_windows(self): | |
manager.app_BodePhase = None | |
self.master.destroy() | |
class Window_NicholsGraph: | |
def __init__(self, master): | |
self.master = master | |
self.master.title("Nichols Graph") | |
self.frame = tk.Frame(self.master) | |
self.frame.pack() | |
self.x = np.linspace(-360, 0, 128) | |
self.y = self.x | |
self.fig = Figure(figsize=(5, 4), dpi=100) | |
self.ax = self.fig.add_subplot(111) | |
self.lines, = self.ax.plot(self.x, self.y) | |
self.canvas = FigureCanvasTkAgg(self.fig, master=self.frame) # A tk.DrawingArea. | |
self.canvas.draw() | |
self.canvas.get_tk_widget().pack(side=tk.TOP, fill=tk.BOTH, expand=1) | |
self.toolbar = NavigationToolbar2TkAgg(self.canvas, self.frame) | |
self.toolbar.update() | |
self.canvas.get_tk_widget().pack(side=tk.TOP, fill=tk.BOTH, expand=1) | |
self.ax.set_xlim([-360, 0]) | |
self.ax.xaxis.set_major_locator(ticker.MultipleLocator(45)) | |
self.ax.yaxis.set_major_locator(ticker.MultipleLocator(20)) | |
self.ax.grid() | |
def update(self, phase, gain, marginGain, marginPhase): | |
mingain, maxgain = min(gain), max(gain) | |
if maxgain-mingain < 40: | |
dgain = 40 | |
else: | |
dgain = maxgain - mingain | |
ymin = mingain - dgain/4 | |
ymax = maxgain + dgain/4 | |
self.lines.set_xdata(phase) | |
self.lines.set_ydata(gain) | |
self.canvas.draw_idle() | |
self.ax.set_ylim([ymin, ymax]) | |
def close_windows(self): | |
manager.app_BodePhase = None | |
self.master.destroy() | |
class Window_NyquistGraph: | |
def __init__(self, master): | |
self.master = master | |
self.master.title("Nyquist Graph") | |
self.frame = tk.Frame(self.master) | |
self.frame.pack() | |
self.x = np.linspace(-3, 3, 128) | |
self.y = self.x | |
self.fig = Figure(figsize=(5, 4), dpi=100) | |
self.ax = self.fig.add_subplot(111) | |
self.lines1, = self.ax.plot(self.x, self.y, color='b') | |
self.lines2, = self.ax.plot(self.x, -self.y, color='b') | |
self.canvas = FigureCanvasTkAgg(self.fig, master=self.frame) # A tk.DrawingArea. | |
self.canvas.draw() | |
self.canvas.get_tk_widget().pack(side=tk.TOP, fill=tk.BOTH, expand=1) | |
self.toolbar = NavigationToolbar2TkAgg(self.canvas, self.frame) | |
self.toolbar.update() | |
self.canvas.get_tk_widget().pack(side=tk.TOP, fill=tk.BOTH, expand=1) | |
#self.ax.xaxis.set_major_locator(ticker.MultipleLocator(45)) | |
#self.ax.yaxis.set_major_locator(ticker.MultipleLocator(20)) | |
self.ax.grid() | |
def update(self, real, imag, marginGain, marginPhase, poles, zeros): | |
if len(poles) > 0: | |
maxp = max(abs(poles)) | |
else: | |
maxp = 1 | |
if len(zeros) > 0: | |
maxz = max(abs(zeros)) | |
else: | |
maxz = 1 | |
maxr = max(abs(real)) | |
maxi = max(abs(imag)) | |
if maxi > 5*maxr: | |
maxi = 0 | |
unit = max(maxz, maxp, maxr, maxi) | |
self.lines1.set_xdata( real) | |
self.lines1.set_ydata( imag) | |
self.lines2.set_xdata( real) | |
self.lines2.set_ydata(-imag) | |
self.canvas.draw_idle() | |
self.ax.set_xlim([-1.2*unit, +1.2*unit]) | |
self.ax.set_ylim([-1.2*unit, +1.2*unit]) | |
def close_windows(self): | |
manager.app_BodePhase = None | |
self.master.destroy() | |
classes = {} | |
classes["BodeGain"] = Window_BodeGainGraph | |
classes["BodePhase"] = Window_BodePhaseGraph | |
classes["Nichols"] = Window_NicholsGraph | |
classes["Nyquist"] = Window_NyquistGraph | |
if __name__ == '__main__': | |
root = tk.Tk() | |
app = Window_Parameters(root) | |
manager = negocio.ManagerParameter(app) | |
root.mainloop() |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import ast | |
import sympy as sp | |
from sympy.abc import s | |
from sympy.parsing.sympy_parser import parse_expr | |
import matplotlib.pyplot as plt | |
from scipy import signal | |
import control | |
import numpy as np | |
class Calcul: | |
def treatStr(string): | |
expr = expr.replace("^", "**") | |
if ',' in expr: | |
raise TypeError("Virgula nao eh separador decimal") | |
def strToSympyExpr(string): | |
expr = parse_expr(expr) # transform string to sympy expression | |
expr = expr.expand() | |
for var, value in variables.items(): | |
expr = expr.subs(var, value) | |
expr = expr.simplify() | |
def separateFraction(expr): | |
num, den = sp.fraction(expr) | |
return num, den | |
def convertExprToCoefs(expr, variables, verbose = False): | |
if verbose: print("hum1") | |
expr = expr.replace("^", "**") | |
if ',' in expr: | |
raise TypeError("Virgula nao eh separador decimal") | |
if verbose: print("hum2") | |
expr = parse_expr(expr) # transform string to sympy expression | |
if verbose: print("hum3") | |
expr = expr.expand() | |
if verbose: print("hum4") | |
for var, value in variables.items(): | |
if verbose: print("...") | |
expr = expr.subs(var, value) | |
if verbose: print("hum5") | |
expr = sp.Poly(expr, s) | |
if verbose: print("hum6") | |
expr = expr.all_coeffs() | |
if verbose: print("hum7") | |
for i, item in enumerate(expr): | |
expr[i] = float(expr[i]) | |
if verbose: print("type = " + str(type(item)) + " value = " + str(item)) | |
if verbose: print("hum8") | |
if verbose: print(expr) | |
return expr | |
def strToNumDen(expr, variables): | |
expr = Calcul.treatStr(expr) | |
expr = Calcul.strToSympyExpr(expr) | |
num, den = Calcul.separateFraction(expr) | |
num = sp.Poly(num, s) | |
num = num.all_coeffs() | |
den = sp.Poly(den, s) | |
den = den.all_coeffs() | |
for i, item in enumerate(expr): | |
num[i] = float(num[i]) | |
for i, item in enumerate(expr): | |
den[i] = float(den[i]) | |
return expr | |
def getData_GainPhase(Gnum, Gden): | |
w = np.logspace(-4, 4, 128) | |
sys = signal.lti(Gnum, Gden) | |
w, mag, phase = signal.bode(sys, w=w) | |
return w, mag, phase | |
def getData_Cartesian(Gnum, Gden): | |
w = np.logspace(-4, 4, 512) | |
sys = signal.lti(Gnum, Gden) | |
w, H = signal.freqresp(sys, w=w) | |
return w, H.real, H.imag | |
def getData_Margins(Gnum, Gden): | |
sys = control.tf(Gnum, Gden) | |
gm, pm, wg, wp = control.margin(sys) | |
return (wg, gm, -180), (wp, 1, pm-180) | |
def getData_PolesZeros(Gnum, Gden): | |
zs, ps, gain = signal.tf2zpk(Gnum, Gden) | |
return ps, zs | |
class Variavel: | |
def __init__(self, name, interval): | |
self.name = name | |
self.interval = interval | |
def get_name(self): | |
return self.name | |
def get_begin(self): | |
return self.interval[0] | |
def get_end(self): | |
return self.interval[1] | |
def get_value(self): | |
return (self.interval[0]+self.interval[1])/2.0 | |
def get_resolution(self): | |
return (self.interval[1]-self.interval[0])/100 | |
class ManagerParameter: | |
def __init__(self, parameter): | |
self.app = {} | |
self.app["Parameter"] = parameter | |
self.app["BodeGain"] = None | |
self.app["BodePhase"] = None | |
self.app["Nichols"] = None | |
self.app["Nyquist"] = None | |
self.variables = {} | |
for var in slider_infos: | |
self.variables[var.get_name()] = var.get_value() | |
self.validNumerator = False | |
self.validDenominator = False | |
self.Gnum = [] | |
self.Gden = [] | |
self.coefsNumerator = [] | |
self.coefsDenominator = [] | |
self.exprNum = "" | |
self.exprDen = "" | |
def callbackA(self, X): | |
self.variables["A"] = X/100 | |
self.__updateNum() | |
self.__updateDen() | |
self.__updateTransferFunction() | |
def callbackB(self, X): | |
self.variables["B"] = X/100 | |
self.__updateNum() | |
self.__updateDen() | |
self.__updateTransferFunction() | |
def callbackK(self, X): | |
self.variables["K"] = X/100 | |
self.__updateNum() | |
self.__updateDen() | |
self.__updateTransferFunction() | |
def send_info(self): | |
if self.app["BodeGain"] != None: | |
self.app["BodeGain"].update(self.w_g, self.gain, self.marginGain, self.marginPhase) | |
if self.app["BodePhase"] != None: | |
self.app["BodePhase"].update(self.w_g, self.phase, self.marginGain, self.marginPhase) | |
if self.app["Nichols"] != None: | |
self.app["Nichols"].update(self.phase, self.gain, self.marginGain, self.marginPhase) | |
if self.app["Nyquist"] != None: | |
self.app["Nyquist"].update(self.real, self.imag, self.marginGain, self.marginPhase, self.poles, self.zeros) | |
def __updateTransferFunction(self): | |
if self.validNumerator and self.validDenominator: | |
if self.Gnum != self.coefsNumerator or self.Gden != self.coefsDenominator: | |
self.Gnum = self.coefsNumerator | |
self.Gden = self.coefsDenominator | |
try: | |
#print("getting...") | |
#print(" - Gain/Phase") | |
self.w_g, self.gain, self.phase = Calcul.getData_GainPhase(self.Gnum, self.Gden) | |
#print(" - Nyquist") | |
self.w_c, self.real, self.imag = Calcul.getData_Cartesian(self.Gnum, self.Gden) | |
#print(" - Margins") | |
self.marginGain, self.marginPhase = Calcul.getData_Margins(self.Gnum, self.Gden) | |
#print(" - Poles and Zeros") | |
self.poles, self.zeros = Calcul.getData_PolesZeros(self.Gnum, self.Gden) | |
print(" margin Gain: " + str(self.marginGain)) | |
print("margin Phase: " + str(self.marginPhase)) | |
except: | |
pass | |
#print("Deu problema dentro de calcular algum dos parametros dentro da funcao de transferencia") | |
self.send_info() | |
#except: | |
# print("Deu problema na hora de passar os argumentos por update") | |
def callbackNum(self, expr): | |
self.exprNum = expr | |
self.__updateNum() | |
self.__updateTransferFunction() | |
def callbackDen(self, expr): | |
self.exprDen = expr | |
self.__updateDen() | |
self.__updateTransferFunction() | |
def __updateNum(self): | |
try: | |
new = Calcul.convertExprToCoefs(self.exprNum, self.variables) | |
if ( len(self.coefsNumerator) == 0 ) or not all(s == 0 for s in new): | |
self.coefsNumerator = new | |
self.validNumerator = True | |
except (TypeError, SyntaxError, sp.parsing.sympy_tokenize.TokenError) as e: | |
self.validNumerator = False | |
self.app["Parameter"].set_stateEntry_Numerator(self.validNumerator) | |
def __updateDen(self): | |
try: | |
new = Calcul.convertExprToCoefs(self.exprDen, self.variables) | |
if len(self.coefsDenominator) == 0 or not all(s == 0 for s in new): | |
self.coefsDenominator = new | |
self.validDenominator = True | |
except (TypeError, SyntaxError, sp.parsing.sympy_tokenize.TokenError) as e: | |
self.validDenominator = False | |
self.app["Parameter"].set_stateEntry_Denominator(self.validDenominator) | |
def can_new_window(self, name): | |
return self.app[name] == None and self.validNumerator and self.validDenominator | |
def set_app(self, name, value): | |
self.app[name] = value | |
self.send_info() | |
slider_infos = [] | |
slider_infos.append(Variavel("A", (0, 100))) | |
slider_infos.append(Variavel("B", (0, 100))) | |
slider_infos.append(Variavel("K", (0, 100))) |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment