feat: AR-ElecArrangement initial commit — Python FastAPI + uvicorn (LAN desktop app, packaged as .exe via PyInstaller)
This commit is contained in:
@@ -0,0 +1,110 @@
|
||||
"""
|
||||
Conversiones SI ↔ imperial usadas en la UI.
|
||||
|
||||
REGLA INTERNA DEL PROYECTO: todo el modelo de datos y todos los cálculos
|
||||
trabajan en SI (m, kg, A, V, W). Las conversiones a unidades imperiales
|
||||
(pies, AWG, BTU/h) ocurren ÚNICAMENTE en el borde UI cuando el usuario lo
|
||||
pide. Persistir AWG o pies en .area está prohibido.
|
||||
|
||||
Tablas
|
||||
------
|
||||
- AWG ↔ mm²: ABYC E-11 Tabla VI / IEC 60228 (relación logarítmica + valores
|
||||
tabulados estándar).
|
||||
- ft ↔ m: 1 ft = 0.3048 m exacto (NIST).
|
||||
- lb ↔ kg: 1 lb = 0.45359237 kg exacto (NIST).
|
||||
"""
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
# ── Lengths ─────────────────────────────────────────────────────────────────
|
||||
M_PER_FT: float = 0.3048
|
||||
FT_PER_M: float = 1.0 / M_PER_FT
|
||||
|
||||
|
||||
def m_to_ft(m: float) -> float:
|
||||
return m * FT_PER_M
|
||||
|
||||
|
||||
def ft_to_m(ft: float) -> float:
|
||||
return ft * M_PER_FT
|
||||
|
||||
|
||||
# ── Mass ────────────────────────────────────────────────────────────────────
|
||||
KG_PER_LB: float = 0.45359237
|
||||
LB_PER_KG: float = 1.0 / KG_PER_LB
|
||||
|
||||
|
||||
def kg_to_lb(kg: float) -> float:
|
||||
return kg * LB_PER_KG
|
||||
|
||||
|
||||
def lb_to_kg(lb: float) -> float:
|
||||
return lb * KG_PER_LB
|
||||
|
||||
|
||||
# ── Wire calibre — AWG ↔ mm² ────────────────────────────────────────────────
|
||||
# Tabla estándar de conductores (no se usa la fórmula logarítmica analítica
|
||||
# porque los valores comerciales están redondeados).
|
||||
# Cobertura: AWG 24 a 4/0 y mm² 0.2 a 120 — rango típico marino.
|
||||
AWG_TO_MM2: dict[str, float] = {
|
||||
"24": 0.205,
|
||||
"22": 0.324,
|
||||
"20": 0.519,
|
||||
"18": 0.823,
|
||||
"16": 1.31,
|
||||
"14": 2.08,
|
||||
"12": 3.31,
|
||||
"10": 5.26,
|
||||
"8": 8.37,
|
||||
"6": 13.3,
|
||||
"4": 21.2,
|
||||
"2": 33.6,
|
||||
"1": 42.4,
|
||||
"1/0": 53.5,
|
||||
"2/0": 67.4,
|
||||
"3/0": 85.0,
|
||||
"4/0": 107.0,
|
||||
}
|
||||
|
||||
# Lista de mm² comerciales IEC para la conversión inversa.
|
||||
COMMERCIAL_MM2: tuple[float, ...] = (
|
||||
0.5, 0.75, 1.0, 1.5, 2.5, 4.0, 6.0, 10.0, 16.0, 25.0, 35.0,
|
||||
50.0, 70.0, 95.0, 120.0, 150.0, 185.0, 240.0,
|
||||
)
|
||||
|
||||
|
||||
def awg_to_mm2(awg: str) -> float:
|
||||
"""Convertir designación AWG (p.ej. ``"10"``, ``"1/0"``) a mm²."""
|
||||
if awg not in AWG_TO_MM2:
|
||||
raise ValueError(f"AWG no soportado: {awg!r}. Válidos: {list(AWG_TO_MM2)}")
|
||||
return AWG_TO_MM2[awg]
|
||||
|
||||
|
||||
def mm2_to_awg(mm2: float) -> str:
|
||||
"""Mapear área (mm²) al AWG cuya área es ≥ la pedida (criterio conservador)."""
|
||||
if mm2 <= 0:
|
||||
raise ValueError(f"mm² debe ser > 0, recibido: {mm2}")
|
||||
# AWG_TO_MM2 está ordenado de menor a mayor área
|
||||
for awg, area in AWG_TO_MM2.items():
|
||||
if area >= mm2:
|
||||
return awg
|
||||
raise ValueError(f"mm² {mm2} excede el AWG máximo soportado (4/0 = 107 mm²)")
|
||||
|
||||
|
||||
# ── Power / energy ──────────────────────────────────────────────────────────
|
||||
def hp_to_kw(hp: float) -> float:
|
||||
"""Caballos métricos (CV / PS) a kW: 1 hp métrico = 0.7355 kW."""
|
||||
return hp * 0.7355
|
||||
|
||||
|
||||
def kw_to_hp(kw: float) -> float:
|
||||
return kw / 0.7355
|
||||
|
||||
|
||||
def btu_per_h_to_kw(btu_h: float) -> float:
|
||||
"""BTU/h a kW (capacidad frigorífica de A/C)."""
|
||||
return btu_h * 0.000293071
|
||||
|
||||
|
||||
def kw_to_btu_per_h(kw: float) -> float:
|
||||
return kw / 0.000293071
|
||||
Reference in New Issue
Block a user