import { CONSTANTS, PRESETS } from "./src/types"; let h = 0, x = 0, vx = 0, vy = 0, v = 0, pitch = 90, t = 0; let currentStage = 0; let fuel = PRESETS[0].stages[0].fuelMass; const currentEvents = []; let maxQ = 0; let isRunning = true; for (let i = 0; i < 50000; i++) { const dt = 0.1; const rocket = PRESETS[0]; const { area, cd, stages } = rocket; const stage = stages[currentStage]; const { dryMass, maxThrust, isp } = stage; let upperStagesMass = 0; for (let j = currentStage + 1; j < stages.length; j++) { upperStagesMass += stages[j].dryMass + stages[j].fuelMass; } const m = dryMass + fuel + upperStagesMass; const mDotMax = maxThrust / (isp * CONSTANTS.g0); let actualThrottle = 1; if (fuel <= 0 && currentStage < stages.length - 1) { currentStage++; fuel = stages[currentStage].fuelMass; if (!currentEvents.find((e) => e.name === `stageSep${currentStage}`)) { currentEvents.push({ name: `stageSep${currentStage}`, time: t }); } } else if (fuel <= 0) { actualThrottle = 0; fuel = 0; } const currentThrust = maxThrust * actualThrottle; const mDot = mDotMax * actualThrottle; if (actualThrottle > 0) { fuel -= mDot * dt; if (fuel < 0) fuel = 0; } v = Math.sqrt(vx * vx + vy * vy); const pitching = h > 500; if (pitching) { pitch = 90 * Math.exp(-h / 30000); } if (h <= 500) { pitch = 90; } const pitchRad = (pitch * Math.PI) / 180; const fg = (CONSTANTS.G * (CONSTANTS.M_EARTH * m)) / Math.pow(CONSTANTS.R_EARTH + h, 2); const centrifugalY = (m * vx * vx) / (CONSTANTS.R_EARTH + h); const rho = h > 100000 ? 0 : CONSTANTS.RHO_0 * Math.exp(-h / CONSTANTS.H); const currentQ = 0.5 * rho * v * v; const fd = currentQ * cd * area; const thrustX = currentThrust * Math.cos(pitchRad); const thrustY = currentThrust * Math.sin(pitchRad); const vDirX = v > 0 ? vx / v : 0; const vDirY = v > 0 ? vy / v : 1; const dragX = fd * vDirX; const dragY = fd * vDirY; const netForceX = thrustX - dragX; const netForceY = thrustY - dragY - fg + centrifugalY; let ax = netForceX / m; let ay = netForceY / m; if (h <= 0 && vy <= 0 && netForceY <= 0) { ay = 0; ax = 0; vx = 0; vy = 0; h = 0; pitch = 90; } vx += ax * dt; vy += ay * dt; x += vx * dt; h += vy * dt; if (h < 0) h = 0; t += dt; v = Math.sqrt(vx * vx + vy * vy); if (h > 10 && v > 1 && !currentEvents.find((e) => e.name === "liftoff")) { currentEvents.push({ name: "liftoff", time: t }); } if (currentQ > maxQ) maxQ = currentQ; if (maxQ > 20000 && currentQ < maxQ * 0.95 && !currentEvents.find((e) => e.name === "maxq")) { currentEvents.push({ name: "maxq", time: t }); } if (currentStage === stages.length - 1 && fuel <= 0 && t > 10 && !currentEvents.find((e) => e.name === "meco")) { currentEvents.push({ name: "meco", time: t }); } if (h >= 100000 && !currentEvents.find((e) => e.name === "karman")) { currentEvents.push({ name: "karman", time: t }); } if (vx >= 7800 && !currentEvents.find((e) => e.name === "orbit")) { currentEvents.push({ name: "orbit", time: t }); } if (i % 500 === 0) { console.log(`t: ${t.toFixed(1)}, stage: ${currentStage}, h: ${(h/1000).toFixed(1)}km, v: ${v.toFixed(1)}m/s, vx: ${vx.toFixed(1)}, pitch: ${pitch.toFixed(1)}, fuel: ${fuel.toFixed(0)}, FnetY: ${netForceY.toFixed(0)}`); } if (currentEvents.find((e) => e.name === "meco") && t > currentEvents.find((e) => e.name === "meco").time + 3) { console.log("SIM ENDED"); break; } } console.log(currentEvents);