""" 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