/* global React */ /* =========================================================== VOLTLAB · QUADRO DE MOTORES Lista de motores de uma instalação: corrente nominal, fator de partida, dimensionamento de cabo e corrente total. Tabelas extraídas da planilha CÁLCULOS.xlsx: · D - MOTORES → fator de partida (tipo × método) · D - CABOS → ampacidade (seção × isolação × B1/B2) Integra-se ao barramento de projeto (Puxar / Enviar). =========================================================== */ const { useState: useStMot, useMemo: useMemoMot } = React; const useMotPersist = (key, initial) => window.useLocalStorage ? window.useLocalStorage(key, initial) : useStMot(initial); /* ── D - MOTORES · fator de partida (tipo de carga × método) ── */ const MOT_FATOR_PARTIDA = { Normal: { DIN: 1.00, SOFT: 1.00, INVERSOR: 1.00, AUTOTRAFO: 10.0 }, "Bomba C/Carga": { DIN: 1.50, SOFT: 1.25, INVERSOR: 1.00, AUTOTRAFO: 3.0 }, Esteira: { DIN: 1.20, SOFT: 1.00, INVERSOR: 1.00, AUTOTRAFO: 4.0 }, }; const MOT_TIPOS = ["Normal", "Bomba C/Carga", "Esteira"]; const MOT_METODOS = [ { v: "DIN", label: "Direta (DIN)" }, { v: "SOFT", label: "Soft-Starter" }, { v: "INVERSOR", label: "Inversor" }, { v: "AUTOTRAFO", label: "Autotrafo" }, ]; /* ── D - CABOS · ampacidade (mm² × isolação × instalação B1/B2) ── */ const MOT_CABOS = [ { sec: 1.0, iso: "PVC", B1: 12, B2: 12 }, { sec: 1.5, iso: "PVC", B1: 17, B2: 15 }, { sec: 2.5, iso: "PVC", B1: 21, B2: 20 }, { sec: 4.0, iso: "PVC", B1: 28, B2: 27 }, { sec: 6.0, iso: "PVC", B1: 36, B2: 34 }, { sec: 10, iso: "PVC", B1: 50, B2: 46 }, { sec: 10, iso: "XLPE", B1: 66, B2: 61 }, { sec: 16, iso: "PVC", B1: 68, B2: 62 }, { sec: 16, iso: "XLPE", B1: 88, B2: 82 }, { sec: 25, iso: "XLPE", B1: 117, B2: 105 }, { sec: 35, iso: "XLPE", B1: 144, B2: 128 }, { sec: 50, iso: "XLPE", B1: 175, B2: 154 }, { sec: 70, iso: "XLPE", B1: 222, B2: 194 }, { sec: 95, iso: "XLPE", B1: 269, B2: 233 }, { sec: 120, iso: "XLPE", B1: 312, B2: 268 }, { sec: 150, iso: "XLPE", B1: 358, B2: 307 }, { sec: 185, iso: "XLPE", B1: 409, B2: 350 }, { sec: 240, iso: "XLPE", B1: 483, B2: 413 }, { sec: 300, iso: "XLPE", B1: 556, B2: 474 }, ]; /* corrente nominal — fator A/CV por faixa (calibrado da planilha) */ function correnteNominal(cv, V, fase) { const P = (parseFloat(cv) || 0) * 735.49875; // CV → W if (P <= 0 || !V) return 0; // rendimento × fator de potência típico por faixa (W22 IR3) let cosfi_rend; if (cv <= 3) cosfi_rend = 0.473; else if (cv <= 7.5) cosfi_rend = 0.52; else if (cv <= 15) cosfi_rend = 0.55; else if (cv <= 50) cosfi_rend = 0.567; else cosfi_rend = 0.567; // divisor conforme o nº de fases const div = fase === "monofasico" ? V : fase === "bifasico" ? (2 * V) : (Math.sqrt(3) * V); // trifásico (padrão) return P / (div * cosfi_rend); } const MOT_FASES = [ { v: "trifasico", label: "Trifásico", abbr: "3F" }, { v: "bifasico", label: "Bifásico", abbr: "2F" }, { v: "monofasico", label: "Monofásico", abbr: "1F" }, ]; const faseAbbr = (f) => MOT_FASES.find(x => x.v === f)?.abbr || "3F"; /* dimensiona cabo a partir da corrente de projeto */ function dimensionarCabo(corrente, metodoInst, isolacaoMin) { // filtra por isolação aceita: se XLPE permitido, usa qualquer; se só PVC, restringe const candidatos = MOT_CABOS.filter(c => isolacaoMin === "PVC" ? true : true); for (const c of candidatos) { const amp = metodoInst === "B1" ? c.B1 : c.B2; if (amp >= corrente) return c; } return MOT_CABOS[MOT_CABOS.length - 1]; } /* ── ícones ── */ const MtIc = ({ n, s = 16 }) => { const p = { width: s, height: s, viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: 1.5, strokeLinecap: "round", strokeLinejoin: "round" }; const d = { motor: <>, bolt: , cable: <>, plus: <>, trash: <>, dl: <>, reset: <>, check: , info: <>, sigma: , gauge: <>, }; return {d[n] || null}; }; /* ── dropdown padrão (.vl-dd) ── */ const MtDropdown = ({ value, onChange, options }) => { const [open, setOpen] = useStMot(false); const ref = React.useRef(null); React.useEffect(() => { if (!open) return; const h = (e) => { if (ref.current && !ref.current.contains(e.target)) setOpen(false); }; document.addEventListener("mousedown", h); return () => document.removeEventListener("mousedown", h); }, [open]); const cur = options.find(o => o.value === value) || options[0]; return (
{open && (
{options.map(o => (
{ onChange(o.value); setOpen(false); }}>{o.label}
))}
)}
); }; const motFmt = (n, d = 1) => isFinite(n) ? n.toLocaleString("pt-BR", { minimumFractionDigits: d, maximumFractionDigits: d }) : "—"; /* motores de exemplo (da planilha) */ const MOT_SAMPLE = [ { id: "m1", nome: "Bomba 01", cv: 100, V: 380, fase: "trifasico", tipo: "Bomba C/Carga", metodo: "SOFT", inst: "B2", iso: "XLPE" }, { id: "m2", nome: "Bomba 02", cv: 100, V: 380, fase: "trifasico", tipo: "Bomba C/Carga", metodo: "SOFT", inst: "B2", iso: "XLPE" }, { id: "m3", nome: "Compressor", cv: 30, V: 380, fase: "trifasico", tipo: "Bomba C/Carga", metodo: "SOFT", inst: "B2", iso: "XLPE" }, { id: "m4", nome: "Ventilador", cv: 3, V: 380, fase: "trifasico", tipo: "Bomba C/Carga", metodo: "DIN", inst: "B2", iso: "PVC" }, { id: "m5", nome: "Dosadora", cv: 1, V: 220, fase: "monofasico", tipo: "Bomba C/Carga", metodo: "DIN", inst: "B2", iso: "PVC" }, ]; const QuadroMotores = () => { const [motores, setMotores] = useMotPersist("vl_quadro_motores_v1", MOT_SAMPLE); const [sel, setSel] = useStMot(MOT_SAMPLE[0].id); const rows = useMemoMot(() => motores.map(m => { const In = correnteNominal(m.cv, m.V, m.fase || "trifasico"); const fp = MOT_FATOR_PARTIDA[m.tipo]?.[m.metodo] ?? 1; const Ipart = In * fp; const cabo = dimensionarCabo(In, m.inst, m.iso); const amp = m.inst === "B1" ? cabo.B1 : cabo.B2; return { ...m, In, fp, Ipart, cabo, amp }; }), [motores]); const totals = useMemoMot(() => { const In = rows.reduce((s, r) => s + r.In, 0); const pot = rows.reduce((s, r) => s + (parseFloat(r.cv) || 0), 0); const potKW = pot * 0.73549875; const maiorPartida = rows.reduce((mx, r) => r.Ipart > mx.Ipart ? r : mx, { Ipart: 0 }); // corrente de pico (maior partida + nominal dos demais) — dimensionamento do barramento const pico = maiorPartida.Ipart > 0 ? (In - maiorPartida.In) + maiorPartida.Ipart : In; return { In, pot, potKW, maiorPartida, pico }; }, [rows]); const selM = rows.find(r => r.id === sel) || rows[0]; const add = () => { const m = { id: "m" + Date.now(), nome: "Motor " + (motores.length + 1), cv: 5, V: 380, fase: "trifasico", tipo: "Normal", metodo: "DIN", inst: "B2", iso: "PVC" }; setMotores([...motores, m]); setSel(m.id); }; const upd = (id, patch) => setMotores(motores.map(m => m.id === id ? { ...m, ...patch } : m)); const del = (id) => { setMotores(motores.filter(m => m.id !== id)); if (sel === id) setSel(null); }; const reset = () => { setMotores(MOT_SAMPLE); setSel(MOT_SAMPLE[0].id); if (window.vlToast) window.vlToast("✓ Restaurado"); }; const exportCSV = () => { const head = ["NOME","POT(CV)","TENSAO(V)","FASE","TIPO","METODO","In(A)","FATOR PARTIDA","Ipart(A)","INSTAL","CABO(mm2)","ISOLACAO","AMPACIDADE(A)"]; const lines = [head.join(";")]; rows.forEach(r => lines.push([r.nome, r.cv, r.V, faseAbbr(r.fase), r.tipo, r.metodo, r.In.toFixed(1), r.fp, r.Ipart.toFixed(1), r.inst, r.cabo.sec, r.cabo.iso, r.amp].join(";"))); lines.push(""); lines.push(["TOTAL In (A)", totals.In.toFixed(1)].join(";")); lines.push(["Corrente de pico (A)", totals.pico.toFixed(1)].join(";")); lines.push(["Potencia total (kW)", totals.potKW.toFixed(1)].join(";")); const a = document.createElement("a"); a.href = URL.createObjectURL(new Blob(["\uFEFF" + lines.join("\n")], { type: "text/csv;charset=utf-8" })); a.download = "quadro-motores.csv"; a.click(); if (window.vlToast) window.vlToast("✓ CSV exportado"); }; const Sync = window.VL_ProjetoSync; return (
{/* ───────── LISTA DE MOTORES ───────── */}
ENTRADA · LISTA DE MOTORES

Quadro de cargas motrizes

AUTO
{Sync && { const t = s.get("tensao"); const sis = s.get("sistema"); setMotores(motores.map(m => ({ ...m, ...(t!=null?{V:parseFloat(t)}:{}), ...(sis?{fase:sis}:{}) }))); }} push={() => ({ tensao: parseFloat(selM?.V) || undefined, sistema: selM?.fase, corrente: +totals.In.toFixed(2), potencia: +totals.potKW.toFixed(3) })} />}
MOTORCVPARTIDAIn (A)CABO
{rows.map(r => (
setSel(r.id)}>
{r.nome} {faseAbbr(r.fase)} · {r.tipo} · {r.V} V
{r.cv} {r.metodo} {motFmt(r.In)} {r.cabo.sec} {r.cabo.iso} · {r.inst}
))}
{/* totalizadores */}
Motores{String(rows.length).padStart(2, "0")}
Corrente total In{motFmt(totals.In)} A
Potência instalada{motFmt(totals.potKW)} kW
{/* ───────── DETALHE DO MOTOR SELECIONADO ───────── */}
{/* ───────── DIMENSIONAMENTO DO BARRAMENTO / TOTAL ───────── */}
DIMENSIONAMENTO GLOBAL · QUADRO

Corrente de projeto do alimentador geral

pico = Σ In + (fator partida − 1)·maior motor
CORRENTE NOMINAL Σ
{motFmt(totals.In)}A
CORRENTE DE PICO
{motFmt(totals.pico)}A
MAIOR PARTIDA
{totals.maiorPartida?.nome ? motFmt(totals.maiorPartida.Ipart) : "—"}A
POTÊNCIA TOTAL
{motFmt(totals.potKW)}kW
Disjuntor geral sugerido ≥ {Math.ceil(totals.pico / 5) * 5} A {totals.maiorPartida?.nome ? ` · maior partida: ${totals.maiorPartida.nome} (${totals.maiorPartida.metodo})` : ""}
{/* ───────── TABELAS DE REFERÊNCIA ───────── */}
REFERÊNCIA · FATOR DE PARTIDA

Tipo de carga × método

D-MOTORES
TIPODINSOFTINVERSORAUTOTRAFO
{MOT_TIPOS.map(t => (
{t} {["DIN","SOFT","INVERSOR","AUTOTRAFO"].map(mt => ( {MOT_FATOR_PARTIDA[t][mt].toFixed(2)} ))}
))}
REFERÊNCIA · AMPACIDADE

Seção × isolação × instalação

D-CABOS · A
SEÇÃO (mm²)ISOLAÇÃOB1 (A)B2 (A)
{MOT_CABOS.map((c, i) => { const isSel = selM && selM.cabo.sec === c.sec && selM.cabo.iso === c.iso; return (
{c.sec} {c.iso} {c.B1} {c.B2}
); })}
); }; window.VL_QuadroMotores = QuadroMotores;