| | class Rocket { |
| | - constructor(wet, payload, diameter, dragCoefficient, specificImpulse) { |
| | - console.assert(wet >= 1); |
| | - console.assert(payload >= 1); |
| | - console.assert(diameter > 0); |
| | - console.assert(dragCoefficient > 0); |
| | - console.assert(specificImpulse > 1); |
| | - |
| | - this.mass = wet; |
| | - this.targetMass = wet + payload; |
| | - this.radius = diameter / 2.0; |
| | - this.specificImpulse = specificImpulse; |
| | - this.totalThrust = 0.0; |
| | - this.targetAltitude = 0.0; |
| | - this.massFlowRate = 0.0; |
| | - this.vAcceleration = 0.0; |
| | - this.hAcceleration = 0.0; |
| | - |
| | - const crossSectionArea = Math.PI * this.radius ** 2; |
| | - this.ballisticCoefficient = dragCoefficient * crossSectionArea; |
| | - |
| | - this.flightRecorder = false; |
| | - this.launched = false; |
| | - this.relocated = false; |
| | - this.world = false; |
| | - } |
| | + constructor(wetMass, payloadMass) { |
| | + this.wetMass = wetMass; |
| | + this.payloadMass = payloadMass; |
| | + this.dryMass = this.wetMass * 0.1 + this.payloadMass; |
| | + this.mass = this.wetMass; |
| | |
| | - recorder(flightRecorder) { |
| | - this.blackBox = flightRecorder; |
| | - this.flightRecorder = true; |
| | + this.azimuth = 0.0; |
| | } |
| | |
| | on(planet) { |
| | this.planet = planet; |
| | - this.world = true; |
| | } |
| | |
| | - translocate(latitude, altitude) { |
| | - console.assert(!this.launched); |
| | - console.assert(this.world); |
| | + fuselage(diameter, dragCoefficient, specificImpulse) { |
| | + const crossSectionalArea = Math.PI * (diameter / 2) ** 2; |
| | + this.ballisticCoefficient = dragCoefficient * crossSectionalArea; |
| | + this.specificImpulse = specificImpulse; |
| | + } |
| | |
| | + translocate(latitude, altitude) { |
| | this.latitude = latitude; |
| | this.altitude = altitude; |
| | - this.azimuth = 0; |
| | - |
| | - const LOCAL_GRAVITY = this.planet.gravity(latitude, altitude); |
| | - this.vExhaust = this.specificImpulse * LOCAL_GRAVITY; |
| | - this.maxAcceleration = 5.0 * LOCAL_GRAVITY; |
| | - this.rotationalSpeed = this.planet.rotationalSpeed(latitude, altitude); |
| | - this.relocated = true; |
| | } |
| | - |
| | - launch(hVelocity, vVelocity) { |
| | - console.assert(this.world); |
| | - console.assert(this.relocated); |
| | - console.assert(!this.launched); |
| | |
| | - this.launched = true; |
| | + apogee(targetAltitude) { |
| | + this.targetAltitude = targetAltitude; |
| | + } |
| | |
| | - this.hVelocity = hVelocity + this.rotationalSpeed; |
| | - this.vVelocity = vVelocity; |
| | + gravity() { |
| | + return this.planet.gravity(this.latitude, this.altitude); |
| | + } |
| | |
| | - const dragForce = this.drag(); |
| | + launch(initialVelocity) { |
| | + this.exhaustVelocity = this.specificImpulse * this.gravity(); |
| | + this.maximumAcceleration = 5.0 * this.gravity(); |
| | + this.vVelocity = initialVelocity * this.planet.soundSpeed(this.altitude); |
| | |
| | - this.massFlowRate = Math.abs(dragForce[1]) / this.vExhaust * 1.001; |
| | - this.totalThrust = this.vExhaust * this.massFlowRate; |
| | + this.hVelocity = this.planet.rotationalSpeed(this.latitude, this.altitude); |
| | + this.hVelocityTarget = this.planet.orbitalSpeed(this.latitude, this.targetAltitude); |
| | + this.massFlowRate = Math.abs(this.drag()[1]) / this.exhaustVelocity * 1.001; |
| | } |
| | |
| | - apogee(altitude) { |
| | - this.hTargetVelocity = this.planet.orbitalSpeed(this.latitude, altitude); |
| | - this.targetAltitude = altitude; |
| | + recorder(blackBox) { |
| | + this.flightRecorder = blackBox; |
| | } |
| | |
| | drag() { |
| | - console.assert(this.launched); |
| | - console.assert(this.relocated); |
| | - console.assert(this.world); |
| | - |
| | const rho = this.planet.airDensity(this.altitude); |
| | - const hVelocityNet = this.hVelocity - this.rotationalSpeed; |
| | - const totalSpeed = Math.sqrt(hVelocityNet ** 2 + this.vVelocity ** 2); |
| | + const vHorNet = this.hVelocity - this.planet.rotationalSpeed(this.latitude, this.altitude); |
| | + const totalSpeed = Math.sqrt(vHorNet ** 2 + this.vVelocity ** 2); |
| | const magnitude = 0.5 * rho * this.ballisticCoefficient * totalSpeed ** 2; |
| | - const forceRatio = [-hVelocityNet / totalSpeed, -this.vVelocity / totalSpeed]; |
| | + const ratio = [-vHorNet / totalSpeed, -this.vVelocity / totalSpeed]; |
| | |
| | - return [forceRatio[0] * magnitude, forceRatio[1] * magnitude]; |
| | + return [ratio[0] * magnitude, ratio[1] * magnitude]; |
| | } |
| | |
| | flying() { |
| | - console.assert(this.mass > 0); |
| | - console.assert(this.targetMass > 0); |
| | - console.assert(this.targetAltitude > 0); |
| | - |
| | - return ( |
| | - this.mass > this.targetMass && |
| | - this.altitude < this.targetAltitude |
| | - ); |
| | + return this.mass > this.dryMass && this.altitude < this.targetAltitude; |
| | } |
| | |
| | fly(step) { |
| | - console.assert(this.launched); |
| | - console.assert(step > 0); |
| | - |
| | - const dragForce = this.drag(); |
| | + const drag = this.drag(); |
| | |
| | - if (this.hVelocity < this.hTargetVelocity) { |
| | - const magnitude = Math.sqrt( |
| | - this.hAcceleration ** 2 + this.vAcceleration ** 2 |
| | - ); |
| | - const absDragForce = Math.abs(dragForce[1]); |
| | + if (this.hVelocity < this.hVelocityTarget) { |
| | + const accMag = Math.sqrt(this.hAcceleration ** 2 + this.vAcceleration ** 2); |
| | + const absDrag = Math.abs(drag[1]); |
| | |
| | - if (magnitude > this.maxAcceleration && |
| | - this.vExhaust * this.massFlowRate * 0.98 > absDragForce) { |
| | + if (accMag > this.maximumAcceleration && this.exhaustVelocity * this.massFlowRate * 0.98 > absDrag) { |
| | this.massFlowRate *= 0.99; |
| | } |
| | - |
| | - if (this.vExhaust * this.massFlowRate < absDragForce) { |
| | - this.massFlowRate = absDragForce / this.vExhaust * 1.1; |
| | + if (this.exhaustVelocity * this.massFlowRate < absDrag) { |
| | + this.massFlowRate = absDrag / this.exhaustVelocity * 1.1; |
| | } |
| | } else { |
| | this.massFlowRate = 0.0; |
| | } |
| | |
| | - this.totalThrust = this.vExhaust * this.massFlowRate; |
| | + this.totalThrust = this.exhaustVelocity * this.massFlowRate; |
| | |
| | const thrusting = this.totalThrust > 0; |
| | - const vThrust = thrusting ? -dragForce[1] : 0.0; |
| | - const hThrust = thrusting ? Math.sqrt(this.totalThrust ** 2 - vThrust ** 2) : 0.0; |
| | + const vThrust = thrusting ? -drag[1] : 0; |
| | + const hThrust = thrusting ? Math.sqrt(this.totalThrust ** 2 - vThrust ** 2) : 0; |
| | |
| | - this.hAcceleration = dragForce[0] / this.mass + hThrust / this.mass; |
| | - this.vAcceleration = dragForce[1] / this.mass - this.planet.gravity(this.latitude, this.altitude) + vThrust / this.mass; |
| | + this.hAcceleration = drag[0] / this.mass + hThrust / this.mass; |
| | + this.vAcceleration = drag[1] / this.mass + this.gravity() + vThrust / this.mass; |
| | |
| | - this.hVelocity += this.hAcceleration * step; |
| | this.vVelocity += this.vAcceleration * step; |
| | + this.hVelocity += this.hAcceleration * step; |
| | |
| | - this.azimuth += this.hVelocity * step + 0.5 * this.hAcceleration * step ** 2; |
| | 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; |
| | - |
| | } |
| | - |
| | - stop() {} |
| | |
| | record(time) { |
| | - console.assert(this.flightRecorder); |
| | - |
| | - this.blackBox.azimuth(time, this.azimuth); |
| | - this.blackBox.horizontalVelocity(time, this.hVelocity); |
| | - this.blackBox.horizontalAcceleration(time, this.hAcceleration); |
| | - this.blackBox.altitude(time, this.altitude); |
| | - this.blackBox.verticalVelocity(time, this.vVelocity); |
| | - this.blackBox.verticalAcceleration(time, this.vAcceleration); |
| | - this.blackBox.thrustAcceleration(time, this.totalThrust / this.mass); |
| | - this.blackBox.mass(time, this.mass); |
| | + 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.totalThrust / this.mass); |
| | + this.flightRecorder.mass(time, this.mass); |
| | + } |
| | } |
| | } |