119 lines
3.5 KiB
JavaScript
119 lines
3.5 KiB
JavaScript
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);
|