/* ============================================================================ VOLTLAB · Seção do Condutor (NBR 5410) ---------------------------------------------------------------------------- Dimensionamento de condutores por TODOS os critérios da NBR 5410 (item 6.2): 1) Capacidade de condução de corrente (ampacidade) — Tab. 36/37 2) Queda de tensão — Tab. 9 3) Seção mínima por aplicação — Tab. 47 4) Proteção contra sobrecargas — item 5.3.4.1 5) Proteção contra curto-circuito — item 5.3.5 Cada critério é ATIVÁVEL individualmente. A seção final é o MAIOR valor entre todos os critérios ligados (regra clássica da NBR 5410). Métodos de entrada da corrente de projeto (Ip): - Direta · Mono P · Bi P · Tri P · Mono S · Tri S Expõe: window.VL_SecaoCondutor (componente React) ============================================================================ */ (function () { const { useState, useMemo, useEffect } = React; /* ------------------------------ Paleta --------------------------------- */ const C = { bg: '#0C1018', panel: '#121826', panel2: '#0F1420', border: 'rgba(61,139,255,0.16)', soft: 'rgba(61,139,255,0.08)', text: '#E8EDF5', dim: '#8FA3BF', blue: '#3D8BFF', cyan: '#57D8E6', amber: '#FFB84D', red: '#FF6B6B', green: '#5CE0A1', purple: '#9B8CFF', copper: '#D08658', aluminum:'#C4CCD6', }; /* cor por critério (usada nos badges e cards) */ const CRIT_COR = { ampacidade: C.amber, queda: C.cyan, minima: C.green, sobrecarga: C.blue, curto: C.red, }; /* ---------- Seções comerciais (mm²) — NBR 5410 ------------------------- */ const SECOES_TAB = [1.5, 2.5, 4, 6, 10, 16, 25, 35, 50, 70, 95, 120, 150, 185, 240]; /* ---------- Métodos de instalação (Tab. 33) ---------------------------- */ const METODOS = [ { id: 'A1', desc: 'Condutores isolados em eletroduto embutido em parede termicamente isolante' }, { id: 'A2', desc: 'Cabo multipolar em eletroduto embutido em parede termicamente isolante' }, { id: 'B1', desc: 'Condutores isolados em eletroduto aparente sobre parede' }, { id: 'B2', desc: 'Cabo multipolar em eletroduto aparente sobre parede' }, { id: 'C', desc: 'Cabos uni/multipolares fixados sobre parede ou teto' }, { id: 'D', desc: 'Cabo multipolar em eletroduto enterrado no solo' }, { id: 'E', desc: 'Cabo multipolar ao ar livre, afastado' }, { id: 'F', desc: 'Cabos unipolares ao ar livre, justapostos (trifólio)' }, ]; /* ---------- Tabelas 36 e 37 (ampères) — Cu/Al × PVC/EPR × 2/3 cond ----- */ const TAB = { Cu_PVC_2: { A1: [14.5, 19.5, 26, 34, 46, 61, 80, 99, 119, 151, 182, 210, 240, 273, 320], A2: [14, 18.5, 25, 32, 43, 57, 75, 92, 110, 139, 167, 192, 219, 248, 291], B1: [17.5, 24, 32, 41, 57, 76, 101, 125, 151, 192, 232, 269, 309, 353, 415], B2: [16.5, 23, 30, 38, 52, 69, 90, 111, 133, 168, 201, 232, 265, 300, 351], C: [19.5, 27, 36, 46, 63, 85, 112, 138, 168, 213, 258, 299, 344, 392, 461], D: [22, 29, 38, 47, 63, 81, 104, 125, 148, 183, 216, 246, 278, 312, 361], E: [22, 30, 40, 51, 70, 94, 119, 148, 180, 232, 282, 328, 379, 434, 514], F: [null, null, null,null,null,null, 131, 162, 196, 251, 304, 352, 406, 463, 546], }, Cu_PVC_3: { A1: [13.5, 18, 24, 31, 42, 56, 73, 89, 108, 136, 164, 188, 216, 245, 286], A2: [13, 17.5, 23, 29, 39, 52, 68, 83, 99, 125, 150, 172, 196, 223, 261], B1: [15.5, 21, 28, 36, 50, 68, 89, 111, 134, 171, 207, 239, 275, 314, 369], B2: [15, 20, 27, 34, 46, 62, 80, 99, 118, 149, 179, 206, 236, 268, 313], C: [17.5, 24, 32, 41, 57, 76, 96, 119, 144, 184, 223, 259, 299, 341, 403], D: [18, 24, 31, 39, 52, 67, 86, 103, 122, 151, 179, 203, 230, 258, 297], E: [18.5, 25, 34, 43, 60, 80, 101, 126, 153, 196, 238, 276, 319, 364, 430], F: [null, null, null,null,null,null, 114, 141, 172, 218, 264, 308, 356, 405, 477], }, Al_PVC_2: { A1: [null, null, 21, 28, 36, 49, 64, 77, 94, 118, 144, 167, 191, 218, 256], A2: [null, null, 19.5,26, 33, 45, 59, 71, 86, 109, 130, 150, 172, 195, 229], B1: [null, null, 25, 33, 44, 60, 79, 97, 118, 150, 181, 210, 241, 275, 324], B2: [null, null, 23, 30, 41, 55, 71, 87, 104, 131, 157, 181, 206, 234, 274], C: [null, null, 28, 36, 49, 66, 86, 107, 130, 165, 200, 232, 267, 305, 359], D: [null, null, 30, 37, 49, 63, 80, 96, 114, 141, 167, 190, 215, 241, 280], E: [null, null, 31, 39, 54, 73, 92, 115, 140, 180, 218, 254, 293, 336, 397], F: [null, null, null,null,null,null, 101, 126, 152, 195, 236, 273, 315, 359, 424], }, Al_PVC_3: { A1: [null, null, 19, 25, 33, 45, 58, 71, 86, 108, 130, 150, 172, 196, 229], A2: [null, null, 18, 23, 31, 41, 54, 66, 79, 100, 119, 137, 157, 178, 209], B1: [null, null, 22, 28, 39, 53, 70, 86, 104, 133, 161, 186, 214, 244, 287], B2: [null, null, 21, 27, 36, 48, 62, 77, 92, 116, 139, 160, 183, 208, 243], C: [null, null, 25, 32, 44, 59, 73, 90, 110, 140, 170, 197, 227, 259, 305], D: [null, null, 24, 30, 40, 52, 66, 80, 94, 117, 138, 157, 178, 200, 230], E: [null, null, 26, 33, 46, 61, 78, 96, 117, 150, 183, 212, 245, 280, 330], F: [null, null, null,null,null,null, 87, 109, 133, 173, 212, 247, 287, 330, 389], }, Cu_EPR_2: { A1: [19, 26, 35, 45, 61, 81, 106, 131, 158, 200, 241, 278, 318, 362, 424], A2: [18.5, 25, 33, 42, 57, 76, 99, 121, 145, 183, 220, 253, 290, 329, 386], B1: [23, 31, 42, 54, 75, 100, 133, 164, 198, 253, 306, 354, 407, 464, 546], B2: [22, 30, 40, 51, 69, 91, 119, 146, 175, 221, 265, 305, 348, 394, 461], C: [24, 33, 45, 58, 80, 107, 138, 171, 209, 269, 328, 382, 441, 506, 599], D: [26, 34, 44, 56, 73, 95, 121, 146, 173, 213, 252, 287, 324, 363, 419], E: [26, 36, 49, 63, 86, 115, 149, 185, 225, 289, 352, 410, 473, 542, 641], F: [null, null, null,null,null,null, 161, 200, 242, 310, 377, 437, 504, 575, 679], }, Cu_EPR_3: { A1: [17, 23, 31, 40, 54, 73, 95, 117, 141, 179, 216, 249, 285, 324, 380], A2: [16.5, 22, 30, 38, 51, 68, 89, 109, 130, 164, 197, 227, 259, 295, 346], B1: [20, 28, 37, 48, 66, 88, 117, 144, 175, 222, 269, 312, 358, 408, 481], B2: [19.5, 26, 35, 44, 60, 80, 105, 128, 154, 194, 233, 268, 307, 348, 407], C: [22, 30, 40, 52, 71, 96, 119, 147, 179, 229, 278, 322, 371, 424, 500], D: [21, 28, 36, 44, 58, 75, 96, 115, 135, 167, 197, 223, 251, 281, 324], E: [23, 32, 42, 54, 75, 100, 127, 158, 192, 246, 298, 346, 399, 456, 538], F: [null, null, null,null,null,null, 135, 169, 207, 268, 328, 383, 444, 510, 607], }, Al_EPR_2: { A1: [null, null, 27, 35, 48, 64, 84, 103, 125, 158, 191, 220, 253, 288, 338], A2: [null, null, 26, 33, 44, 59, 77, 94, 113, 142, 171, 197, 226, 256, 300], B1: [null, null, 32, 42, 58, 78, 103, 127, 155, 197, 238, 275, 316, 361, 425], B2: [null, null, 31, 39, 53, 71, 92, 114, 137, 173, 207, 239, 274, 312, 365], C: [null, null, 36, 47, 64, 86, 112, 138, 169, 217, 263, 305, 351, 401, 472], D: [null, null, 34, 43, 56, 73, 93, 112, 132, 163, 193, 220, 249, 279, 322], E: [null, null, 39, 50, 70, 93, 121, 150, 184, 237, 289, 337, 389, 447, 530], F: [null, null, null,null,null,null, 130, 162, 197, 254, 311, 362, 419, 480, 569], }, Al_EPR_3: { A1: [null, null, 25, 32, 43, 57, 75, 92, 112, 142, 171, 197, 226, 257, 302], A2: [null, null, 23, 30, 39, 53, 69, 84, 101, 128, 153, 176, 201, 229, 268], B1: [null, null, 29, 37, 51, 69, 91, 112, 136, 174, 211, 244, 280, 320, 377], B2: [null, null, 27, 35, 47, 63, 82, 101, 121, 153, 184, 212, 242, 275, 322], C: [null, null, 32, 41, 57, 76, 98, 121, 147, 188, 228, 264, 305, 348, 410], D: [null, null, 28, 35, 46, 59, 75, 90, 106, 130, 154, 174, 197, 220, 253], E: [null, null, 35, 45, 62, 84, 101, 126, 154, 198, 241, 280, 324, 371, 439], F: [null, null, null,null,null,null, 110, 137, 167, 216, 264, 308, 356, 409, 485], }, }; /* ---------- Tab. 40 — fatores de correção por temperatura -------------- */ const K_TEMP_PVC = { 10:1.22, 15:1.17, 20:1.12, 25:1.06, 30:1.00, 35:0.94, 40:0.87, 45:0.79, 50:0.71, 55:0.61, 60:0.50, }; const K_TEMP_EPR = { 10:1.15, 15:1.12, 20:1.08, 25:1.04, 30:1.00, 35:0.96, 40:0.91, 45:0.87, 50:0.82, 55:0.76, 60:0.71, 65:0.65, 70:0.58, 75:0.50, }; /* ---------- Tab. 42 — fator de agrupamento ----------------------------- */ const K_AGRUP = { 1:1.00, 2:0.80, 3:0.70, 4:0.65, 5:0.60, 6:0.57, 7:0.54, 8:0.52, 9:0.50, 10:0.49, 12:0.45, 14:0.43, 16:0.41, 18:0.39, 20:0.38, }; /* ---------- Resistividade (Ω·mm²/m) na temperatura de regime ----------- */ /* Cu @70°C ≈ 0,0225 · Cu @90°C ≈ 0,0246 · Al @70°C ≈ 0,036 · Al @90°C ≈ 0,041 */ const RHO = { Cu_PVC: 0.0225, Cu_EPR: 0.0246, Al_PVC: 0.0360, Al_EPR: 0.0410, }; /* ---------- Tab. 27 — constante K p/ critério curto-circuito ----------- */ const K_CURTO = { Cu_PVC: 115, Cu_EPR: 143, Al_PVC: 76, Al_EPR: 94, }; /* ---------- Tab. 47 — seção mínima por aplicação ----------------------- */ /* Alumínio na NBR 5410 só é permitido a partir de 16 mm² */ const SECAO_MIN_APLIC = { iluminacao: { rotulo: 'Circuito de iluminação', Cu: 1.5, Al: 16 }, tomadas: { rotulo: 'Circuito de tomadas (TUG/TUE)', Cu: 2.5, Al: 16 }, forca: { rotulo: 'Circuitos de força/motor', Cu: 2.5, Al: 16 }, alimentador: { rotulo: 'Alimentador (entrada/quadros)', Cu: 10, Al: 16 }, controle: { rotulo: 'Sinalização / controle', Cu: 0.5, Al: 16 }, }; /* ---------- Diâmetros aproximados (para o desenho) --------------------- */ const D_EXT = { 1.5:3.4, 2.5:3.9, 4:4.5, 6:5.1, 10:6.6, 16:7.7, 25:9.6, 35:10.8, 50:12.2, 70:14.0, 95:16.0, 120:17.6, 150:19.3, 185:21.4, 240:24.0, 300:26.3, 400:29.5, 500:32.4, }; /* ============================ Utilitários ============================== */ function fmt(v, casas) { if (!isFinite(v) || v == null) return '—'; const n = casas == null ? 2 : casas; return v.toFixed(n).replace(/\.?0+$/, ''); } function interp(map, x) { const keys = Object.keys(map).map(Number).sort((a,b) => a-b); if (x <= keys[0]) return map[keys[0]]; if (x >= keys[keys.length-1]) return map[keys[keys.length-1]]; for (let i = 0; i < keys.length-1; i++) { const a = keys[i], b = keys[i+1]; if (x >= a && x <= b) { const t = (x - a) / (b - a); return map[a] + t * (map[b] - map[a]); } } return 1; } function fatorAgrupamento(n) { if (n <= 1) return 1.0; const keys = Object.keys(K_AGRUP).map(Number).sort((a,b) => a-b); let best = keys[0]; for (const k of keys) { if (k <= n) best = k; } return K_AGRUP[best]; } /* Primeira seção da lista que satisfaz cond(secao, capacidade) */ function buscarSecao(linha, cond) { if (!linha) return null; for (let i = 0; i < SECOES_TAB.length; i++) { if (linha[i] == null) continue; if (cond(SECOES_TAB[i], linha[i])) { return { secao: SECOES_TAB[i], capacidade: linha[i] }; } } return null; } /* Primeira seção comercial ≥ valor */ function arredondaParaSecaoComercial(v) { for (const s of SECOES_TAB) if (s >= v) return s; return SECOES_TAB[SECOES_TAB.length - 1]; } /* ============================ Corrente de projeto ====================== */ function calcCorrente(modo, p) { const V = +p.V || 0, FP = +p.FP || 1; const Pp = +p.P || 0, S = +p.S || 0, Id = +p.I || 0; if (V <= 0 && modo !== 'direta') return 0; switch (modo) { case 'direta': return Math.max(0, Id); case 'mono_P': return Pp / (V * Math.max(0.01, FP)); case 'bi_P': return Pp / (V * Math.max(0.01, FP)); case 'tri_P': return Pp / (Math.sqrt(3) * V * Math.max(0.01, FP)); case 'mono_S': return S / V; case 'tri_S': return S / (Math.sqrt(3) * V); default: return 0; } } /* ============================ Critérios ================================ */ /* (1) Capacidade de condução de corrente (ampacidade) */ function critAmpacidade({ Ip, material, isolacao, ncond, metodo, tempAmb, nCircuitos }) { const tabMap = isolacao === 'PVC' ? K_TEMP_PVC : K_TEMP_EPR; const k1 = interp(tabMap, tempAmb); const k2 = fatorAgrupamento(nCircuitos); const Ic = Ip / (k1 * k2); const linha = TAB[`${material}_${isolacao}_${ncond}`]?.[metodo]; if (!linha) return { ok:false, msg:'Combinação sem dados na tabela', k1, k2, Ic }; const esc = buscarSecao(linha, (_, cap) => cap >= Ic); return { ok: !!esc, secao: esc?.secao || null, capacidade: esc?.capacidade || null, Ip, k1, k2, Ic, detalhe: `Iz ≥ Ip/(K1·K2) = ${fmt(Ip,1)} / (${fmt(k1,2)}·${fmt(k2,2)}) = ${fmt(Ic,1)} A`, }; } /* (2) Queda de tensão (despreza X, suficiente para BT até ~70 mm²) ΔV% = k · ρ · L · I · cosφ · 100 / (S · V_ref) k: 2 (mono), 2 (bi), √3 (tri) Inverte: S_min = k · ρ · L · I · cosφ · 100 / (ΔV%_max · V_ref) */ function critQueda({ Ip, material, isolacao, modo, V, FP, L_m, dV_max_pct }) { const rho = RHO[`${material}_${isolacao}`]; if (!(L_m > 0) || !(dV_max_pct > 0)) { return { ok:false, msg:'Defina L e ΔV% máxima' }; } if (!(Ip > 0)) return { ok:false, msg:'Ip não definida' }; const cosphi = (modo === 'mono_S' || modo === 'tri_S') ? 1 : Math.max(0.01, FP); let k = 2, V_ref = V; /* monofásico default */ if (modo === 'tri_P' || modo === 'tri_S') { k = Math.sqrt(3); V_ref = V; } else if (modo === 'bi_P') { k = 2; V_ref = V; } if (V_ref <= 0) return { ok:false, msg:'V inválida' }; const S_min = (k * rho * L_m * Ip * cosphi * 100) / (dV_max_pct * V_ref); const secao = arredondaParaSecaoComercial(S_min); /* ΔV% real para a seção comercial escolhida */ const dV_real = (k * rho * L_m * Ip * cosphi * 100) / (secao * V_ref); return { ok: secao != null, secao, capacidade: null, S_calc: S_min, dV_real, k, rho, L_m, dV_max_pct, V_ref, detalhe: `ΔV% = ${k === 2 ? '2' : '√3'} · ρ · L · I · cosφ · 100 / (S · V) S_min = ${k === 2 ? '2' : '√3'}·${fmt(rho,4)}·${fmt(L_m,1)}·${fmt(Ip,1)}·${fmt(cosphi,2)}·100 / (${fmt(dV_max_pct,2)}·${fmt(V_ref,0)}) S_min teórica = ${fmt(S_min,2)} mm² → comercial = ${secao} mm² (ΔV ≈ ${fmt(dV_real,2)}%)`, }; } /* (3) Seção mínima por aplicação (Tab. 47) */ function critMinima({ material, aplicacao }) { const ap = SECAO_MIN_APLIC[aplicacao]; if (!ap) return { ok:false, msg:'Aplicação não definida' }; const sec = ap[material]; if (sec == null) return { ok:false, msg:'Sem mínima definida para este material' }; return { ok: true, secao: sec, capacidade: null, detalhe: `${ap.rotulo} · mínimo NBR 5410 = ${sec} mm² (${material})`, }; } /* (4) Proteção contra sobrecargas — Iz(S) ≥ In/(K1·K2) */ function critSobrecarga({ In, material, isolacao, ncond, metodo, tempAmb, nCircuitos }) { if (!(In > 0)) return { ok:false, msg:'Defina In (corrente nominal do dispositivo)' }; const tabMap = isolacao === 'PVC' ? K_TEMP_PVC : K_TEMP_EPR; const k1 = interp(tabMap, tempAmb); const k2 = fatorAgrupamento(nCircuitos); const I_alvo = In / (k1 * k2); const linha = TAB[`${material}_${isolacao}_${ncond}`]?.[metodo]; if (!linha) return { ok:false, msg:'Sem dados na tabela' }; const esc = buscarSecao(linha, (_, cap) => cap >= I_alvo); return { ok: !!esc, secao: esc?.secao || null, capacidade: esc?.capacidade || null, In, k1, k2, I_alvo, detalhe: `Iz ≥ In/(K1·K2) = ${fmt(In,1)} / (${fmt(k1,2)}·${fmt(k2,2)}) = ${fmt(I_alvo,1)} A`, }; } /* (5) Curto-circuito — S_min = I_cc · √t / K */ function critCurto({ I_cc_kA, t_s, material, isolacao }) { if (!(I_cc_kA > 0) || !(t_s > 0)) return { ok:false, msg:'Defina I_cc e t' }; const K = K_CURTO[`${material}_${isolacao}`]; const I_cc = I_cc_kA * 1000; const S_min = (I_cc * Math.sqrt(t_s)) / K; const secao = arredondaParaSecaoComercial(S_min); return { ok: true, secao, capacidade: null, S_calc: S_min, K, I_cc, t_s, detalhe: `S_min = I_cc·√t / K = ${fmt(I_cc,0)}·√${fmt(t_s,2)} / ${K} S_min teórica = ${fmt(S_min,2)} mm² → comercial = ${secao} mm²`, }; } /* ============================ Orquestrador ============================= */ function dimensionar(params) { const { ativos, Ip } = params; const resultados = {}; if (ativos.ampacidade) resultados.ampacidade = critAmpacidade(params); if (ativos.queda) resultados.queda = critQueda(params); if (ativos.minima) resultados.minima = critMinima(params); if (ativos.sobrecarga) resultados.sobrecarga = critSobrecarga(params); if (ativos.curto) resultados.curto = critCurto(params); /* Vencedor: maior seção entre os critérios OK */ let vencedor = null; let secaoVencedora = 0; for (const [k, r] of Object.entries(resultados)) { if (r.ok && r.secao != null && r.secao > secaoVencedora) { secaoVencedora = r.secao; vencedor = k; } } /* Capacidade real do cabo escolhido (ampacidade real do vencedor) */ let capacidadeReal = null; if (secaoVencedora) { const idx = SECOES_TAB.indexOf(secaoVencedora); const linha = TAB[`${params.material}_${params.isolacao}_${params.ncond}`]?.[params.metodo]; if (linha && idx >= 0) capacidadeReal = linha[idx]; } return { Ip, resultados, vencedor, secaoVencedora, capacidadeReal }; } /* ===================== Desenho da seção do condutor ===================== */ function ConductorSVG({ secao, material, isolacao, ncond, capacidade, vencedorCor }) { const dExt = D_EXT[secao] || (2 * Math.sqrt(secao / Math.PI) + 3); const dCore = 2 * Math.sqrt(secao / Math.PI); const VB = 320; const maxExt = 24; const px = (VB * 0.82) / maxExt; const cx = VB / 2, cy = VB / 2; const rExt = (dExt / 2) * px; const rIso = rExt - Math.max(6, rExt * 0.10); const rCore = (dCore / 2) * px; const corNucleo = material === 'Cu' ? C.copper : C.aluminum; const corIso = isolacao === 'PVC' ? '#1a4d8f' : '#1a8f6b'; const arranjo = (() => { if (ncond === 1) return [{ x: cx, y: cy }]; if (ncond === 2) { const d = rIso - rCore - 4; return [{ x: cx - d/2, y: cy }, { x: cx + d/2, y: cy }]; } if (ncond === 3) { const R = (rIso - rCore) - 4; const a = -Math.PI / 2; return [0,1,2].map(i => ({ x: cx + R * Math.cos(a + i * 2 * Math.PI / 3), y: cy + R * Math.sin(a + i * 2 * Math.PI / 3), })); } const R = (rIso - rCore) - 6; return Array.from({ length: ncond }, (_, i) => { const a = -Math.PI / 2 + (i * 2 * Math.PI / ncond); return { x: cx + R * Math.cos(a), y: cy + R * Math.sin(a) }; }); })(); const isMulti = ncond >= 2; const rCoreMulti = isMulti ? Math.max(8, rCore * 0.6) : rCore; const rIsoMulti = isMulti ? rCoreMulti + Math.max(4, rCoreMulti * 0.45) : rIso; const rExtMulti = isMulti ? Math.max(...arranjo.map(p => Math.hypot(p.x - cx, p.y - cy))) + rIsoMulti + 8 : rExt; const coresVeias = ncond === 2 ? ['#1f6dd6', '#222'] : ncond === 3 ? ['#222', '#1f6dd6', '#2fa256'] : ['#222', '#c33', '#888', '#1f6dd6', '#2fa256']; return ( {/* Anel de critério vencedor (cor) */} {isMulti ? arranjo.map((p, i) => ( )) : ( ) } Ø {fmt(dExt, 1)} mm {secao} mm² · {ncond}× · {material === 'Cu' ? 'Cobre' : 'Alumínio'} · {isolacao} {capacidade && ( CAPACIDADE Iz {fmt(capacidade,0)} A )} ); } /* ============================ Sub-componentes ========================== */ function Field({ label, hint, children }) { return ( ); } function Pill({ active, onClick, children, title }) { return ( ); } function Stat({ rotulo, valor, unidade, accent }) { return (
{rotulo}
{valor}{unidade && {unidade}}
); } function Switch({ on, onChange, cor }) { return ( ); } function CriterioCard({ id, titulo, ativo, onToggle, status, secaoCalc, msg, detalhe, vencedor, children }) { const cor = CRIT_COR[id]; return (

{titulo}

{vencedor && CRITÉRIO VENCEDOR}
{ativo && (
{children}
{status === 'ok' && secaoCalc != null && (
{secaoCalc} mm²
)} {status === 'erro' && (
⚠ {msg}
)} {detalhe && status === 'ok' && (
{detalhe}
)}
)}
); } /* ============================ Componente principal ===================== */ function SecaoCondutor() { /* corrente */ const [modo, setModo] = useState('tri_P'); const [V, setV] = useState(380); const [P, setP] = useState(7500); const [S, setS] = useState(10000); const [FP, setFP] = useState(0.92); const [Idir, setIdir] = useState(20); /* cabo / instalação */ const [material, setMaterial] = useState('Cu'); const [isolacao, setIsolacao] = useState('PVC'); const [ncond, setNcond] = useState(3); const [metodo, setMetodo] = useState('B1'); const [tempAmb, setTempAmb] = useState(30); const [nCircuitos, setNCirc] = useState(1); /* critérios ativos */ const [ativos, setAtivos] = useState({ ampacidade: true, queda: false, minima: false, sobrecarga: false, curto: false, }); /* parâmetros dos critérios opcionais */ const [L_m, setL] = useState(30); const [dV_max, setDV] = useState(4); const [aplicacao, setAp] = useState('tomadas'); const [In, setIn] = useState(20); const [I_cc_kA, setIcc] = useState(3); const [t_s, setT] = useState(0.1); /* override manual do desenho */ const [overrideSecao, setOverr] = useState(null); /* corrente de projeto */ const Ip = useMemo(() => calcCorrente(modo, { V, P, S, FP, I: Idir }), [modo, V, P, S, FP, Idir]); /* cálculo consolidado */ const dim = useMemo(() => dimensionar({ ativos, Ip, material, isolacao, ncond, metodo, tempAmb, nCircuitos, modo, V, FP, L_m, dV_max_pct: dV_max, aplicacao, In, I_cc_kA, t_s, }), [ativos, Ip, material, isolacao, ncond, metodo, tempAmb, nCircuitos, modo, V, FP, L_m, dV_max, aplicacao, In, I_cc_kA, t_s]); /* seção apresentada no desenho */ const secaoMostrada = overrideSecao != null ? overrideSecao : (dim.secaoVencedora || null); /* capacidade real do cabo (na seção mostrada) */ const capMostrada = useMemo(() => { if (!secaoMostrada) return null; const idx = SECOES_TAB.indexOf(secaoMostrada); const linha = TAB[`${material}_${isolacao}_${ncond}`]?.[metodo]; return linha && idx >= 0 ? linha[idx] : null; }, [secaoMostrada, material, isolacao, ncond, metodo]); useEffect(() => { setOverr(null); }, [material, isolacao, ncond, metodo, tempAmb, nCircuitos, modo, ativos]); function exportarJSON() { const data = { modulo: 'secao_condutor-nbr5410', criado_em: new Date().toISOString(), entrada: { modo, V, P, S, FP, I: Idir }, cabo: { material, isolacao, ncond, metodo, tempAmb, nCircuitos }, criterios_ativos: ativos, parametros: { L_m, dV_max, aplicacao, In, I_cc_kA, t_s }, resultados: dim.resultados, vencedor: dim.vencedor, secao_final_mm2: dim.secaoVencedora, capacidade_Iz_A: dim.capacidadeReal, }; const blob = new Blob([JSON.stringify(data, null, 2)], { type:'application/json' }); const a = document.createElement('a'); a.href = URL.createObjectURL(blob); a.download = `secao_condutor_${Date.now()}.json`; a.click(); setTimeout(() => URL.revokeObjectURL(a.href), 1000); } const modoInfo = { direta: { label: 'Direta', formula: 'I = valor digitado' }, mono_P: { label: 'Mono · P', formula: 'I = P / (V · FP)' }, bi_P: { label: 'Bifásico · P', formula: 'I = P / (V_ff · FP)' }, tri_P: { label: 'Trifásico · P', formula: 'I = P / (√3 · V_ff · FP)' }, mono_S: { label: 'Mono · S', formula: 'I = S / V' }, tri_S: { label: 'Trifásico · S', formula: 'I = S / (√3 · V_ff)' }, }; const toggleAtivo = (k) => setAtivos(prev => ({ ...prev, [k]: !prev[k] })); /* lista para a tabela comparativa */ const linhaComp = (id, titulo) => { const r = dim.resultados[id]; if (!ativos[id]) return null; if (!r) return null; const isVenc = dim.vencedor === id; return ( {titulo} {r.ok ? `${r.secao} mm²` : '—'} {r.ok ? (isVenc ? '✓ vencedor' : 'OK') : '✗ ' + (r.msg || '')} ); }; return (
Dimensionamento · NBR 5410 (Item 6.2)
{/* COL 1 — Entradas */}

Corrente de projeto

{Object.entries(modoInfo).map(([k, v]) => setModo(k)}>{v.label} )}
{modoInfo[modo].formula}
{modo === 'direta' && ( setIdir(+e.target.value)}/> )} {(modo === 'mono_P' || modo === 'tri_P' || modo === 'bi_P') && (<> setP(+e.target.value)}/> setV(+e.target.value)}/> setFP(+e.target.value)}/> )} {(modo === 'mono_S' || modo === 'tri_S') && (<> setS(+e.target.value)}/> setV(+e.target.value)}/> )}
Ip calculada {fmt(Ip, 1)} A

Cabo & instalação

setMaterial('Cu')}> Cobre setMaterial('Al')}> Alumínio
setIsolacao('PVC')}> PVC 70°C setIsolacao('EPR')}> EPR/XLPE 90°C
setNcond(2)}>2 cond. setNcond(3)}>3 cond.
setTempAmb(+e.target.value)}/> setNCirc(+e.target.value)}/>
{/* Critérios */}

Critérios de dimensionamento

{/* (1) AMPACIDADE */} toggleAtivo('ampacidade')} status={dim.resultados.ampacidade?.ok ? 'ok' : 'erro'} secaoCalc={dim.resultados.ampacidade?.secao} msg={dim.resultados.ampacidade?.msg} detalhe={dim.resultados.ampacidade?.detalhe} vencedor={dim.vencedor === 'ampacidade'}>
K1 = {fmt(dim.resultados.ampacidade?.k1, 2)} K2 = {fmt(dim.resultados.ampacidade?.k2, 2)} Ic = {fmt(dim.resultados.ampacidade?.Ic, 1)} A
{/* (2) QUEDA DE TENSÃO */} toggleAtivo('queda')} status={dim.resultados.queda?.ok ? 'ok' : 'erro'} secaoCalc={dim.resultados.queda?.secao} msg={dim.resultados.queda?.msg} detalhe={dim.resultados.queda?.detalhe} vencedor={dim.vencedor === 'queda'}>
setL(+e.target.value)}/>
{/* (3) SEÇÃO MÍNIMA */} toggleAtivo('minima')} status={dim.resultados.minima?.ok ? 'ok' : 'erro'} secaoCalc={dim.resultados.minima?.secao} msg={dim.resultados.minima?.msg} detalhe={dim.resultados.minima?.detalhe} vencedor={dim.vencedor === 'minima'}> {/* (4) SOBRECARGA */} toggleAtivo('sobrecarga')} status={dim.resultados.sobrecarga?.ok ? 'ok' : 'erro'} secaoCalc={dim.resultados.sobrecarga?.secao} msg={dim.resultados.sobrecarga?.msg} detalhe={dim.resultados.sobrecarga?.detalhe} vencedor={dim.vencedor === 'sobrecarga'}> setIn(+e.target.value)}/> {/* (5) CURTO-CIRCUITO */} toggleAtivo('curto')} status={dim.resultados.curto?.ok ? 'ok' : 'erro'} secaoCalc={dim.resultados.curto?.secao} msg={dim.resultados.curto?.msg} detalhe={dim.resultados.curto?.detalhe} vencedor={dim.vencedor === 'curto'}>
setIcc(+e.target.value)}/> setT(+e.target.value)}/>
K = {K_CURTO[`${material}_${isolacao}`]}
{/* COMPARATIVO */}

Comparativo entre critérios

{linhaComp('ampacidade', 'Ampacidade')} {linhaComp('queda', 'Queda de tensão')} {linhaComp('minima', 'Seção mínima')} {linhaComp('sobrecarga', 'Sobrecarga')} {linhaComp('curto', 'Curto-circuito')}
CritérioSeção mín.Status
{/* COL 3 — Resultado final + Desenho */}

Seção final

{dim.secaoVencedora ? (
RESULTADO
{dim.secaoVencedora} mm²
vencedor: { {ampacidade:'Ampacidade', queda:'Queda de tensão', minima:'Seção mínima', sobrecarga:'Sobrecarga', curto:'Curto-circuito'}[dim.vencedor] }
{dim.capacidadeReal && (
Iz = {fmt(dim.capacidadeReal, 0)} A
)}
) : (
Ative ao menos um critério para obter resultado.
)}
{secaoMostrada ? :
Sem seção definida
}
{material === 'Cu' ? 'Cobre' : 'Alumínio'}
isolação {isolacao}
capa
{overrideSecao && ( )}
Resumo
Ip = {fmt(Ip, 1)} A
{Object.entries(dim.resultados).map(([k, r]) => ativos[k] && r.ok && (
{k}: {r.secao} mm²
) )} {dim.secaoVencedora && (
→ final: {ncond}× {dim.secaoVencedora} mm² {material} {isolacao}
)}
{/* /vlsec-right */}
); } /* ================================ CSS ================================== */ const CSS = ` .vlsec{display:flex;flex-direction:column;min-height:100%;color:var(--fg); font-family:var(--ff-body)} .vlsec *{box-sizing:border-box} .vlsec h1,.vlsec h2,.vlsec h3{font-family:var(--ff-display);margin:0} .vlsec-topbar{display:flex;align-items:center;justify-content:space-between; margin-bottom:16px;gap:12px} .vlsec-body{display:grid;grid-template-columns:360px 1fr;gap:var(--gap-grid); align-items:start;flex:1} .vlsec-right{display:grid;grid-template-columns:1fr 280px;gap:var(--gap-grid); align-items:start} .vlsec-col{display:flex;flex-direction:column;gap:12px;overflow-y:auto} .vlsec-col.panel{padding:var(--pad-panel)} .vlsec-col-svg.panel{background:var(--bg-2)} .vlsec-col-title{font-size:10px;font-weight:600;letter-spacing:1.6px; text-transform:uppercase;color:var(--fg-mute);margin:0 0 6px} .vlsec-sub-title{font-size:10px;font-weight:600;letter-spacing:1.6px; text-transform:uppercase;color:var(--fg-mute);margin:16px 0 6px} .vlsec-sep{border:none;border-top:1px solid var(--border);margin:8px 0 4px} .vlsec-pills{display:flex;flex-wrap:wrap;gap:6px} .vlsec-pill{background:var(--bg-2);color:var(--fg-mute);border:1px solid var(--border); padding:6px 11px;border-radius:var(--r-pill);cursor:pointer; font:500 11.5px var(--ff-body);letter-spacing:.2px;transition:all .12s ease; display:inline-flex;align-items:center;gap:6px} .vlsec-pill:hover{color:var(--fg);border-color:var(--border-2)} .vlsec-pill.is-active{background:var(--accent-soft);color:var(--fg); border-color:var(--accent);box-shadow:0 0 0 1px var(--accent-soft) inset} .vlsec-pill small{color:var(--fg-mute);font-size:10.5px;margin-left:3px} .vlsec-pill i{width:10px;height:10px;border-radius:50%;display:inline-block; border:1px solid rgba(0,0,0,0.3)} .vlsec-toggle{display:flex;gap:6px;flex-wrap:wrap} .vlsec-formula{font:13px var(--ff-mono);color:var(--accent-2); background:oklch(72% 0.14 200/0.07);border:1px solid oklch(72% 0.14 200/0.20); padding:8px 12px;border-radius:var(--r-2)} .vlsec-field{display:flex;flex-direction:column;gap:5px} .vlsec-field-head{display:flex;justify-content:space-between;align-items:baseline; font-size:11.5px;color:var(--fg-mute);font-weight:500;letter-spacing:.3px} .vlsec-field-hint{font-size:10.5px;color:var(--fg-mute);opacity:.7} .vlsec-field input,.vlsec-field select{ background:var(--bg-2);color:var(--fg);border:1px solid var(--border); border-radius:var(--r-2);padding:8px 11px;font:14px var(--ff-mono); outline:none;transition:border .12s;width:100%} .vlsec-field input:focus,.vlsec-field select:focus{border-color:var(--accent)} .vlsec-row2{display:grid;grid-template-columns:1fr 1fr;gap:12px} .vlsec-ip-box{display:flex;justify-content:space-between;align-items:center; padding:8px 14px;background:var(--bg-2);border:1px solid var(--border); border-radius:var(--r-2);margin-top:4px} .vlsec-ip-box span{font-size:11px;color:var(--fg-mute);letter-spacing:.5px;text-transform:uppercase} .vlsec-ip-box strong{font:600 18px var(--ff-mono);color:var(--accent-2)} /* ----- cards de critério ----- */ .vlsec-crit{background:var(--bg-2);border:1px solid var(--border);border-radius:var(--r-3); overflow:hidden;transition:border-color .15s} .vlsec-crit.is-ativo{border-color:var(--border-2)} .vlsec-crit.is-vencedor{border-color:var(--accent)!important; box-shadow:0 0 0 1px var(--accent-soft) inset} .vlsec-crit-head{display:flex;align-items:center;justify-content:space-between; padding:10px 14px;gap:10px;cursor:pointer} .vlsec-crit-title{display:flex;align-items:center;gap:9px;flex-wrap:wrap} .vlsec-crit-dot{width:8px;height:8px;border-radius:50%;flex-shrink:0} .vlsec-crit-badge{font:600 9.5px var(--ff-mono);letter-spacing:.8px;padding:2px 7px; border-radius:var(--r-pill);text-transform:uppercase} .vlsec-crit-name{font:600 12px var(--ff-display)} .vlsec-crit-body{padding:12px 14px;display:flex;flex-direction:column;gap:10px} .vlsec-crit-secao{display:flex;align-items:baseline;gap:5px; font-family:var(--ff-display)} .vlsec-crit-secao-num{font-size:26px;font-weight:700;line-height:1} .vlsec-crit-secao-unit{font-size:14px;color:var(--fg-mute)} .vlsec-crit-msg{font-size:12px;color:var(--fg-mute);font-family:var(--ff-mono); background:var(--bg-0);padding:6px 10px;border-radius:var(--r-2)} .vlsec-mini-stats{display:flex;gap:14px;flex-wrap:wrap; font:11.5px var(--ff-mono);color:var(--fg-mute)} /* ----- tabela comparativa ----- */ .vlsec-table-wrap{border:1px solid var(--border);border-radius:var(--r-2);overflow:hidden} .vlsec-table{width:100%;border-collapse:collapse;font-size:12px} .vlsec-table th{padding:7px 10px;text-align:left;font:600 9.5px var(--ff-mono); letter-spacing:.8px;text-transform:uppercase;color:var(--fg-mute); background:var(--bg-2);border-bottom:1px solid var(--border)} .vlsec-table td{padding:8px 10px;border-bottom:1px solid var(--border);color:var(--fg-dim)} .vlsec-table tr:last-child td{border-bottom:none} .vlsec-table tr.is-vencedor td{color:var(--fg);font-weight:600;background:var(--accent-soft)} .vlsec-table tr.is-falha td{opacity:.5} .vlsec-table-dot{display:inline-block;width:7px;height:7px;border-radius:50%; margin-right:7px;vertical-align:middle} /* ----- toggle switch ----- */ .vlsec-switch{position:relative;width:32px;height:18px;flex-shrink:0} .vlsec-switch input{opacity:0;width:0;height:0} .vlsec-switch-track{position:absolute;inset:0;border-radius:var(--r-pill); background:var(--bg-3);border:1px solid var(--border); transition:background .2s,border-color .2s;cursor:pointer} .vlsec-switch input:checked + .vlsec-switch-track{background:var(--accent); border-color:var(--accent)} .vlsec-switch-track::after{content:'';position:absolute;top:2px;left:2px; width:12px;height:12px;border-radius:50%;background:#fff; transition:transform .2s;box-shadow:0 1px 3px rgba(0,0,0,.4)} .vlsec-switch input:checked + .vlsec-switch-track::after{transform:translateX(14px)} /* ----- painel resultado ----- */ .vlsec-final{border:1px solid var(--border);border-radius:var(--r-3); padding:16px;display:flex;flex-direction:column;align-items:center;gap:5px; text-align:center;background:var(--bg-0);transition:border-color .3s} .vlsec-final-head{font:600 9px var(--ff-mono);letter-spacing:1.8px; text-transform:uppercase;color:var(--fg-mute)} .vlsec-final-main{display:flex;align-items:baseline;gap:5px} .vlsec-final-num{font:700 44px var(--ff-display);line-height:1;letter-spacing:-1px} .vlsec-final-unit{font-size:20px;color:var(--fg-mute)} .vlsec-final-sub{font-size:12px;color:var(--fg-mute)} .vlsec-final-sub b{color:var(--fg)} .vlsec-final-cap{font:600 11px var(--ff-mono);color:var(--ok);margin-top:2px; letter-spacing:.5px} .vlsec-warn{font-size:12px;color:var(--fg-mute);padding:12px; background:var(--bg-2);border:1px solid var(--border);border-radius:var(--r-2); text-align:center} .vlsec-svg-wrap{display:flex;justify-content:center;padding:8px 0} .vlsec-svg-empty{height:120px;display:flex;align-items:center;justify-content:center; color:var(--fg-mute);font-size:12px} .vlsec-legend{display:flex;flex-wrap:wrap;justify-content:center; gap:12px;font-size:11.5px;color:var(--fg-mute);margin:4px 0} .vlsec-legend i{width:12px;height:12px;border-radius:50%;display:inline-block; margin-right:5px;vertical-align:middle;border:1px solid rgba(0,0,0,0.2)} .vlsec-foot{margin-top:auto;padding:12px 14px;background:var(--bg-0); border:1px solid var(--border);border-radius:var(--r-2); font:12px var(--ff-mono);color:var(--fg-mute);line-height:1.7} .vlsec-foot b{color:var(--fg);font-family:var(--ff-display);font-size:11px; letter-spacing:1px;text-transform:uppercase;display:block;margin-bottom:4px} @media (max-width:1100px){ .vlsec-body{grid-template-columns:1fr} .vlsec-right{grid-template-columns:1fr} } @media (max-width:760px){ .vlsec-row2{grid-template-columns:1fr} .vlsec-svg-wrap{max-width:280px;margin:0 auto} } `; if (!document.getElementById('vl-secao-condutor-css')) { const s = document.createElement('style'); s.id = 'vl-secao-condutor-css'; s.textContent = CSS; document.head.appendChild(s); } /* ============================ Registro global ========================== */ window.VL_SecaoCondutor = SecaoCondutor; if (window.VOLTLAB_MODULES && Array.isArray(window.VOLTLAB_MODULES)) { window.VOLTLAB_MODULES.push({ id: 'secao_condutor', nome: 'Seção do Condutor', descricao: 'Dimensionamento por 5 critérios da NBR 5410 (ampacidade, queda, mínima, sobrecarga, curto)', component: SecaoCondutor, }); } })();