class Rocket {
constructor(wetMass, payloadMass) {
this.mass = wetMass;
this.payloadMass = payloadMass;
this.dryMass = wetMass * 0.1 + this.payloadMass;
this.azimuth = 0.0;
this.altitude = 0.0;
}
on(planet) {
this.planet = planet;
}
fuselage(diameter, dragCoefficient, specificImpulse) {
const crossSectionalArea = Math.PI * (diameter / 2) ** 2;
this.ballisticCoefficient = dragCoefficient * crossSectionalArea;
this.specificImpulse = specificImpulse;
}
translocate(latitude, altitude) {
console.assert(altitude >= 0);
this.latitude = latitude;
this.altitude = altitude;
}
apogee(targetAltitude) {
this.targetAltitude = targetAltitude;
this.hVelocityTarget = this.planet.orbitalSpeed(
this.latitude, this.targetAltitude
);
}
rotational() {
return this.planet.rotationalSpeed(this.latitude, this.altitude);
}
launch(velocity) {
const g = this.planet.gravity(this.latitude, this.targetAltitude);
this.exhaustVelocity = this.specificImpulse * g;
this.hVelocityInitial = this.rotational();
this.hVelocity = this.hVelocityInitial;
this.vVelocity = velocity * this.planet.soundSpeed(this.altitude);
this.vVelocityInitial = this.vVelocity;
this.maxAcceleration = 5.0 * g;
const drag = this.drag();
this.massFlowRate = Math.abs(this.drag()[1]) / this.exhaustVelocity * 1.001;
this.tThrust = this.exhaustVelocity * this.massFlowRate;
const vThrust = -drag[1];
const hThrust = Math.sqrt(this.tThrust ** 2 - vThrust ** 2);
this.vAcceleration = drag[1] / this.mass + g + vThrust / this.mass;
this.hAcceleration = drag[0] / this.mass + hThrust / this.mass;
}
recorder(blackBox) {
this.flightRecorder = blackBox;
}
drag() {
const rho = this.planet.airDensity(this.altitude);
const vHorNet = this.hVelocity - this.hVelocityInitial;
let speedTotal = this.magnitude(vHorNet, this.vVelocity);
if (speedTotal === 0) {
speedTotal = 1e-10;
}
const dragForce = 0.5 * rho * this.ballisticCoefficient *
speedTotal ** 2;
const ratio = [-vHorNet / speedTotal, -this.vVelocity / speedTotal];
return [dragForce * ratio[0], dragForce * ratio[1]];
}
altitudeReached() {
const mu = this.planet.standardGravity();
const r0 = this.planet.radius(this.latitude);
const r1 = r0 + this.altitude;
const r2 = mu / (-0.5 * this.vVelocity ** 2 + mu / r1);
return r2 - r0;
}
flying() {
return (
this.mass > this.dryMass &&
this.altitude < this.targetAltitude &&
this.altitude > 0
);
}
fly(step) {
const drag = this.drag();
if (this.hVelocity < this.hVelocityTarget) {
const accMag = this.magnitude(this.hAcceleration, this.vAcceleration);
const absDrag = Math.abs(drag[1]);
if (accMag > this.maxAcceleration &&
this.exhaustVelocity * this.massFlowRate * 0.98 > absDrag) {
this.massFlowRate *= 0.99;
}
if (this.exhaustVelocity * this.massFlowRate < absDrag) {
this.massFlowRate = absDrag / this.exhaustVelocity * 1.1;
}
} else {
this.massFlowRate = 0.0;
}
console.assert(this.massFlowRate >= 0);
this.tThrust = this.exhaustVelocity * this.massFlowRate;
let vThrust = 0.0;
let hThrust = 0.0;
if (this.tThrust > 0) {
vThrust = -drag[1];
const reached = this.altitudeReached();
if (reached < this.targetAltitude) {
vThrust = 0.99 * this.tThrust;
}
if (vThrust > this.tThrust) {
vThrust = this.tThrust;
}
hThrust = Math.sqrt(this.tThrust ** 2 - vThrust ** 2)
}
const g = this.planet.gravity(this.latitude, this.altitude);
this.vAcceleration = drag[1] / this.mass - g + vThrust / this.mass;
this.hAcceleration = drag[0] / this.mass + hThrust / this.mass;
this.vVelocity += this.vAcceleration * step;
this.hVelocity += this.hAcceleration * step;
this.altitude += this.vVelocity * step + 0.5 * this.vAcceleration * step ** 2;
this.azimuth += this.hVelocity * step + 0.5 * this.hAcceleration * step ** 2;
this.mass -= this.massFlowRate * step;
}
record(time) {
if (this.flightRecorder) {
this.flightRecorder.azimuth(time, this.azimuth);
this.flightRecorder.horizontalVelocity(time, this.hVelocity);
this.flightRecorder.horizontalAcceleration(time, this.hAcceleration);
this.flightRecorder.altitude(time, this.altitude);
this.flightRecorder.verticalVelocity(time, this.vVelocity);
this.flightRecorder.verticalAcceleration(time, this.vAcceleration);
this.flightRecorder.thrustAcceleration(time, this.tThrust / this.mass);
this.flightRecorder.mass(time, this.mass);
}
}
magnitude(x, y) {
return Math.sqrt(x ** 2 + y ** 2);
}
emptyMass() {
return this.dryMass;
}
initialOrbitalVelocity() {
return this.hVelocityInitial;
}
initialVerticalVelocity() {
return this.vVelocityInitial;
}
successfulFlight() {
return (
this.mass >= this.dryMass &&
this.hVelocity >= this.hVelocityTarget &&
this.altitude >= this.targetAltitude
);
}
}
export default Rocket;