$w.onReady(function () { const toNum = (v) => Number(String(v ?? "").replace(",", ".")); const r0 = (x) => Math.round(+x); // integer bars const r2 = (x) => (Math.round((+x) * 100) / 100).toFixed(2); // 2 decimals for % // ----------------------- // CONFIG: average fill gas temperatures (°C) // ----------------------- const TFILL_GRAVITY_C = 45; // typical "gravity" fill (medium-fast) const TFILL_BOOSTER_C = 65; // booster ~1:20 (average conservative value) $w("#button1").onClick(() => { // --- Inputs --- const V = toNum($w("#input6").value); const xEAN = toNum($w("#input5").value) / 100; // Current mix const O2v = toNum($w("#input4").value) / 100; const Hev = toNum($w("#input7").value) / 100; const P0 = toNum($w("#input8").value); // Target mix const O2t = toNum($w("#input9").value) / 100; const Het = toNum($w("#input10").value) / 100; const Pt = toNum($w("#input11").value); // target at cold (final stabilized pressure) // --- New controls --- const useTemp = Array.isArray($w("#checkboxGroup2").value) && $w("#checkboxGroup2").value.length > 0; const useBooster = Array.isArray($w("#checkboxGroup3").value) && $w("#checkboxGroup3").value.length > 0; const Tamb_C = toNum($w("#input12").value); // --- Validations --- if ([xEAN,O2v,Hev,P0,O2t,Het,Pt].some(isNaN)) { $w("#text17").text = "Error: please fill all numeric fields."; return; } if (O2v + Hev > 1 || O2t + Het > 1) { $w("#text17").text = "Error: O₂% + He% must be ≤ 100%."; return; } if (Pt <= P0) { $w("#text17").text = "Error: target pressure must be higher than current pressure."; return; } if (useTemp && isNaN(Tamb_C)) { $w("#text17").text = "Error: please enter ambient temperature (°C)."; return; } // ----------------------- // MOLAR CALCULATION (cold) — base math unchanged // ----------------------- const O2pp0 = P0 * O2v; const Hepp0 = P0 * Hev; const N2pp0 = P0 * (1 - O2v - Hev); // 1) Helium const He_pp_tar = Pt * Het; let addHe = He_pp_tar - Hepp0; if (addHe < -1e-9) { $w("#text17").text = "Impossible: current He already above target."; return; } addHe = Math.max(0, addHe); const P1 = P0 + addHe; // 2) Oxygen let addO2; if (Math.abs(1 - xEAN) < 1e-9) { addO2 = Pt * O2t - O2pp0; } else { addO2 = (Pt*O2t - O2pp0 - xEAN*Pt + xEAN*P1) / (1 - xEAN); } if (addO2 < -1e-9) addO2 = 0; const P2 = P1 + addO2; // 3) Air/EAN const addEAN = Pt - P2; if (addEAN < -1e-9) { $w("#text17").text = "Impossible: final pressure exceeded."; return; } // Final mix check (cold) const O2ppF = O2pp0 + addO2 + addEAN * xEAN; const HeppF = Hepp0 + addHe; const N2ppF = N2pp0 + addEAN * (1 - xEAN); const O2f = O2ppF / Pt; const Hef = HeppF / Pt; const N2f = 1 - O2f - Hef; // ----------------------- // BASIC ISOTHERMAL OUTPUT (no temperature correction) // ----------------------- if (!useTemp) { const heBars = r0(addHe); const o2Bars = r0(addO2); const eanBars = r0(addEAN); const pStart = r0(P0); const pAfterHe= r0(P0 + addHe); const pAfterO2= r0(P1 + addO2); const pFinal = r0(Pt); const line1 = `STEP 1 — Helium (He): add ${heBars} bar → from ${pStart} to ${pAfterHe} bar \n`; const line2 = `STEP 2 — Oxygen (O₂): add ${o2Bars} bar → from ${pAfterHe} to ${pAfterO2} bar \n`; const line3 = `STEP 3 — Air/EAN (${(xEAN*100).toFixed(0)}% O₂): add ${eanBars} bar → from ${pAfterO2} to ${pFinal} bar \n`; $w("#text17").text = `${line1}\n${line2}\n${line3}\n\n` + `Final mix @ ${pFinal} bar:\n` + `• O₂ ≈ ${r2(O2f*100)}% | He ≈ ${r2(Hef*100)}% | N₂ ≈ ${r2(N2f*100)}%`; return; } // ----------------------- // TEMPERATURE CORRECTION (continuous fill, no pauses) // ----------------------- const Tfill_C = useBooster ? TFILL_BOOSTER_C : TFILL_GRAVITY_C; const Tamb_K = Tamb_C + 273.15; const Tfill_K = Tfill_C + 273.15; const k = Tfill_K / Tamb_K; // >1 → what the gauge shows while filling // Convert to "hot" bars seen on the gauge let P_hot = P0; // current gauge pressure const addHe_hot = addHe * k; P_hot += addHe_hot; const P1_hot = P_hot; const addO2_hot = addO2 * k; P_hot += addO2_hot; const P2_hot = P_hot; const addEAN_hot = addEAN * k; P_hot += addEAN_hot; const P3_hot = P_hot; // Predicted cold pressure after cooling down to Tamb const P_final_cold = P3_hot * (Tamb_K / Tfill_K); // Rounded values for display const heBarsHot = r0(addHe_hot); const o2BarsHot = r0(addO2_hot); const eanBarsHot = r0(addEAN_hot); const pStartHot = r0(P0); const pAfterHeHot = r0(P1_hot); const pAfterO2Hot = r0(P2_hot); const pFinalHot = r0(P3_hot); const pFinalCold = r0(P_final_cold); // Output text const modeTxt = useBooster ? "booster (~1:20)" : "gravity fill"; const line1 = `STEP 1 — Helium (He): add ${heBarsHot} bar (hot) → from ${pStartHot} to ${pAfterHeHot} bar \n`; const line2 = `STEP 2 — Oxygen (O₂): add ${o2BarsHot} bar (hot) → up to ${pAfterO2Hot} bar \n`; const line3 = `STEP 3 — Air/EAN (${(xEAN*100).toFixed(0)}% O₂): add ${eanBarsHot} bar (hot) → up to ${pFinalHot} bar \n`; $w("#text17").text = `${line1}\n${line2}\n${line3}\n\n` + `Thermal assumptions: Tₐₘb = ${r0(Tamb_C)}°C, T_fill ≈ ${r0(Tfill_C)}°C, mode = ${modeTxt}\n` + `Predicted stabilized (cold) pressure: ${pFinalCold} bar (target: ${r0(Pt)} bar)\n` + `Expected final mix @ cold:\n` + `• O₂ ≈ ${r2(O2f*100)}% | He ≈ ${r2(Hef*100)}% | N₂ ≈ ${r2(N2f*100)}%`; }); });