/* global React */ /* =========================================================== VOLTLAB · SPDA — Dimensionamento Completo ABNT NBR 5419:2026 (Partes 1, 2, 3 e 4) Aba 1 · Análise de Risco (Parte 2) Aba 2 · SPDA Externo (Parte 3) Aba 3 · SPDA Interno / MPS/DPS (Parte 4) =========================================================== */ const { useState, useMemo, useEffect } = React; const usePersist = (key, init) => window.useLocalStorage ? window.useLocalStorage(key, init) : React.useState(init); /* ─── UI atoms (re-exposed locally so this file is standalone) ─── */ const RIcon = ({ n, sz = 16 }) => { const p = { width: sz, height: sz, viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: 1.5, strokeLinecap: "round", strokeLinejoin: "round" }; const paths = { ok: , warn: <>, info: <>, bolt: , shield: <>, zap: , }; return {paths[n]}; }; /* ─── Design-system components ──────────────────────────────── */ function FieldBlock({ label, hint, children }) { return (
{children}
); } function NumberInput({ value, onChange, suffix, step, min }) { return (
onChange(e.target.value)} step={step ?? "0.1"} min={min ?? "0"}/> {suffix && {suffix}}
); } function Seg({ value, onChange, options }) { return (
{options.map(o => ( ))}
); } function ResultBig({ label, value, unit, status }) { return (
{label}
{value} {unit}
); } function MetricCell({ label, value, unit, status }) { return (
{label}
{value} {unit && {unit}}
); } function StatusBanner({ kind, children }) { const icon = kind === "ok" ? "ok" : "warn"; return (
{children}
); } function MemoryStep({ n, title, isFormula, children }) { return (
{String(n).padStart(2, "0")} {title}
{children}
); } /* ═══════════════════════════════════════════════════════════════ TABELAS NORMATIVAS EMBUTIDAS Fonte: ABNT NBR 5419-2:2026 e NBR 5419-3:2026 ════════════════════════════════════════════════════════════════ */ /* Tabela 4 / NBR 5419-2 — Risco Tolerável */ const RT = { R1: 1e-5, R3: 1e-4 }; /* Tabela A.1 — Fator de localização CD */ const TAB_CD = [ { value: "0.25", label: "Rodeada por objetos mais altos" }, { value: "0.5", label: "Rodeada por objetos da mesma altura" }, { value: "1", label: "Estrutura isolada" }, { value: "2", label: "Isolada no topo de colina/morro" }, ]; /* Tabela A.2 — Fator de instalação da linha CI */ const TAB_CI = [ { value: "1", label: "Aérea" }, { value: "0.5", label: "Enterrada" }, { value: "0.01", label: "Enterrada em malha aterramento" }, ]; /* Tabela A.3 — Fator tipo de linha CT */ const TAB_CT = [ { value: "1", label: "Energia BT ou sinal" }, { value: "0.2", label: "Energia AT (com trafo AT/BT)" }, ]; /* Tabela A.4 — Fator ambiental CE */ const TAB_CE = [ { value: "1", label: "Rural" }, { value: "0.5", label: "Suburbano" }, { value: "0.1", label: "Urbano" }, { value: "0.01", label: "Urbano c/ struct. > 20m" }, ]; /* Tabela B.1 — PTA (medidas contra tensão toque/passo) */ const TAB_PTA = [ { value: "1", label: "Nenhuma medida" }, { value: "0.1", label: "Avisos visíveis" }, { value: "0.01", label: "Isolação elétrica (toque) ou malha equip. solo (passo)" }, { value: "0.001",label: "Estrutura metálica / concreto armado c/ descida natural" }, ]; /* Tabela B.2 — PB: prob. danos físicos por NP */ const TAB_PB = [ { value: "1", label: "Sem SPDA" }, { value: "0.2", label: "SPDA NP IV" }, { value: "0.1", label: "SPDA NP III" }, { value: "0.05", label: "SPDA NP II" }, { value: "0.02", label: "SPDA NP I" }, { value: "0.01", label: "SPDA NP I + descida natural concreto" }, { value: "0.001", label: "Cobertura metálica natural + descida natural" }, ]; /* Tabela B.3 — PSPD */ const TAB_PSPD = [ { value: "1", label: "Sem sistema coordenado de DPS" }, { value: "0.05", label: "DPS NP III-IV" }, { value: "0.02", label: "DPS NP II" }, { value: "0.01", label: "DPS NP I" }, ]; /* Tabela B.4 — CLD (fator blindagem/aterramento da linha) */ const TAB_CLD = [ { value: "1", label: "Linha aérea ou subterr. sem blindagem" }, { value: "0.5", label: "Linha com neutro multiaterrado" }, { value: "0.3", label: "Subterr. blindada, blindagem não equip." }, { value: "0.1", label: "Aérea blindada, blindagem não equip." }, { value: "0", label: "Blindagem equip. ao mesmo barramento" }, ]; /* Tabela C.2 — Valores típicos LT, LF, LO */ const TAB_LOSSES = { "residencial": { LT: 1e-2, LF: 1e-2, LO: 1e-3, label: "Residencial / Outros" }, "industrial": { LT: 1e-2, LF: 2e-2, LO: 1e-3, label: "Industrial / Comercial" }, "publico": { LT: 1e-2, LF: 5e-2, LO: 1e-3, label: "Público (igreja, museu, entret.)" }, "hospital": { LT: 1e-2, LF: 1e-1, LO: 1e-2, label: "Hospital / Hotel / Escola / Cívico" }, "hospital_uti": { LT: 1e-2, LF: 1e-1, LO: 1e-2, label: "Hospital (UTI / Bloco cirúrgico)" }, "explosao": { LT: 1e-2, LF: 1e-1, LO: 1e-1, label: "Risco de explosão" }, }; /* Tabela C.3 — Fator rt (tipo de solo/piso) */ const TAB_RT_SOLO = [ { value: "0.01", label: "Terra / Concreto" }, { value: "0.001", label: "Mármore / Cerâmica" }, { value: "0.0001", label: "Brita / Tapete / Carpete" }, { value: "0.00001", label: "Asfalto / Linóleo / Madeira" }, ]; /* Tabela C.4 — Fator rp (combate incêndio) */ const TAB_RP = [ { value: "1", label: "Nenhuma providência" }, { value: "0.5", label: "Extintores / alarme manual / compartimentos" }, { value: "0.2", label: "Instalações automáticas de supressão ou alarme" }, ]; /* Tabela C.5 — Fator rf (risco incêndio/explosão) */ const TAB_RF = [ { value: "0", label: "Sem incêndio / sem explosão" }, { value: "0.001",label: "Risco baixo de incêndio (< 400 MJ/m²)" }, { value: "0.01", label: "Risco normal de incêndio (400–800 MJ/m²)" }, { value: "0.1", label: "Risco alto de incêndio (> 800 MJ/m²) / explosão Zonas 1,21" }, { value: "1", label: "Explosão — Zonas 0, 20 e explosivos sólidos" }, ]; /* Tabela C.6 — Fator hz (perigo especial) */ const TAB_HZ = [ { value: "1", label: "Sem perigo especial" }, { value: "2", label: "Baixo pânico (≤ 2 andares, ≤ 100 pessoas)" }, { value: "5", label: "Pânico médio (100–1000 pessoas) / Dif. evacuação" }, { value: "10", label: "Alto pânico (> 1000 pessoas)" }, ]; /* Tabela C.7 — Fator rs (tipo estrutura) */ const TAB_RS = [ { value: "2", label: "Simples (madeira / alvenaria)" }, { value: "1", label: "Robusta (metálica / concreto armado)" }, ]; /* ─── NBR 5419-3: Parâmetros SPDA Externo por NP ───────────── Fonte: ABNT NBR 5419-3:2026 (Tabelas 1 e 2) r = raio esfera rolante (m) mesh = módulo malha subsistema captação (m) angle_10m = ângulo proteção para h=10m (graus) — franklin angle_20m = ângulo para h=20m (graus) angle_30m = ângulo para h=30m (graus) descidas_max = dist. máx. entre descidas (m) aterr_tipo = tipo recomendado eletrodo aterramento */ const SPDA_EXT = { "I": { r: 20, mesh: 5, angle_10: 75, angle_20: 70, angle_30: 65, descidas_max: 10, label: "Nível I" }, "II": { r: 30, mesh: 10, angle_10: 70, angle_20: 60, angle_30: 55, descidas_max: 10, label: "Nível II" }, "III": { r: 45, mesh: 15, angle_10: 60, angle_20: 50, angle_30: 45, descidas_max: 15, label: "Nível III" }, "IV": { r: 60, mesh: 20, angle_10: 50, angle_20: 45, angle_30: 43, descidas_max: 20, label: "Nível IV" }, }; /* ─── Seções mínimas condutores SPDA Externo ────────────────── */ const SECAO_MIN_CAPTACAO = { "I": { Cu: 50, Al: 70, Fe: 50, label: "Cap." }, "II": { Cu: 50, Al: 70, Fe: 50, label: "Cap." }, "III": { Cu: 50, Al: 70, Fe: 50, label: "Cap." }, "IV": { Cu: 50, Al: 70, Fe: 50, label: "Cap." }, }; const SECAO_MIN_DESCIDA = { "I": { Cu: 50, Al: 70, Fe: 50 }, "II": { Cu: 50, Al: 70, Fe: 50 }, "III": { Cu: 25, Al: 35, Fe: 50 }, "IV": { Cu: 16, Al: 25, Fe: 50 }, }; const SECAO_MIN_ATERR = { "I": { Cu: 50, Al: 70, Fe: 80 }, "II": { Cu: 50, Al: 70, Fe: 80 }, "III": { Cu: 16, Al: 25, Fe: 50 }, "IV": { Cu: 16, Al: 25, Fe: 50 }, }; /* ─── SPDA Interno / DPS ─────────────────────────────────────── */ /* Correntes Iimp mínimas por NP (kA) — classe I (10/350µs) Fonte: NBR 5419-1:2026, Anexo B e NBR 5419-4:2026, Anexo C/D 50% vai pro aterramento, 50% retorna pelas linhas Sistema trifásico: Iimp = 50% × Imax / 4 condutores = 12.5% × Imax */ const DPS_DATA = { "I": { Imax: 200, Iimp_classe1: 25, In_classe2: 20, Up_max: 2.5, label: "NP I" }, "II": { Imax: 150, Iimp_classe1: 18.75, In_classe2: 15, Up_max: 2.5, label: "NP II" }, "III": { Imax: 100, Iimp_classe1: 12.5, In_classe2: 10, Up_max: 2.5, label: "NP III/IV" }, "IV": { Imax: 100, Iimp_classe1: 12.5, In_classe2: 10, Up_max: 2.5, label: "NP III/IV" }, }; /* ─── Mapa NP → Classe visual ───────────────────────────────── */ const NP_LABEL = { "I": "Classe I", "II": "Classe II", "III": "Classe III", "IV": "Classe IV" }; const NP_COLOR = { "I": "danger", "II": "warn", "III": "warn", "IV": "ok" }; /* ═══════════════════════════════════════════════════════════════ TABELAS DE PROJETO — DIMENSIONAMENTO SPDA ════════════════════════════════════════════════════════════════ */ /* Tabela B.2 → PB por NP (para iteração automática do nível) */ const PB_POR_NP = { "IV": 0.2, "III": 0.1, "II": 0.05, "I": 0.02 }; /* Tabela B.3 → PSPD recomendado por NP */ const PSPD_POR_NP = { "IV": 0.05, "III": 0.05, "II": 0.02, "I": 0.01 }; /* Tabela 7 NBR 5419-3 — Coeficiente ki para distância de segurança s */ const KI_POR_NP = { "I": 0.08, "II": 0.06, "III": 0.04, "IV": 0.04 }; /* Coeficiente km — material da separação (NBR 5419-3 Tab. 6) */ const TAB_KM = [ { value: "1", label: "Ar" }, { value: "0.5", label: "Concreto / alvenaria" }, ]; /* Tipo de cobertura (define captação preferencial) */ const TAB_COBERTURA = [ { value: "plana", label: "Plana (malha)" }, { value: "inclinada", label: "Inclinada (cumeeira+beiral)" }, { value: "metalica", label: "Metálica (natural)" }, ]; /* Tipo de eletrodo de aterramento (override do usuário) */ const TAB_TIPO_ATERR = [ { value: "A", label: "Tipo A — hastes/radiais" }, { value: "B", label: "Tipo B — anel/malha" }, ]; /* Categoria de instalação (Uw) — IEC 60364-4-44 */ const TAB_UW = [ { value: "1.5", label: "Cat. I (1,5 kV) — eletrônico" }, { value: "2.5", label: "Cat. II (2,5 kV) — eletrodomést." }, { value: "4.0", label: "Cat. III (4,0 kV) — QGBT" }, { value: "6.0", label: "Cat. IV (6,0 kV) — entrada" }, ]; /* Comprimento mínimo l1 da haste (Tipo A) — Fig. 3 NBR 5419-3:2026 Interpolação linear sobre a curva. ρ em Ω·m → l1 em m. */ function calcL1Haste(NP, rho) { if (rho <= 500) return 5; if (NP === "III" || NP === "IV") return 5; if (NP === "II") { if (rho <= 1500) return 5 + (rho - 500) * 5 / 1000; if (rho <= 2500) return 10 + (rho - 1500) * 10 / 1000; return 20 + (rho - 2500) * 10 / 500; } // NP I if (rho <= 1000) return 5 + (rho - 500) * 5 / 500; if (rho <= 2000) return 10 + (rho - 1000) * 20 / 1000; return 30 + (rho - 2000) * 40 / 1000; } /* Raio médio re do eletrodo Tipo B — Fig. 3 NBR 5419-3:2026 */ function calcReAnel(NP, rho) { if (rho <= 500) return 5; if (NP === "III" || NP === "IV") return 5; if (NP === "II") { if (rho <= 1000) return 5 + (rho - 500) * 3 / 500; if (rho <= 2000) return 8 + (rho - 1000) * 7 / 1000; return 15 + (rho - 2000) * 9 / 1000; } // NP I if (rho <= 1000) return 5 + (rho - 500) * 7 / 500; if (rho <= 2000) return 12 + (rho - 1000) * 21 / 1000; return 33 + (rho - 2000) * 47 / 1000; } /* ═══════════════════════════════════════════════════════════════ MOTOR DE CÁLCULO CENTRAL — tudo via useMemo ════════════════════════════════════════════════════════════════ */ function calcularSPDA(inp) { /* ──── 1. Geometria ────────────────────────────────────────── */ const L = parseFloat(inp.L) || 0; const W = parseFloat(inp.W) || 0; const H = parseFloat(inp.H) || 0; if (L <= 0 || W <= 0 || H <= 0) return null; /* ──── 2. Áreas de exposição (Anexo A NBR 5419-2:2026) ────── */ const H3 = 3 * H; const AD = L * W + 2 * H3 * (L + W) + Math.PI * H3 * H3; const AM = 2 * 500 * (L + W) + Math.PI * 500 * 500; const LL = parseFloat(inp.LL) || 1000; const AL = 40 * LL; const AI = 4000 * LL; /* ──── 3. Eventos perigosos N (Eqs. A.3–A.10) ─────────────── */ const NG = parseFloat(inp.NG) || 0; const CD = parseFloat(inp.CD) || 1; const CI = parseFloat(inp.CI) || 1; const CT = parseFloat(inp.CT) || 1; const CE = parseFloat(inp.CE) || 1; const ND = NG * AD * CD * 1e-6; const NM = NG * AM * 1e-6; const NL = NG * AL * CI * CT * CE * 1e-6; const NI = NG * AI * CI * CT * CE * 1e-6; /* ──── 4. Inputs de probabilidade / perdas ─────────────────── */ const PTA = parseFloat(inp.PTA) || 1; const PB_user = parseFloat(inp.PB) || 1; const PSPD_user = parseFloat(inp.PSPD) || 1; const CLD = parseFloat(inp.CLD) || 1; const tipoEst = inp.tipoEst || "residencial"; const losses = TAB_LOSSES[tipoEst] || TAB_LOSSES["residencial"]; const rt = parseFloat(inp.rt) || 0.01; const rp = parseFloat(inp.rp) || 1; const rf = parseFloat(inp.rf) || 0.01; const hz = parseFloat(inp.hz) || 1; const rs = parseFloat(inp.rs) || 1; const nz_nt = parseFloat(inp.nz_nt) || 1; const tz_h = parseFloat(inp.tz_h) || 8760; const f_occ = nz_nt * (tz_h / 8760); const LA = rt * losses.LT * f_occ * rs; const LB = rp * rf * hz * losses.LF * f_occ * rs; const LC = losses.LO * f_occ * rs; const LU = rt * losses.LT * f_occ * rs; const LV = rp * rf * hz * losses.LF * f_occ * rs; const LW = losses.LO * f_occ * rs; const LM = losses.LO * f_occ * rs; const LZ = losses.LO * f_occ * rs; /* ──── 5. Função para calcular R1/R3 dado PB e PSPD ─────────── */ const calcRisks = (PB, PSPD) => { const PA = PTA * PB; const PC = PSPD * CLD; const PM = PSPD; const PU = PTA; const PV = PB; const PW = PSPD * CLD; const PZ = PSPD; const RA = ND * PA * LA; const RB = ND * PB * LB; const RC = ND * PC * LC; const RM = NM * PM * LM; const RU = NL * PU * LU; const RV = NL * PV * LV; const RW = NL * PW * LW; const RZ = NI * PZ * LZ; const R1 = RA + RB + RC + RM + RU + RV + RW + RZ; const R3 = RB + RV; return { PA, PB, PC, PM, PU, PV, PW, PZ, RA, RB, RC, RM, RU, RV, RW, RZ, R1, R3 }; }; /* ──── 6. Risco com proteção atual informada pelo usuário ──── */ const atual = calcRisks(PB_user, PSPD_user); const needsSpda = atual.R1 > RT.R1 || atual.R3 > RT.R3; /* ──── 7. ITERAÇÃO DO NP (NBR 5419-2 §5.5) ────────────────── Tenta NP IV → III → II → I até R1 ≤ RT1 e R3 ≤ RT3. */ let NP = null, recom = null; if (needsSpda) { for (const np of ["IV", "III", "II", "I"]) { const tentativa = calcRisks(PB_POR_NP[np], PSPD_POR_NP[np]); if (tentativa.R1 <= RT.R1 && tentativa.R3 <= RT.R3) { NP = np; recom = tentativa; break; } } if (!NP) { // Mesmo NP I + medidas máximas não basta NP = "I"; recom = calcRisks(0.001, 0.01); // SPDA NP I + cobertura natural + DPS NP I } } /* ──── 8. SPDA EXTERNO — Parâmetros NBR 5419-3:2026 ────────── */ const ext = NP ? SPDA_EXT[NP] : null; let perimetro = 0, nDescidas = 0, espDescidas = 0; if (ext) { perimetro = 2 * (L + W); espDescidas = ext.descidas_max; /* NBR 5419-3 §5.3.5: mínimo 2 descidas em qualquer NP */ nDescidas = Math.max(2, Math.ceil(perimetro / espDescidas)); } /* ──── 9. DIMENSIONAMENTO DA CAPTAÇÃO ─────────────────────── Malha sobre toda a cobertura (método mais comum): n_linhas_X = ceil(W/malha)+1, n_linhas_Y = ceil(L/malha)+1 L_malha = n_linhas_X × L + n_linhas_Y × W */ const cobertura = inp.cobertura || "plana"; const malhaSize = ext ? ext.mesh : 0; let nLinX = 0, nLinY = 0, LMalha = 0; if (ext) { nLinX = Math.ceil(W / malhaSize) + 1; nLinY = Math.ceil(L / malhaSize) + 1; LMalha = nLinX * L + nLinY * W; } /* Comprimento de descidas (H + 1m de conexão ao aterramento) */ const LDesc = ext ? nDescidas * (H + 1) : 0; const LCaboTotal = LMalha + LDesc; /* ──── 10. ATERRAMENTO ────────────────────────────────────── */ const rho = parseFloat(inp.rho_solo) || 300; /* NP I e II → Tipo B obrigatório; NP III/IV pode ser A ou B */ const tipoAterrUser = inp.tipoAterr || "B"; const tipoAterr = (NP === "I" || NP === "II") ? "B" : tipoAterrUser; const areaTopo = L * W; const reCalc = Math.sqrt(areaTopo / Math.PI); // raio equivalente da estrutura let l1_haste = 0, reReq = 0, anelL = 0, hastesAdicionais = 0; if (ext) { if (tipoAterr === "A") { l1_haste = calcL1Haste(NP, rho); } else { reReq = calcReAnel(NP, rho); anelL = perimetro + 8; // anel 1m afastado da estrutura if (reReq > reCalc) { const extra = reReq - reCalc; hastesAdicionais = Math.max(2, Math.ceil(extra / 5)); } } } /* ──── 11. DISTÂNCIA DE SEGURANÇA s (Eq. NBR 5419-3 §6.3) ─── s = ki × kc × L / km kc simplificado para malha + anel: kc ≈ 1/n + 0,1 */ const km = parseFloat(inp.km) || 1; const ki = NP ? KI_POR_NP[NP] : 0; const kc = ext ? Math.max(0.1, 1 / nDescidas + 0.1) : 0; const s = ext ? (ki * kc * H) / km : 0; /* ──── 12. SPDA INTERNO / DPS ─────────────────────────────── */ const dps = NP ? DPS_DATA[NP] : null; const Uw = parseFloat(inp.Uw) || 2.5; const Lcabo = parseFloat(inp.Lcabo) || 5; /* Tensão efetiva no equipamento considerando indução nos cabos: Lcabo ≤ 10m: Up_ef ≈ Up × (1 + Lcabo/20) Lcabo > 10m: oscilação dobra → Up_ef ≈ 2 × Up */ const Up_dps = dps ? dps.Up_max : 2.5; const Up_ef = Lcabo > 10 ? Up_dps * 2 : Up_dps * (1 + Lcabo / 20); const dpsOk = Up_ef <= Uw; /* ZPR */ const zpr = { ZPR0: "Exterior (sem proteção)", ZPR1: "Interior — SPDA externo como fronteira", ZPR2: "Sala/ambiente interno — blindagem (malha ≤ 5m)", ZPR3: "Equipamento / rack — gabinete blindado", }; return { /* Áreas e eventos */ AD, AM, AL, AI, ND, NM, NL, NI, LA, LB, LC, LU, LV, LW, LM, LZ, /* Análise de risco — estado atual e recomendado */ atual, recom, needsSpda, NP, PA: atual.PA, PB: PB_user, PC: atual.PC, PM: atual.PM, PU: atual.PU, PV: atual.PV, PW: atual.PW, PZ: atual.PZ, RA: atual.RA, RB: atual.RB, RC: atual.RC, RM: atual.RM, RU: atual.RU, RV: atual.RV, RW: atual.RW, RZ: atual.RZ, R1: atual.R1, R3: atual.R3, /* SPDA Externo — parâmetros + projeto */ ext, perimetro, nDescidas, espDescidas, rEsfera: ext ? ext.r : null, malha: malhaSize, ang10: ext ? ext.angle_10 : null, ang20: ext ? ext.angle_20 : null, ang30: ext ? ext.angle_30 : null, cobertura, nLinX, nLinY, LMalha, LDesc, LCaboTotal, /* Aterramento */ tipoAterr, rho, l1_haste, reCalc, reReq, anelL, hastesAdicionais, /* Distância de segurança */ s, ki, kc, km, /* SPDA Interno / DPS */ dps, zpr, Uw, Lcabo, Up_dps, Up_ef, dpsOk, /* Inputs espelhados para memória de cálculo */ L, W, H, NG, CD, LL, H3, }; } /* ═══════════════════════════════════════════════════════════════ COMPONENTE PRINCIPAL ════════════════════════════════════════════════════════════════ */ function SPDA() { const [tab, setTab] = useState("risco"); /* ─── Aba 1: Dados da Estrutura ──────────────────────────── */ const [L, setL] = usePersist("vl_spda_L", "30"); const [W, setW] = usePersist("vl_spda_W", "20"); const [H, setH] = usePersist("vl_spda_H", "10"); const [NG, setNG] = usePersist("vl_spda_NG", "5"); const [CD, setCD] = usePersist("vl_spda_CD", "1"); const [LL, setLL] = usePersist("vl_spda_LL", "500"); const [CI, setCI] = usePersist("vl_spda_CI", "1"); const [CT, setCT] = usePersist("vl_spda_CT", "1"); const [CE, setCE] = usePersist("vl_spda_CE", "0.5"); /* ─── Aba 1: Probabilidades ──────────────────────────────── */ const [PTA, setPTA] = usePersist("vl_spda_PTA", "1"); const [PB, setPB] = usePersist("vl_spda_PB", "1"); const [PSPD, setPSPD] = usePersist("vl_spda_PSPD", "1"); const [CLD, setCLD] = usePersist("vl_spda_CLD", "1"); /* ─── Aba 1: Perdas ─────────────────────────────────────── */ const [tipoEst, setTipoEst] = usePersist("vl_spda_tipo", "residencial"); const [rt, setRt] = usePersist("vl_spda_rt", "0.01"); const [rp, setRp] = usePersist("vl_spda_rp", "1"); const [rf, setRf] = usePersist("vl_spda_rf", "0.01"); const [hz, setHz] = usePersist("vl_spda_hz", "1"); const [rs, setRs] = usePersist("vl_spda_rs", "1"); const [nz_nt, setNzNt] = usePersist("vl_spda_nznt", "1"); const [tz_h, setTzH] = usePersist("vl_spda_tzh", "8760"); /* ─── Aba 2: Inputs de Projeto (SPDA Externo) ──────────── */ const [rho_solo, setRhoSolo] = usePersist("vl_spda_rho", "300"); const [cobertura, setCobertura] = usePersist("vl_spda_cobert", "plana"); const [tipoAterr, setTipoAterr] = usePersist("vl_spda_taterr", "B"); const [km, setKm] = usePersist("vl_spda_km", "1"); /* ─── Aba 3: Inputs de Projeto (SPDA Interno / DPS) ───── */ const [Uw, setUw] = usePersist("vl_spda_Uw", "2.5"); const [Lcabo, setLcabo] = usePersist("vl_spda_Lcabo", "5"); /* ─── Motor ─────────────────────────────────────────────── */ const inp = { L, W, H, NG, CD, LL, CI, CT, CE, PTA, PB, PSPD, CLD, tipoEst, rt, rp, rf, hz, rs, nz_nt, tz_h, rho_solo, cobertura, tipoAterr, km, Uw, Lcabo }; const calc = useMemo(() => calcularSPDA(inp), [ L, W, H, NG, CD, LL, CI, CT, CE, PTA, PB, PSPD, CLD, tipoEst, rt, rp, rf, hz, rs, nz_nt, tz_h, rho_solo, cobertura, tipoAterr, km, Uw, Lcabo ]); /* ─── Export hook ───────────────────────────────────────── */ useEffect(() => { window._VL_lastExport = () => calc ? ({ modulo: "spda-nbr5419-2026", norma: "ABNT NBR 5419:2026 (Partes 1–4)", geradoEm: new Date().toLocaleString("pt-BR"), entradas: { comprimento_m: L, largura_m: W, altura_m: H, densidade_ng: NG, fator_cd: CD, comprimento_linha_m: LL, tipo_estrutura: tipoEst, resistividade_solo: rho_solo, tipo_cobertura: cobertura, tipo_aterramento: tipoAterr, material_separacao_km: km, uw_equipamento_kV: Uw, distancia_dps_equip_m: Lcabo, }, resultado: { R1: calc.R1.toExponential(2), R3: calc.R3.toExponential(2), RT1: "1e-5", RT3: "1e-4", necessita_spda: calc.needsSpda, nivel_protecao: calc.NP || "—", R1_recomendado: calc.recom ? calc.recom.R1.toExponential(2) : "—", }, spda_externo: calc.ext ? { raio_esfera_m: calc.rEsfera, malha: `${calc.malha}×${calc.malha} m`, n_descidas: calc.nDescidas, esp_max_descidas_m: calc.espDescidas, L_malha_captacao_m: calc.LMalha.toFixed(1), L_descidas_m: calc.LDesc.toFixed(1), L_cabo_total_m: calc.LCaboTotal.toFixed(1), tipo_aterramento: calc.tipoAterr, l1_haste_m: calc.tipoAterr === "A" ? calc.l1_haste.toFixed(1) : "—", anel_perimetro_m: calc.tipoAterr === "B" ? calc.anelL.toFixed(1) : "—", re_requerido_m: calc.reReq ? calc.reReq.toFixed(1) : "—", hastes_adicionais: calc.hastesAdicionais, distancia_seguranca_s_m: calc.s.toFixed(3), } : null, spda_interno: calc.dps ? { iimp_kA: calc.dps.Iimp_classe1, in_classe2_kA: calc.dps.In_classe2, up_max_kV: calc.dps.Up_max, up_efetivo_kV: calc.Up_ef.toFixed(2), uw_equipamento_kV: calc.Uw, coordenacao_ok: calc.dpsOk, } : null, }) : null; return () => { window._VL_lastExport = null; }; }, [calc]); const fmt = (v, digits = 2) => { if (!isFinite(v) || v === 0) return "0,00"; if (Math.abs(v) < 1e-3) return v.toExponential(2); return v.toFixed(digits).replace(".", ","); }; const fmtExp = (v) => v.toExponential(2).replace("e-", "×10⁻").replace("e+", "×10⁺"); const tabList = [ { id: "risco", label: "① Análise de Risco", eyebrow: "PARTES 1 & 2" }, { id: "externo", label: "② SPDA Externo", eyebrow: "PARTE 3" }, { id: "interno", label: "③ SPDA Interno / DPS",eyebrow: "PARTE 4" }, ]; const npStatus = calc?.NP ? NP_COLOR[calc.NP] : "ok"; return (
{/* ── Tabs ────────────────────────────────────────────── */}
{tabList.map(t => ( ))}
{/* ══════════════════════════════════════════════════════ ABA 1 — ANÁLISE DE RISCO (NBR 5419-2) ══════════════════════════════════════════════════════ */} {tab === "risco" && (
{/* COLUNA ESQUERDA: Entradas */}
{/* Dimensões */}
GEOMETRIA DA ESTRUTURA · NBR 5419-2 ANEXO A

Dimensões

{/* Linha Elétrica */}
LINHA ELÉTRICA CONECTADA · FONTES S3 E S4

Parâmetros da linha

{/* Probabilidades */}
PROBABILIDADES DE DANOS · ANEXO B

Medidas de proteção existentes

{/* Perdas */}
FATORES DE PERDA · ANEXO C

Características da estrutura

({ value: k, label: v.label })) }/>
{/* COLUNA DIREITA: Resultados */}
{!calc && (
Preencha as dimensões e NG para calcular.
)} {calc && ( <> {/* Resultado principal */}
RESULTADO PRINCIPAL · R1 e R3

Riscos calculados

RT.R1 ? "danger" : "ok"} />
RT.R1 ? "danger" : "ok"}/>
RT.R3 ? "warn" : "ok"} />
RT.R3 ? "warn" : "ok"}/>
{calc.needsSpda ? SPDA NECESSÁRIO — R1 ou R3 acima do tolerável (NBR 5419-2, 5.4.4) : Sem necessidade de SPDA — Risco dentro do tolerável (NBR 5419-2, 5.4.3) } {calc.NP && (
NÍVEL DE PROTEÇÃO RECOMENDADO
NP {calc.NP}
{NP_LABEL[calc.NP]} · ABNT NBR 5419
)}
{/* Componentes de risco detalhados */}
COMPONENTES DE RISCO · TABELA 6

Decomposição de R1

0 ? "ok" : undefined}/> 0 ? "ok" : undefined}/> 0 ? "ok" : undefined}/> 0 ? "ok" : undefined}/>
0 ? "ok" : undefined}/> 0 ? "ok" : undefined}/> 0 ? "ok" : undefined}/> 0 ? "ok" : undefined}/>
{/* Número de eventos */}
EVENTOS PERIGOSOS / ANO · ANEXO A

ND / NM / NL / NI

{/* Memória de cálculo */}
MEMÓRIA DE CÁLCULO

Passo a passo

AD = L×W + 2×(3H)×(L+W) + π×(3H)² = {calc.L}×{calc.W} + 2×{fmt(calc.H3,1)}×{calc.L+calc.W} + π×{fmt(calc.H3,1)}² = {fmt(calc.AD,1)} m² ND = NG × AD × CD × 10⁻⁶ = {calc.NG} × {fmt(calc.AD,0)} × {calc.CD} × 10⁻⁶ = {calc.ND.toExponential(3)} NL = NG × AL × CI × CT × CE × 10⁻⁶ = {calc.NG} × {fmt(calc.AL,0)} × {calc.CI} × {calc.CT} × {calc.CE} × 10⁻⁶ = {calc.NL.toExponential(3)} RB = ND × PB × LB = {calc.ND.toExponential(2)} × {PB} × {fmt(calc.LB,5)} = {calc.RB.toExponential(2)} R1 = RA+RB+RC+RM+RU+RV+RW+RZ = {fmtExp(calc.R1)} {calc.R1 > RT.R1 ? "⚠ > RT1=10⁻⁵" : "✓ ≤ RT1=10⁻⁵"}
)}
)} {/* ══════════════════════════════════════════════════════ ABA 2 — SPDA EXTERNO (NBR 5419-3) ══════════════════════════════════════════════════════ */} {tab === "externo" && (
{/* COLUNA ESQUERDA: Inputs de projeto + Parâmetros NP */}
{!calc?.NP && (
Complete a Aba 1 — Análise de Risco para dimensionar o SPDA Externo.
)} {calc?.NP && ( <> {/* Inputs de projeto */}
DADOS DO LOCAL · PROJETO

Parâmetros de campo

{/* Parâmetros do NP */}
NÍVEL DE PROTEÇÃO · NBR 5419-3:2026

Parâmetros normativos NP {calc.NP}

NP {calc.NP}
Tabelas 1 e 2 — NBR 5419-3:2026
{/* Seções mínimas */}
SEÇÕES MÍNIMAS · TABELA 6 NBR 5419-3

Materiais dos condutores

{["Subsistema", "Cu (mm²)", "Al (mm²)", "Fe (mm²)"].map(h => ( ))} {[ { label: "Captação", s: SECAO_MIN_CAPTACAO[calc.NP] }, { label: "Descida", s: SECAO_MIN_DESCIDA[calc.NP] }, { label: "Aterramento", s: SECAO_MIN_ATERR[calc.NP] }, ].map(row => ( ))}
{h}
{row.label} {row.s.Cu} {row.s.Al} {row.s.Fe}
)}
{/* COLUNA DIREITA: Dimensionamento do projeto */} {calc?.NP && (
{/* Captação dimensionada */}
SUBSISTEMA DE CAPTAÇÃO · DIMENSIONADO

Malha sobre a cobertura

Malha {calc.malha}×{calc.malha} m sobre cobertura de {fmt(calc.L)}×{fmt(calc.W)} m → {calc.nLinX} × {fmt(calc.L)} m + {calc.nLinY} × {fmt(calc.W)} m = {fmt(calc.LMalha, 1)} m.
{/* Descidas dimensionadas */}
SUBSISTEMA DE DESCIDA · DIMENSIONADO

Condutores verticais

{calc.nDescidas} descidas distribuídas no perímetro (mín. 2 por NBR 5419-3 §5.3.5) · espaçamento máx. {calc.espDescidas} m · comprimento total {fmt(calc.LDesc, 1)} m (H+1m por descida).
{/* Aterramento dimensionado */}
SUBSISTEMA DE ATERRAMENTO · DIMENSIONADO

Eletrodo Tipo {calc.tipoAterr}

{calc.tipoAterr === "A" ? ( <>
Por descida: 2 hastes verticais de {fmt(calc.l1_haste, 1)} m ou 1 condutor radial de {fmt(calc.l1_haste * 2, 1)} m (Fig. 3 NBR 5419-3:2026). ) : ( <>
calc.reCalc ? "warn" : "ok"}/> 0 ? "warn" : "ok"}/>
0 ? "warn" : "ok"}> {calc.hastesAdicionais > 0 ? `Solo de alta resistividade (ρ=${calc.rho} Ω·m): re necessário (${fmt(calc.reReq,1)} m) > re da estrutura (${fmt(calc.reCalc,1)} m). Adicionar ${calc.hastesAdicionais} hastes radiais para complementar.` : `re da estrutura (${fmt(calc.reCalc,1)} m) ≥ re necessário (${fmt(calc.reReq,1)} m). Apenas o anel atende.`}

Anel a 0,5 m de profundidade, 1 m afastado da estrutura · seção mín. {SECAO_MIN_ATERR[calc.NP].Cu} mm² Cu ou {SECAO_MIN_ATERR[calc.NP].Fe} mm² Fe.

)}
{/* Distância de segurança s */}
DISTÂNCIA DE SEGURANÇA · NBR 5419-3 §6.3

Separação SPDA × partes internas

s = ki × kc × L / km = {calc.ki} × {fmt(calc.kc, 2)} × {calc.H} / {calc.km} = {fmt(calc.s, 3)} m. Partes metálicas internas devem estar a no mínimo essa distância das descidas, OU equipotencializadas.
{/* Lista de materiais */}
LISTA DE MATERIAIS (BoM)

Resumo do projeto

{["Item", "Qtd.", "Unid."].map(h => ( ))} {[ { item: `Cabo Cu nu ${SECAO_MIN_CAPTACAO[calc.NP].Cu} mm² — captação`, qtd: fmt(calc.LMalha, 1), un: "m" }, { item: `Cabo Cu nu ${SECAO_MIN_DESCIDA[calc.NP].Cu} mm² — descidas`, qtd: fmt(calc.LDesc, 1), un: "m" }, calc.tipoAterr === "A" ? { item: `Haste de aterramento Cu/Aço L ≥ ${fmt(calc.l1_haste,1)} m`, qtd: calc.nDescidas * 2, un: "un." } : { item: `Cabo Cu nu ${SECAO_MIN_ATERR[calc.NP].Cu} mm² — anel`, qtd: fmt(calc.anelL, 1), un: "m" }, calc.tipoAterr === "B" && calc.hastesAdicionais > 0 ? { item: "Haste radial complementar", qtd: calc.hastesAdicionais, un: "un." } : null, { item: "Conector de medição (TAP)", qtd: calc.nDescidas, un: "un." }, { item: "Caixa de inspeção", qtd: calc.nDescidas, un: "un." }, { item: "Suporte/isolador para cabo", qtd: Math.ceil(calc.LCaboTotal / 1.5), un: "un." }, ].filter(Boolean).map((r, i) => ( ))}
{h}
{r.item} {r.qtd} {r.un}
{/* Memória de cálculo */}
MEMÓRIA DE CÁLCULO

SPDA Externo

P = 2 × (L + W) = 2 × ({calc.L} + {calc.W}) = {fmt(calc.perimetro)} m n = max(2, ceil(P / d_max)) = max(2, ceil({fmt(calc.perimetro)}/{calc.espDescidas})) = {calc.nDescidas} L_malha = nx × L + ny × W = {calc.nLinX} × {fmt(calc.L)} + {calc.nLinY} × {fmt(calc.W)} = {fmt(calc.LMalha, 1)} m {calc.tipoAterr === "A" ? ( Fig. 3 NBR 5419-3 → l1 mín = {fmt(calc.l1_haste, 1)} m por haste ) : ( re necessário = {fmt(calc.reReq, 1)} m · re estrutura = {fmt(calc.reCalc, 1)} m )} s = ki × kc × L / km = {calc.ki} × {fmt(calc.kc, 2)} × {calc.H} / {calc.km} = {fmt(calc.s, 3)} m
)}
)} {/* ══════════════════════════════════════════════════════ ABA 3 — SPDA INTERNO / MPS / DPS (NBR 5419-4) ══════════════════════════════════════════════════════ */} {tab === "interno" && (
{!calc?.NP && (
Complete a Aba 1 para calcular as MPS e DPS.
)} {calc?.NP && ( <> {/* Inputs de projeto DPS */}
DADOS DO EQUIPAMENTO · PROJETO DPS

Parâmetros de instalação

{/* ZPR */}
ZONAS DE PROTEÇÃO CONTRA RAIOS · NBR 5419-4 SEC. 4.3

Conceito de ZPR

{Object.entries(calc.zpr).map(([key, desc]) => (
{key}
{desc}
))} Todas as linhas elétricas que cruzam fronteiras de ZPR devem ter DPS ou interface isolante instalada no ponto de cruzamento (NBR 5419-4, 5.5).
{/* Equipotencialização */}
EQUIPOTENCIALIZAÇÃO · NBR 5419-4 SEC. 5

Seções mínimas

{["Componente", "Cu (mm²)", "Al (mm²)", "Fe (mm²)"].map(h => ( ))} {[ { comp: "Barras de equipotencializ.", Cu: 50, Al: "—", Fe: 50 }, { comp: "Condut. barra → aterramento", Cu: 50, Al: "—", Fe: 70 }, { comp: "Condut. entre barras (corrente signif.)", Cu: 16, Al: 25, Fe: 50 }, { comp: "Partes metálicas internas → barra", Cu: 6, Al: 10, Fe: 16 }, { comp: "Interlig. DPS classe I", Cu: 16, Al: "—", Fe: "—" }, { comp: "Interlig. DPS classe II", Cu: 6, Al: "—", Fe: "—" }, { comp: "Interlig. DPS classe III", Cu: 2.5, Al: "—", Fe: "—" }, ].map(r => ( ))}
{h}
{r.comp} {r.Cu} {r.Al} {r.Fe}

Fonte: NBR 5419-4:2026, Tabela 1. Ligação equipotencial em rede: malha típica ≤ 5 m × 5 m (Seção 5.3).

)}
{/* Coluna direita: DPS */} {calc?.NP && (
{/* DPS — Especificação por NP */}
SISTEMA COORDENADO DE DPS · NBR 5419-4 ANEXO C

Dispositivos de Proteção contra Surtos

{calc.NP === "I" ? "NP I: DPS Classe I obrigatório (10/350µs · Iimp ≥ 25 kA) na entrada do quadro elétrico (fronteira ZPR 0→1)." : calc.NP === "II" ? "NP II: DPS Classe I na entrada (Iimp ≥ 18,75 kA) + Classe II nos quadros secundários (fronteira ZPR 1→2)." : "NP III/IV: DPS Classe I/II na entrada (Iimp ≥ 12,5 kA). DPS Classe II nos circuitos terminais."}
{/* Verificação de coordenação */}
VERIFICAÇÃO DE COORDENAÇÃO · NBR 5419-4 §C.2.1

Up efetivo vs. Uw do equipamento

10 ? "warn" : "ok"}/>
{calc.dpsOk ? `Coordenação OK — Up_ef (${fmt(calc.Up_ef,2)} kV) ≤ Uw (${calc.Uw} kV). DPS no quadro protege o equipamento.` : `INSUFICIENTE — Up_ef (${fmt(calc.Up_ef,2)} kV) > Uw (${calc.Uw} kV). ${calc.Lcabo > 10 ? "Instale DPS adicional (Classe III) a menos de 10 m do equipamento." : "Use DPS com menor Up ou eleve a categoria do equipamento."}`}
{/* Plano de instalação de DPS */}
PLANO DE INSTALAÇÃO DE DPS

Localização e especificação

{["Local", "Classe", "Iimp / In", "Up máx."].map(h => ( ))} {[ { local: "Entrada (QGBT) — ZPR 0→1", classe: "Classe I (B)", corr: `Iimp ≥ ${calc.dps?.Iimp_classe1.toFixed(2)} kA (10/350µs)`, up: "≤ 4,0 kV", }, { local: "Quadros secundários — ZPR 1→2", classe: "Classe II (C)", corr: `In ≥ ${calc.dps?.In_classe2} kA (8/20µs)`, up: "≤ 2,5 kV", }, { local: "Próximo equip. sensível — ZPR 2→3", classe: "Classe III (D)", corr: "In ≥ 5 kA (8/20µs)", up: "≤ 1,5 kV", }, ].map(r => ( ))}
{h}
{r.local} {r.classe} {r.corr} {r.up}

Cada cruzamento de ZPR exige DPS ou interface isolante (NBR 5419-4 §5.5). Cabo Cu mín. 16 mm² (Cl. I), 6 mm² (Cl. II), 2,5 mm² (Cl. III) — Tabela 1.

MEMÓRIA — DPS
50% no aterramento · 50% pelas linhas → {calc.dps?.Imax} × 0,5 / 4 cond. = {calc.dps?.Iimp_classe1.toFixed(2)} kA por DPS {calc.Lcabo > 10 ? `Lcabo > 10m → oscilação dobra: Up_ef = 2 × ${calc.Up_dps} = ` : `Lcabo ≤ 10m → Up_ef = Up × (1 + Lcabo/20) = ${calc.Up_dps} × (1 + ${calc.Lcabo}/20) = `} {fmt(calc.Up_ef, 2)} kV Up_ef ≤ Uw → {fmt(calc.Up_ef, 2)} ≤ {calc.Uw} → {calc.dpsOk ? "ATENDE" : "NÃO ATENDE"}
{/* Blindagem */}
BLINDAGEM MAGNÉTICA E ROTEAMENTO · SEC. 6

Recomendações MPS

{[ { titulo: "Malha de equipotencialização interna", desc: "Largura típica ≤ 5 m × 5 m. Interligar estruturas metálicas, trilhos de elevador, tubulações, bandejas de cabos, armações de janelas (NBR 5419-4, 5.3)." }, { titulo: "Roteamento de linhas internas", desc: "Minimizar área dos laços de indução. Instalar cabos de energia e sinal próximos e paralelos. KS3 = 0,01 para cabos no mesmo eletroduto (Tabela B.5 da NBR 5419-2)." }, { titulo: "Blindagem de cabos externos", desc: "Blindagem interligada ao mesmo barramento de equipotencialização do equipamento → CLD = 0 (linha completamente blindada). Reduz PC significativamente." }, { titulo: "Interfaces isolantes", desc: "Usar para bloquear surtos conduzidos quando DPS não for suficiente. Fibra óptica (sem metálico) = zero corrente conduzida entre ZPRs (NBR 5419-4, Sec. 8)." }, ].map(item => (
▸ {item.titulo}
{item.desc}
))}
{/* Inspeção */}
INSPEÇÃO E MANUTENÇÃO · NBR 5419-4 SEC. 9

Periodicidade recomendada

Inspecionar imediatamente após suspeita de descarga direta na estrutura (contador de raios ou danos visíveis) — NBR 5419-4, 9.2.2-e).
)}
)} {/* ── Referência normativa ─────────────────────────────── */}
REFERÊNCIA NORMATIVA

ABNT NBR 5419:2026 — Proteção contra descargas atmosféricas

2ª edição · 10.03.2026
PARTETÍTULOESCOPO PRINCIPALMÓDULO
{[ { parte: "Parte 1", titulo: "Princípios gerais", escopo: "Parâmetros corrente descarga, esfera rolante, gaiola Faraday", modulo: "Base" }, { parte: "Parte 2", titulo: "Análise de risco", escopo: "Cálculo de R1, R3 · Determinação do NP · Fórmulas ND, NL, probabilidades PX", modulo: "Aba 1" }, { parte: "Parte 3", titulo: "Danos físicos e perigos à vida", escopo: "SPDA externo: captação, descida, aterramento · Seções mínimas · Distância de segurança", modulo: "Aba 2" }, { parte: "Parte 4", titulo: "Sistemas elétricos e eletrônicos internos", escopo: "ZPR · Equipotencialização em rede · Sistema coordenado DPS · Seleção Up/Iimp", modulo: "Aba 3" }, ].map(r => (
{r.parte} {r.titulo} {r.escopo} {r.modulo}
))}
); } window.VL_SPDA = SPDA;