This commit is contained in:
parent
bba7224fd5
commit
4c4230e4cc
@ -7,7 +7,7 @@ steps:
|
|||||||
image: python:3.9
|
image: python:3.9
|
||||||
commands:
|
commands:
|
||||||
- python -m venv venv
|
- python -m venv venv
|
||||||
- ./venv/Scripts/activate
|
- source venv/bin/activate
|
||||||
- pip install -r requirements.txt
|
- pip install -r requirements.txt
|
||||||
- python -m nuitka --standalone --onefile --enable-plugin=tk-inter src/LaunchSim.py
|
- python -m nuitka --standalone --onefile --enable-plugin=tk-inter src/LaunchSim.py
|
||||||
|
|
||||||
|
@ -57,7 +57,7 @@ LaunchSim es una aplicación diseñada para calcular trayectorias de proyectiles
|
|||||||
Si deseas distribuir la aplicación como un ejecutable independiente:
|
Si deseas distribuir la aplicación como un ejecutable independiente:
|
||||||
- En Windows:
|
- En Windows:
|
||||||
```bash
|
```bash
|
||||||
python -m nuitka --standalone --windows-disable-console=disable --enable-plugin=tk-inter --windows-icon-from-ico=src/static/icon.ico src/LaunchSim.py
|
python -m nuitka --standalone --windows-disable-console --enable-plugin=tk-inter --windows-icon-from-ico=src/static/icon.ico src/LaunchSim.py
|
||||||
```
|
```
|
||||||
- En Linux/Mac:
|
- En Linux/Mac:
|
||||||
```bash
|
```bash
|
||||||
|
@ -12,7 +12,7 @@ from tabs.tab_simulator import TabSimulator
|
|||||||
from tabs.tab_search import TabSearch
|
from tabs.tab_search import TabSearch
|
||||||
from tabs.tab_drag import TabDrag
|
from tabs.tab_drag import TabDrag
|
||||||
from tabs.tab_coil import TabCoil
|
from tabs.tab_coil import TabCoil
|
||||||
from tabs.tab_electrical import TabElectrical
|
from tabs.tab_dynamic import TabDynamic
|
||||||
|
|
||||||
class MainApp:
|
class MainApp:
|
||||||
def __init__(self, master):
|
def __init__(self, master):
|
||||||
@ -44,10 +44,10 @@ class MainApp:
|
|||||||
# Pestaña 4: Bobinas
|
# Pestaña 4: Bobinas
|
||||||
self.tab_coil = TabCoil(self.notebook, self.tab_sim)
|
self.tab_coil = TabCoil(self.notebook, self.tab_sim)
|
||||||
self.notebook.add(self.tab_coil.frame, text="Bobinas")
|
self.notebook.add(self.tab_coil.frame, text="Bobinas")
|
||||||
|
|
||||||
# Pestaña 5: Eléctrico
|
# Pestaña 5: Cálculos dinámicos
|
||||||
self.tab_elec = TabElectrical(self.notebook, self.tab_sim, self.tab_coil)
|
tab_dyn = TabDynamic(self.notebook, self.tab_coil, self.tab_sim, self.tab_drag)
|
||||||
self.notebook.add(self.tab_elec.frame, text="Eléctrico")
|
self.notebook.add(tab_dyn.frame, text="Cálculos Dinámicos")
|
||||||
|
|
||||||
if __name__ == "__main__":
|
if __name__ == "__main__":
|
||||||
root = tk.Tk()
|
root = tk.Tk()
|
||||||
|
@ -129,7 +129,7 @@ def inductance_from_spiralist(espiras, wire_radius):
|
|||||||
M_ij = mutual_inductance_coaxial(r_i, r_j, dist_z)
|
M_ij = mutual_inductance_coaxial(r_i, r_j, dist_z)
|
||||||
L_total += 2.0 * M_ij
|
L_total += 2.0 * M_ij
|
||||||
|
|
||||||
return L_total
|
return abs(L_total)
|
||||||
|
|
||||||
# -------------------------------------------------------------------
|
# -------------------------------------------------------------------
|
||||||
# Importamos la función para dibujar la bobina 2D (tal y como estaba).
|
# Importamos la función para dibujar la bobina 2D (tal y como estaba).
|
||||||
|
@ -12,8 +12,8 @@ import numpy as np
|
|||||||
class TabDrag:
|
class TabDrag:
|
||||||
def __init__(self, notebook, tab_simulator):
|
def __init__(self, notebook, tab_simulator):
|
||||||
"""
|
"""
|
||||||
Pestaña para calcular un coef. 'b' a partir de la geometría.
|
Pestaña para calcular un coef. 'b' a partir de la geometría
|
||||||
Luego se pasa a tab_simulator.set_b_value(...) para usarlo en la simulación.
|
y exponer métodos para la reluctancia (l_fe y S_disp).
|
||||||
"""
|
"""
|
||||||
self.notebook = notebook
|
self.notebook = notebook
|
||||||
self.tab_simulator = tab_simulator
|
self.tab_simulator = tab_simulator
|
||||||
@ -88,13 +88,13 @@ class TabDrag:
|
|||||||
def update_param_labels(self):
|
def update_param_labels(self):
|
||||||
geom = self.geometria_var.get()
|
geom = self.geometria_var.get()
|
||||||
self.entry_param2.config(state="normal", fg="black")
|
self.entry_param2.config(state="normal", fg="black")
|
||||||
if geom=="Prisma cuadrado":
|
if geom == "Prisma cuadrado":
|
||||||
self.label_param1.config(text="Lado base (m):")
|
self.label_param1.config(text="Lado base (m):")
|
||||||
self.label_param2.config(text="Longitud (m):")
|
self.label_param2.config(text="Longitud (m):")
|
||||||
elif geom=="Cilindro":
|
elif geom == "Cilindro":
|
||||||
self.label_param1.config(text="Radio (m):")
|
self.label_param1.config(text="Radio (m):")
|
||||||
self.label_param2.config(text="Altura (m):")
|
self.label_param2.config(text="Altura (m):")
|
||||||
elif geom=="Esfera":
|
elif geom == "Esfera":
|
||||||
self.label_param1.config(text="Radio (m):")
|
self.label_param1.config(text="Radio (m):")
|
||||||
self.label_param2.config(text="(no aplica):")
|
self.label_param2.config(text="(no aplica):")
|
||||||
self.entry_param2.delete(0, tk.END)
|
self.entry_param2.delete(0, tk.END)
|
||||||
@ -109,50 +109,48 @@ class TabDrag:
|
|||||||
try:
|
try:
|
||||||
p1 = float(self.entry_param1.get())
|
p1 = float(self.entry_param1.get())
|
||||||
except ValueError:
|
except ValueError:
|
||||||
p1=1.0
|
p1 = 1.0
|
||||||
try:
|
try:
|
||||||
if self.entry_param2.cget("state")!="disabled":
|
if self.entry_param2.cget("state") != "disabled":
|
||||||
p2 = float(self.entry_param2.get())
|
p2 = float(self.entry_param2.get())
|
||||||
else:
|
else:
|
||||||
p2=1.0
|
p2 = 1.0
|
||||||
except ValueError:
|
except ValueError:
|
||||||
p2=1.0
|
p2 = 1.0
|
||||||
|
|
||||||
self.ax.clear()
|
self.ax.clear()
|
||||||
self.ax.set_axis_off()
|
self.ax.set_axis_off()
|
||||||
|
|
||||||
if geom=="Prisma cuadrado":
|
if geom == "Prisma cuadrado":
|
||||||
Xs=[0,p1,p1,0,0,p1,p1,0]
|
Xs = [0,p1,p1,0,0,p1,p1,0]
|
||||||
Ys=[0,0,p1,p1,0,0,p1,p1]
|
Ys = [0,0,p1,p1,0,0,p1,p1]
|
||||||
Zs=[0,0,0,0,p2,p2,p2,p2]
|
Zs = [0,0,0,0,p2,p2,p2,p2]
|
||||||
edges=[(0,1),(1,2),(2,3),(3,0),
|
edges = [(0,1),(1,2),(2,3),(3,0),
|
||||||
(4,5),(5,6),(6,7),(7,4),
|
(4,5),(5,6),(6,7),(7,4),
|
||||||
(0,4),(1,5),(2,6),(3,7)]
|
(0,4),(1,5),(2,6),(3,7)]
|
||||||
for (i,j) in edges:
|
for (i,j) in edges:
|
||||||
self.ax.plot([Xs[i],Xs[j]], [Ys[i],Ys[j]], [Zs[i],Zs[j]], color='orange')
|
self.ax.plot([Xs[i],Xs[j]], [Ys[i],Ys[j]], [Zs[i],Zs[j]], color='orange')
|
||||||
self.ax.set_box_aspect((p1,p1,p2))
|
self.ax.set_box_aspect((p1,p1,p2))
|
||||||
elif geom=="Cilindro":
|
elif geom == "Cilindro":
|
||||||
import numpy as np
|
import numpy as np
|
||||||
import math
|
r = p1
|
||||||
r=p1
|
h = p2
|
||||||
h=p2
|
theta = np.linspace(0,2*math.pi,30)
|
||||||
theta=np.linspace(0,2*math.pi,30)
|
z = np.linspace(0,h,30)
|
||||||
z=np.linspace(0,h,30)
|
T,Z = np.meshgrid(theta,z)
|
||||||
T,Z=np.meshgrid(theta,z)
|
X = r*np.cos(T)
|
||||||
X=r*np.cos(T)
|
Y = r*np.sin(T)
|
||||||
Y=r*np.sin(T)
|
|
||||||
self.ax.plot_surface(X, Y, Z, color='orange', alpha=0.8)
|
self.ax.plot_surface(X, Y, Z, color='orange', alpha=0.8)
|
||||||
self.ax.set_box_aspect((2*r,2*r,h))
|
self.ax.set_box_aspect((2*r,2*r,h))
|
||||||
elif geom=="Esfera":
|
elif geom == "Esfera":
|
||||||
import numpy as np
|
import numpy as np
|
||||||
import math
|
r = p1
|
||||||
r=p1
|
phi = np.linspace(0,math.pi,30)
|
||||||
phi=np.linspace(0,math.pi,30)
|
t = np.linspace(0,2*math.pi,30)
|
||||||
t=np.linspace(0,2*math.pi,30)
|
phi_grid,t_grid = np.meshgrid(phi,t)
|
||||||
phi_grid,t_grid=np.meshgrid(phi,t)
|
X = r*np.sin(phi_grid)*np.cos(t_grid)
|
||||||
X=r*np.sin(phi_grid)*np.cos(t_grid)
|
Y = r*np.sin(phi_grid)*np.sin(t_grid)
|
||||||
Y=r*np.sin(phi_grid)*np.sin(t_grid)
|
Z = r*np.cos(phi_grid)
|
||||||
Z=r*np.cos(phi_grid)
|
|
||||||
self.ax.plot_surface(X,Y,Z,color='orange',alpha=0.8)
|
self.ax.plot_surface(X,Y,Z,color='orange',alpha=0.8)
|
||||||
self.ax.set_box_aspect((2*r,2*r,2*r))
|
self.ax.set_box_aspect((2*r,2*r,2*r))
|
||||||
else:
|
else:
|
||||||
@ -162,6 +160,9 @@ class TabDrag:
|
|||||||
self.canvas_3d.draw()
|
self.canvas_3d.draw()
|
||||||
|
|
||||||
def calcular_coef_rozamiento(self):
|
def calcular_coef_rozamiento(self):
|
||||||
|
"""
|
||||||
|
Calcula un coeficiente b ~ 0.5*rho*Cd*A
|
||||||
|
"""
|
||||||
geom = self.geometria_var.get()
|
geom = self.geometria_var.get()
|
||||||
try:
|
try:
|
||||||
p1 = float(self.entry_param1.get())
|
p1 = float(self.entry_param1.get())
|
||||||
@ -186,11 +187,9 @@ class TabDrag:
|
|||||||
self.label_result_b.config(text="Error param2", fg="red")
|
self.label_result_b.config(text="Error param2", fg="red")
|
||||||
return
|
return
|
||||||
Cd=0.82
|
Cd=0.82
|
||||||
import math
|
|
||||||
A=math.pi*(p1**2)
|
A=math.pi*(p1**2)
|
||||||
elif geom=="Esfera":
|
elif geom=="Esfera":
|
||||||
Cd=0.47
|
Cd=0.47
|
||||||
import math
|
|
||||||
A=math.pi*(p1**2)
|
A=math.pi*(p1**2)
|
||||||
|
|
||||||
rho=1.225
|
rho=1.225
|
||||||
@ -198,3 +197,76 @@ class TabDrag:
|
|||||||
|
|
||||||
self.label_result_b.config(text=f"Coef (b) ~ {b_calc:.4f}", fg="blue")
|
self.label_result_b.config(text=f"Coef (b) ~ {b_calc:.4f}", fg="blue")
|
||||||
self.tab_simulator.set_b_value(b_calc)
|
self.tab_simulator.set_b_value(b_calc)
|
||||||
|
|
||||||
|
def get_l_fe(self):
|
||||||
|
"""
|
||||||
|
Devuelve la 'altura' l_fe (m) según la geometría:
|
||||||
|
- Prisma cuadrado: param2 (Longitud)
|
||||||
|
- Cilindro: param2 (Altura)
|
||||||
|
- Esfera: 2*radio (diámetro)
|
||||||
|
"""
|
||||||
|
geom = self.geometria_var.get()
|
||||||
|
|
||||||
|
try:
|
||||||
|
p1 = float(self.entry_param1.get())
|
||||||
|
except ValueError:
|
||||||
|
p1 = 1.0
|
||||||
|
|
||||||
|
l_fe_val = 1.0
|
||||||
|
|
||||||
|
if geom == "Prisma cuadrado":
|
||||||
|
try:
|
||||||
|
l_fe_val = float(self.entry_param2.get())
|
||||||
|
except ValueError:
|
||||||
|
l_fe_val = 1.0
|
||||||
|
|
||||||
|
elif geom == "Cilindro":
|
||||||
|
try:
|
||||||
|
l_fe_val = float(self.entry_param2.get())
|
||||||
|
except ValueError:
|
||||||
|
l_fe_val = 1.0
|
||||||
|
|
||||||
|
elif geom == "Esfera":
|
||||||
|
# Usamos 2*r (diámetro). Ajusta si prefieres 0
|
||||||
|
l_fe_val = 2.0 * p1
|
||||||
|
|
||||||
|
return l_fe_val
|
||||||
|
|
||||||
|
def get_projectile_section_for_reluctance(self, tab_coil):
|
||||||
|
"""
|
||||||
|
Devuelve S_disp (m^2) para la fórmula de reluctancia:
|
||||||
|
- Si la geometría es "Esfera", => S_disp = 2 * S_bob
|
||||||
|
con S_bob = pi * (r_ext^2)
|
||||||
|
(r_ext lo lees de tab_coil en mm, conv a m)
|
||||||
|
- En otros casos => área frontal real (p1^2 si prisma, pi*r^2 si cilindro).
|
||||||
|
"""
|
||||||
|
geom = self.geometria_var.get()
|
||||||
|
|
||||||
|
# 1) Leer r_ext de tab_coil (en mm) => m
|
||||||
|
try:
|
||||||
|
r_ext_mm = float(tab_coil.var_r_ext.get())
|
||||||
|
except:
|
||||||
|
r_ext_mm = 10.0
|
||||||
|
r_ext_m = r_ext_mm / 1000.0
|
||||||
|
|
||||||
|
# S_bob = pi*(r_ext_m^2)
|
||||||
|
s_bob = math.pi*(r_ext_m**2)
|
||||||
|
|
||||||
|
# 2) Leer p1
|
||||||
|
try:
|
||||||
|
p1 = float(self.entry_param1.get())
|
||||||
|
except ValueError:
|
||||||
|
p1 = 1.0
|
||||||
|
|
||||||
|
if geom == "Esfera":
|
||||||
|
# S_disp = 2*S_bob
|
||||||
|
return 2.0 * s_bob
|
||||||
|
elif geom == "Prisma cuadrado":
|
||||||
|
# Sección frontal ~ p1 x p1
|
||||||
|
return (p1**2)
|
||||||
|
elif geom == "Cilindro":
|
||||||
|
# Sección frontal ~ pi*(radio^2) = pi*(p1^2)
|
||||||
|
return math.pi*(p1**2)
|
||||||
|
else:
|
||||||
|
# Por defecto, algo por si la geo no es conocida
|
||||||
|
return 1.0
|
||||||
|
@ -0,0 +1,307 @@
|
|||||||
|
# src/tab_dynamic.py
|
||||||
|
|
||||||
|
import tkinter as tk
|
||||||
|
from tkinter import ttk
|
||||||
|
from tkinter.scrolledtext import ScrolledText
|
||||||
|
import math
|
||||||
|
import numpy as np
|
||||||
|
|
||||||
|
MU0 = 4.0e-7 * math.pi
|
||||||
|
|
||||||
|
class TabDynamic:
|
||||||
|
def __init__(self, notebook, tab_coil=None, tab_simulator=None, tab_drag=None):
|
||||||
|
"""
|
||||||
|
Pestaña que:
|
||||||
|
- Obtiene el trabajo W desde tab_simulator.
|
||||||
|
- Calcula la reluctancia media con la integración en x in [0, h_c].
|
||||||
|
- Usa el modelo W = ((N I)^2 * h_c)/(4 mu0 S_fe (sumR_avg)^2) para hallar I.
|
||||||
|
- Ofrece dimensionamiento de fuente (condensador / DC).
|
||||||
|
"""
|
||||||
|
self.notebook = notebook
|
||||||
|
self.tab_coil = tab_coil
|
||||||
|
self.tab_simulator = tab_simulator
|
||||||
|
self.tab_drag = tab_drag
|
||||||
|
|
||||||
|
self.frame = tk.Frame(notebook)
|
||||||
|
self.frame.pack(fill="both", expand=True)
|
||||||
|
|
||||||
|
# Panel Izq: Botones / parámetros
|
||||||
|
left_frame = tk.Frame(self.frame)
|
||||||
|
left_frame.pack(side="left", fill="y", padx=5, pady=5)
|
||||||
|
|
||||||
|
# Panel Der: Logs
|
||||||
|
right_frame = tk.Frame(self.frame, bd=2, relief="groove")
|
||||||
|
right_frame.pack(side="right", fill="both", expand=True, padx=5, pady=5)
|
||||||
|
|
||||||
|
# Sección 1: Importar Config
|
||||||
|
import_frame = tk.LabelFrame(left_frame, text="1) Importar Config")
|
||||||
|
import_frame.pack(fill="x", pady=5)
|
||||||
|
|
||||||
|
btn_import = tk.Button(import_frame, text="Importar Config", command=self.importar_config)
|
||||||
|
btn_import.pack(pady=5)
|
||||||
|
|
||||||
|
self.var_W_mech = tk.StringVar(value="")
|
||||||
|
tk.Label(import_frame, text="W (J):").pack(anchor="w")
|
||||||
|
tk.Entry(import_frame, textvariable=self.var_W_mech, width=12, state="readonly").pack(pady=2)
|
||||||
|
|
||||||
|
self.W_mech = 0.0 # energía mecánica importada
|
||||||
|
|
||||||
|
# Sección 2: Calcular Reluctancia Media
|
||||||
|
rel_frame = tk.LabelFrame(left_frame, text="2) Reluctancia Media")
|
||||||
|
rel_frame.pack(fill="x", pady=5)
|
||||||
|
|
||||||
|
self.var_sumR_avg = tk.StringVar(value="")
|
||||||
|
tk.Button(rel_frame, text="Calcular Rel. Media", command=self.calcular_reluctancia_media).pack(pady=5)
|
||||||
|
tk.Label(rel_frame, text="sum(R)_avg:").pack(anchor="w")
|
||||||
|
tk.Entry(rel_frame, textvariable=self.var_sumR_avg, width=15, state="readonly").pack(pady=2)
|
||||||
|
|
||||||
|
self.sumR_avg = 0.0 # valor en el interior
|
||||||
|
|
||||||
|
# Sección 3: Calcular Corriente
|
||||||
|
work_frame = tk.LabelFrame(left_frame, text="3) Corriente Necesaria")
|
||||||
|
work_frame.pack(fill="x", pady=5)
|
||||||
|
|
||||||
|
self.var_S_fe = tk.DoubleVar(value=1e-4) # Sección en la zona férrea
|
||||||
|
tk.Label(work_frame, text="S_fe (m²):").grid(row=0, column=0, sticky="w", padx=5, pady=2)
|
||||||
|
tk.Entry(work_frame, textvariable=self.var_S_fe, width=10).grid(row=0, column=1, padx=5, pady=2)
|
||||||
|
|
||||||
|
tk.Button(work_frame, text="Calcular Corriente", command=self.calcular_corriente_trabajo).grid(row=1, column=0, columnspan=2, pady=5)
|
||||||
|
|
||||||
|
self.var_I_req = tk.StringVar(value="")
|
||||||
|
tk.Label(work_frame, text="I_req (A):").grid(row=2, column=0, sticky="w", padx=5, pady=2)
|
||||||
|
tk.Entry(work_frame, textvariable=self.var_I_req, width=10, state="readonly").grid(row=2, column=1, padx=5, pady=2)
|
||||||
|
|
||||||
|
# Sección 4: Dimensionar Fuente
|
||||||
|
fuente_frame = tk.LabelFrame(left_frame, text="4) Dimensionar Fuente")
|
||||||
|
fuente_frame.pack(fill="x", pady=5)
|
||||||
|
|
||||||
|
tk.Button(fuente_frame, text="Dimensionar Capacitor", command=self.dimensionar_condensador).pack(pady=5)
|
||||||
|
tk.Button(fuente_frame, text="Fuente DC minima", command=self.dimensionar_fuente_dc).pack(pady=5)
|
||||||
|
|
||||||
|
self.var_C_sug = tk.StringVar(value="")
|
||||||
|
self.var_V_sug = tk.StringVar(value="")
|
||||||
|
self.var_Vdc_min = tk.StringVar(value="")
|
||||||
|
|
||||||
|
tk.Label(fuente_frame, text="C (F) ~").pack(anchor="w")
|
||||||
|
tk.Entry(fuente_frame, textvariable=self.var_C_sug, width=15, state="readonly").pack(pady=2)
|
||||||
|
|
||||||
|
tk.Label(fuente_frame, text="Vcap (V) ~").pack(anchor="w")
|
||||||
|
tk.Entry(fuente_frame, textvariable=self.var_V_sug, width=15, state="readonly").pack(pady=2)
|
||||||
|
|
||||||
|
tk.Label(fuente_frame, text="V_DC min (V) ~").pack(anchor="w")
|
||||||
|
tk.Entry(fuente_frame, textvariable=self.var_Vdc_min, width=15, state="readonly").pack(pady=2)
|
||||||
|
|
||||||
|
# LOGS
|
||||||
|
tk.Label(right_frame, text="Logs:").pack(anchor="w")
|
||||||
|
self.log_area = ScrolledText(right_frame, wrap="word", height=25, width=50)
|
||||||
|
self.log_area.pack(fill="both", expand=True)
|
||||||
|
self.log_area.configure(state="disabled")
|
||||||
|
self.log_area.tag_config("info", foreground="green")
|
||||||
|
self.log_area.tag_config("error", foreground="red")
|
||||||
|
|
||||||
|
# --------------------------------------------------------
|
||||||
|
# Log helper
|
||||||
|
# --------------------------------------------------------
|
||||||
|
def log_message(self, msg, mode="info"):
|
||||||
|
self.log_area.configure(state="normal")
|
||||||
|
self.log_area.insert("end", msg + "\n", mode)
|
||||||
|
self.log_area.see("end")
|
||||||
|
self.log_area.configure(state="disabled")
|
||||||
|
|
||||||
|
# --------------------------------------------------------
|
||||||
|
# 1) Importar Config (energía W)
|
||||||
|
# --------------------------------------------------------
|
||||||
|
def importar_config(self):
|
||||||
|
"""
|
||||||
|
Lee la energía mecánica W de tab_simulator y la guarda en self.W_mech
|
||||||
|
"""
|
||||||
|
try:
|
||||||
|
if not self.tab_simulator:
|
||||||
|
raise ValueError("No hay tab_simulator para leer W.")
|
||||||
|
w_val = self.tab_simulator.get_energy_required()
|
||||||
|
if w_val<=0:
|
||||||
|
raise ValueError("Energía <= 0.")
|
||||||
|
self.W_mech = w_val
|
||||||
|
self.var_W_mech.set(f"{w_val:.3f}")
|
||||||
|
self.log_message(f"Importado W={w_val:.3f} J", "info")
|
||||||
|
|
||||||
|
except Exception as e:
|
||||||
|
self.log_message(f"Error importar_config: {e}", "error")
|
||||||
|
|
||||||
|
# --------------------------------------------------------
|
||||||
|
# 2) Calcular Reluctancia Media (sum(R)_avg)
|
||||||
|
# => integrando la ecuación sum_R(x)= ...
|
||||||
|
# --------------------------------------------------------
|
||||||
|
def calcular_reluctancia_media(self):
|
||||||
|
try:
|
||||||
|
if not self.tab_coil:
|
||||||
|
raise ValueError("Falta referencia a tab_coil.")
|
||||||
|
if not self.tab_drag:
|
||||||
|
raise ValueError("Falta referencia a tab_drag.")
|
||||||
|
|
||||||
|
# 1) Leer h_c, N, r_int (en mm->m)
|
||||||
|
h_c_m = float(self.tab_coil.var_h_c.get())/1000.0
|
||||||
|
if h_c_m<=0:
|
||||||
|
raise ValueError("h_c_m <=0.")
|
||||||
|
|
||||||
|
r_int_m = float(self.tab_coil.var_r_int.get())/1000.0
|
||||||
|
if r_int_m<=0:
|
||||||
|
raise ValueError("r_int_m <=0.")
|
||||||
|
|
||||||
|
# 2) l_fe => de tab_drag
|
||||||
|
l_fe_m = self.tab_drag.get_l_fe() # en metros
|
||||||
|
if l_fe_m<0:
|
||||||
|
raise ValueError("l_fe<0?")
|
||||||
|
|
||||||
|
# 3) s_disp => get_projectile_section_for_reluctance
|
||||||
|
s_disp = self.tab_drag.get_projectile_section_for_reluctance(self.tab_coil)
|
||||||
|
if s_disp<=0:
|
||||||
|
raise ValueError("s_disp <=0.")
|
||||||
|
|
||||||
|
# 4) s_c= pi*r_int^2
|
||||||
|
s_c = math.pi*(r_int_m**2)
|
||||||
|
if s_c<=0:
|
||||||
|
raise ValueError("s_c<=0.")
|
||||||
|
|
||||||
|
# 5) Definir sumR(x)
|
||||||
|
def sumR_of_x(x):
|
||||||
|
# sum_R = h_c/(mu0*s_disp)
|
||||||
|
# + (h_c + l_fe - x)/(mu0*s_disp)
|
||||||
|
# + (h_c - x)/(mu0*s_c)
|
||||||
|
return (
|
||||||
|
(h_c_m/(MU0*s_disp))
|
||||||
|
+ ((h_c_m + l_fe_m - x)/(MU0*s_disp))
|
||||||
|
+ ((h_c_m - x)/(MU0*s_c))
|
||||||
|
)
|
||||||
|
|
||||||
|
# 6) Integración en [0..h_c_m]
|
||||||
|
n_steps=200
|
||||||
|
dx = h_c_m/n_steps
|
||||||
|
area_sum=0.0
|
||||||
|
x_curr=0.0
|
||||||
|
for _ in range(n_steps):
|
||||||
|
x_mid= x_curr+0.5*dx
|
||||||
|
val_mid= sumR_of_x(x_mid)
|
||||||
|
area_sum+= val_mid
|
||||||
|
x_curr+=dx
|
||||||
|
area_sum*= dx
|
||||||
|
|
||||||
|
sumR_avg= area_sum/h_c_m
|
||||||
|
if sumR_avg<=1e-30:
|
||||||
|
raise ValueError("sumR_avg nulo o negativo.")
|
||||||
|
|
||||||
|
self.sumR_avg= sumR_avg
|
||||||
|
self.var_sumR_avg.set(f"{sumR_avg:.3e}")
|
||||||
|
self.log_message(f"Reluctancia media= {sumR_avg:.3e} H^-1", "info")
|
||||||
|
|
||||||
|
except ValueError as ve:
|
||||||
|
self.sumR_avg=0.0
|
||||||
|
self.var_sumR_avg.set("")
|
||||||
|
self.log_message(f"Error calc Reluctancia media: {ve}", "error")
|
||||||
|
except Exception as ex:
|
||||||
|
self.sumR_avg=0.0
|
||||||
|
self.var_sumR_avg.set("")
|
||||||
|
self.log_message(f"Excepción calc Reluct. media: {ex}", "error")
|
||||||
|
|
||||||
|
# --------------------------------------------------------
|
||||||
|
# 3) Calcular Corriente, con W = ((N I)^2 * h_c)/(4 mu0 S_fe (sumR_avg)^2)
|
||||||
|
# --------------------------------------------------------
|
||||||
|
def calcular_corriente_trabajo(self):
|
||||||
|
try:
|
||||||
|
if self.W_mech<=0:
|
||||||
|
raise ValueError("No hay W_mech positivo. Importa config primero.")
|
||||||
|
if self.sumR_avg<=0:
|
||||||
|
raise ValueError("sumR_avg<=0. Calcula la Reluctancia media antes.")
|
||||||
|
|
||||||
|
# 1) Leer h_c (mm->m), N, etc. de tab_coil
|
||||||
|
h_c_m = float(self.tab_coil.var_h_c.get())/1000.0
|
||||||
|
N_val = float(self.tab_coil.var_N.get())
|
||||||
|
if h_c_m<=0 or N_val<=0:
|
||||||
|
raise ValueError("Parámetros de bobina inválidos.")
|
||||||
|
|
||||||
|
# 2) Leer S_fe
|
||||||
|
S_fe_val= self.var_S_fe.get()
|
||||||
|
if S_fe_val<=0:
|
||||||
|
raise ValueError("S_fe <=0")
|
||||||
|
|
||||||
|
# 3) Tomamos sumR_avg, W
|
||||||
|
sumR_avg= self.sumR_avg
|
||||||
|
W= self.W_mech
|
||||||
|
|
||||||
|
# 4) W= ((N I)^2 * h_c)/(4 mu0 S_fe (sumR_avg)^2)
|
||||||
|
# => (N I)^2= [4 mu0 S_fe (sumR_avg)^2 W]/h_c
|
||||||
|
top= 4.0*MU0*S_fe_val*(sumR_avg**2)* W
|
||||||
|
bottom= h_c_m
|
||||||
|
if bottom<=1e-30:
|
||||||
|
raise ValueError("h_c_m=0?")
|
||||||
|
|
||||||
|
NI_sq= top/bottom
|
||||||
|
if NI_sq<=0:
|
||||||
|
raise ValueError("Resultado (N I)^2 <=0, no válido.")
|
||||||
|
|
||||||
|
NI= math.sqrt(NI_sq)
|
||||||
|
I_req= NI/ N_val
|
||||||
|
|
||||||
|
self.var_I_req.set(f"{I_req:.3f}")
|
||||||
|
self.log_message(f"I necesaria= {I_req:.3f} A", "info")
|
||||||
|
|
||||||
|
except ValueError as ve:
|
||||||
|
self.var_I_req.set("")
|
||||||
|
self.log_message(f"Error calc I trabajo: {ve}", "error")
|
||||||
|
except Exception as ex:
|
||||||
|
self.var_I_req.set("")
|
||||||
|
self.log_message(f"Excepción calc I trabajo: {ex}", "error")
|
||||||
|
|
||||||
|
# --------------------------------------------------------
|
||||||
|
# 4) Dimensionar la fuente (ejemplo condensador y DC)
|
||||||
|
# --------------------------------------------------------
|
||||||
|
def dimensionar_condensador(self):
|
||||||
|
"""
|
||||||
|
Ejemplo: suponer que la energía total W -> (1/2)C V^2
|
||||||
|
W_marg = W_mech * factor... etc.
|
||||||
|
"""
|
||||||
|
try:
|
||||||
|
W= self.W_mech
|
||||||
|
if W<=0:
|
||||||
|
raise ValueError("Primero importa config. W<=0?")
|
||||||
|
|
||||||
|
# suponer un factor "pérdidas"
|
||||||
|
eff=0.7
|
||||||
|
# E capacitor= W/ eff
|
||||||
|
E_cap= W/eff
|
||||||
|
# asumes C= 1mF => V= sqrt(2 E_cap/C)
|
||||||
|
# o V= 200 => C= 2E_cap/V^2, etc.
|
||||||
|
# Aquí arbitrariamente p.ej C=1e-3 y calculamos V
|
||||||
|
C_val= 1e-3
|
||||||
|
Vcalc= math.sqrt(2.0*E_cap/C_val)
|
||||||
|
|
||||||
|
self.var_C_sug.set(f"{C_val:.3g}")
|
||||||
|
self.var_V_sug.set(f"{Vcalc:.1f}")
|
||||||
|
self.log_message(f"Caps: C=1mF => V~{Vcalc:.1f} V (descarga)", "info")
|
||||||
|
|
||||||
|
except ValueError as ve:
|
||||||
|
self.log_message(f"Error dimensionar_condensador: {ve}", "error")
|
||||||
|
except Exception as ex:
|
||||||
|
self.log_message(f"Excepción dimensionar_condensador: {ex}", "error")
|
||||||
|
|
||||||
|
def dimensionar_fuente_dc(self):
|
||||||
|
"""
|
||||||
|
Ejemplo simple: V_dc >= R_coil * I_req
|
||||||
|
R_coil en ohms => la obtendrías o la metes manual.
|
||||||
|
"""
|
||||||
|
try:
|
||||||
|
Ireq_str= self.var_I_req.get()
|
||||||
|
Ireq= float(Ireq_str)
|
||||||
|
if Ireq<=0:
|
||||||
|
raise ValueError("I_req <=0? Calcula la corriente primero.")
|
||||||
|
|
||||||
|
# supongamos R_coil= 2 ohms (ejemplo)
|
||||||
|
R_coil= 2.0
|
||||||
|
V_dc= R_coil* Ireq
|
||||||
|
self.var_Vdc_min.set(f"{V_dc:.1f}")
|
||||||
|
self.log_message(f"Fuente DC~ {V_dc:.1f} V (min. ohmico)", "info")
|
||||||
|
|
||||||
|
except ValueError as ve:
|
||||||
|
self.log_message(f"Error dimensionar_fuente_dc: {ve}", "error")
|
||||||
|
except Exception as ex:
|
||||||
|
self.log_message(f"Excepción dimensionar_fuente_dc: {ex}", "error")
|
@ -1,155 +0,0 @@
|
|||||||
import tkinter as tk
|
|
||||||
from tkinter import ttk
|
|
||||||
import math
|
|
||||||
|
|
||||||
import matplotlib
|
|
||||||
matplotlib.use("TkAgg")
|
|
||||||
import matplotlib.pyplot as plt
|
|
||||||
from matplotlib.backends.backend_tkagg import FigureCanvasTkAgg
|
|
||||||
|
|
||||||
import numpy as np
|
|
||||||
|
|
||||||
class TabElectrical:
|
|
||||||
def __init__(self, notebook, tab_simulator, tab_coil):
|
|
||||||
"""
|
|
||||||
Pestaña para estimar la potencia y corriente necesarias
|
|
||||||
para suministrar la energía 'E_mec' en diferentes tiempos,
|
|
||||||
con un voltaje fijo V.
|
|
||||||
- 'tab_simulator': donde se calcula la energía mecánica requerida.
|
|
||||||
- 'tab_coil': por si quieres leer datos de la bobina (en este ejemplo,
|
|
||||||
no lo usamos ya, pero lo mantenemos para coherencia).
|
|
||||||
"""
|
|
||||||
self.notebook = notebook
|
|
||||||
self.tab_sim = tab_simulator
|
|
||||||
self.tab_coil = tab_coil
|
|
||||||
|
|
||||||
# Creamos el frame principal de la pestaña
|
|
||||||
self.frame = tk.Frame(notebook)
|
|
||||||
self.frame.pack(fill="both", expand=True)
|
|
||||||
# Nota: si en main.py ya se hace 'notebook.add(self.frame, text="Eléctrico")',
|
|
||||||
# no repitas esa línea aquí.
|
|
||||||
|
|
||||||
# Layout principal (izquierda: controles, derecha: gráfica)
|
|
||||||
frame_left = tk.Frame(self.frame)
|
|
||||||
frame_left.pack(side="left", fill="y", padx=5, pady=5)
|
|
||||||
|
|
||||||
frame_right = tk.Frame(self.frame, bd=2, relief="groove")
|
|
||||||
frame_right.pack(side="right", fill="both", expand=True, padx=5, pady=5)
|
|
||||||
|
|
||||||
#
|
|
||||||
# Sección Izquierda
|
|
||||||
#
|
|
||||||
tk.Label(frame_left, text="Simulación Eléctrica (Potencia & Corriente)").pack(anchor="w", pady=3)
|
|
||||||
|
|
||||||
btn_import = tk.Button(
|
|
||||||
frame_left, text="Importar Config",
|
|
||||||
command=self.import_config
|
|
||||||
)
|
|
||||||
btn_import.pack(pady=5, anchor="w")
|
|
||||||
|
|
||||||
# Variables
|
|
||||||
self.var_emech = tk.DoubleVar(value=0.0) # Energía mecánica importada
|
|
||||||
self.var_V = tk.DoubleVar(value=12.0) # Voltaje (valor por defecto 12 V)
|
|
||||||
self.var_tmax = tk.DoubleVar(value=2.0) # Tiempo máximo de estudio (s)
|
|
||||||
|
|
||||||
# Muestra la energía mecánica importada
|
|
||||||
tk.Label(frame_left, text="E_mec (J):").pack(anchor="w")
|
|
||||||
self.lbl_emech = tk.Label(frame_left, text="N/A")
|
|
||||||
self.lbl_emech.pack(anchor="w", pady=2)
|
|
||||||
|
|
||||||
# Frame para pedir V y T_max
|
|
||||||
param_frame = tk.Frame(frame_left, bd=1, relief="sunken")
|
|
||||||
param_frame.pack(fill="x", pady=10)
|
|
||||||
|
|
||||||
tk.Label(param_frame, text="Voltaje (V):").grid(row=0, column=0, sticky="w", padx=4, pady=2)
|
|
||||||
self.entry_V = tk.Entry(param_frame, width=8, textvariable=self.var_V)
|
|
||||||
self.entry_V.grid(row=0, column=1, padx=5, pady=2)
|
|
||||||
|
|
||||||
tk.Label(param_frame, text="T_max (s):").grid(row=1, column=0, sticky="w", padx=4, pady=2)
|
|
||||||
self.entry_Tmax = tk.Entry(param_frame, width=8, textvariable=self.var_tmax)
|
|
||||||
self.entry_Tmax.grid(row=1, column=1, padx=5, pady=2)
|
|
||||||
|
|
||||||
# Botón de simulación
|
|
||||||
btn_simular = tk.Button(param_frame, text="Simular", command=self.simular)
|
|
||||||
btn_simular.grid(row=2, column=0, columnspan=2, pady=5)
|
|
||||||
|
|
||||||
#
|
|
||||||
# Sección Derecha: gráficas
|
|
||||||
#
|
|
||||||
self.fig = plt.Figure(figsize=(5, 3), dpi=100)
|
|
||||||
|
|
||||||
# Subplot 1: Potencia vs tiempo
|
|
||||||
self.ax_p = self.fig.add_subplot(211)
|
|
||||||
# Subplot 2: Corriente vs tiempo
|
|
||||||
self.ax_i = self.fig.add_subplot(212)
|
|
||||||
|
|
||||||
self.canvas = FigureCanvasTkAgg(self.fig, master=frame_right)
|
|
||||||
self.canvas_widget = self.canvas.get_tk_widget()
|
|
||||||
self.canvas_widget.pack(fill="both", expand=True)
|
|
||||||
|
|
||||||
def import_config(self):
|
|
||||||
"""
|
|
||||||
Importa la energía mecánica desde la pestaña de simulación.
|
|
||||||
Ajusta la variable self.var_emech.
|
|
||||||
"""
|
|
||||||
# Supongamos que TabSimulator tiene un método 'get_energy_required()'
|
|
||||||
# que devuelve la energía calculada.
|
|
||||||
try:
|
|
||||||
E_mech_val = self.tab_sim.get_energy_required()
|
|
||||||
except:
|
|
||||||
E_mech_val = 0.0
|
|
||||||
|
|
||||||
self.var_emech.set(E_mech_val)
|
|
||||||
self.lbl_emech.config(text=f"{E_mech_val:.3f} J")
|
|
||||||
|
|
||||||
def simular(self):
|
|
||||||
"""
|
|
||||||
Barrido de tiempos (0..T_max):
|
|
||||||
P(t) = E / t
|
|
||||||
I(t) = P(t) / V
|
|
||||||
Se grafican P(t) e I(t).
|
|
||||||
"""
|
|
||||||
E = self.var_emech.get() # Joules
|
|
||||||
V = self.var_V.get() # Voltios
|
|
||||||
T_max = self.var_tmax.get() # s
|
|
||||||
|
|
||||||
# Evitar tiempos <= 0
|
|
||||||
if T_max <= 0.0:
|
|
||||||
T_max = 2.0
|
|
||||||
self.var_tmax.set(T_max)
|
|
||||||
|
|
||||||
# Creamos un vector de tiempos discretos, evitando t=0
|
|
||||||
# por ejemplo de 0.01 a T_max en 50 pasos
|
|
||||||
t_vals = np.linspace(0.01, T_max, 50)
|
|
||||||
p_vals = [] # Potencia en cada t
|
|
||||||
i_vals = [] # Corriente en cada t
|
|
||||||
|
|
||||||
for t in t_vals:
|
|
||||||
# P(t) = E / t
|
|
||||||
P_t = 0.0
|
|
||||||
I_t = 0.0
|
|
||||||
if t > 0:
|
|
||||||
P_t = E / t
|
|
||||||
# I(t) = P(t)/V = E/(V*t)
|
|
||||||
if V > 1e-12:
|
|
||||||
I_t = P_t / V
|
|
||||||
|
|
||||||
p_vals.append(P_t)
|
|
||||||
i_vals.append(I_t)
|
|
||||||
|
|
||||||
# Graficamos
|
|
||||||
self.ax_p.clear()
|
|
||||||
self.ax_p.plot(t_vals, p_vals, label="P(t) = E / t", color="blue")
|
|
||||||
self.ax_p.set_xlabel("Tiempo (s)")
|
|
||||||
self.ax_p.set_ylabel("Potencia (W)")
|
|
||||||
self.ax_p.grid(True)
|
|
||||||
self.ax_p.legend()
|
|
||||||
|
|
||||||
self.ax_i.clear()
|
|
||||||
self.ax_i.plot(t_vals, i_vals, label="I(t) = P(t)/V", color="red")
|
|
||||||
self.ax_i.set_xlabel("Tiempo (s)")
|
|
||||||
self.ax_i.set_ylabel("Corriente (A)")
|
|
||||||
self.ax_i.grid(True)
|
|
||||||
self.ax_i.legend()
|
|
||||||
|
|
||||||
self.canvas.draw()
|
|
Loading…
Reference in New Issue
Block a user