ショートストーリー 反転して逆加速の革新的な再利用型ロケット
東京のプログラマー、田中は、自分の開発したシミュレーションコードが歴史を変えるとは夢にも思わなかった。革新的な再利用型ロケットは、地球周回軌道にペイロードを送り届けた後、反転して逆加速を行い、地上に着陸するという奇想天外な設計だ。しかし、その背後には、田中が数ヶ月前に書いた小さなプログラムがあった。
田中のコードは、ロケットが軌道速度に到達するまでの加速と、その後、同じ推力を用いて減速するシミュレーションを精密に計算するものだった。地球の引力を計算に入れ、適切な減速を行えば、ロケットは大気の摩擦で速度を失いながらも安全に地上に着陸できることを、彼のプログラムは示していた。
「逆加速で地球に向かって落下するなんて、ありえないだろう」。当初、多くの技術者がそう言った。だが、田中は違った。シミュレーション結果は確かにその可能性を示していたのだ。
ロケットが宇宙でのミッションを終え、予定通りに反転し、地球に向かって減速を開始した瞬間、田中の心臓は高鳴った。まるで彼自身がそのプログラムの中にいるかのように、ロケットの動きを追っていた。ロケットが軌道を離れ、計算通りに降下していく様子は、田中の作ったシミュレーションと寸分違わなかった。
やがて、ロケットは大気圏に突入し、強烈な摩擦によって減速した。田中の胸の中で、無数のコードが駆け巡る。あの小さなシミュレーションが、現実の技術革新を導いた瞬間だった。
コードをメモ帳などのテキストエディタに貼り付け、ファイル名を「index.html」として保存します。その後、保存したファイルをブラウザで開けば、コードが実行されます。
着陸シーケンス開始ボタンは速度が7,800に到達したら有効になります。
推力最大、ペイロード最小の設定が良いです。
シミュレーションのコントロールパネルにユーザーが入力した値がリアルタイムに反映されます、ペイロードの重さ、推力、高度の調整が行われます。また、軌道速度到達後に着陸シーケンスも開始でき、軌道に乗った後の着陸フェーズをシミュレートします。スペースX のブースターの様に軌道速度到達後反転して降下します。
<!DOCTYPE html>
<html lang="ja">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>地球周回軌道シミュレーション</title>
<style>
/* 画面全体に表示するために、マージンとスクロールを無効化 */
body {
margin: 0;
overflow: hidden;
}
/* コントロールパネルのスタイル設定 */
#controls {
position: absolute;
top: 10px;
left: 10px;
z-index: 100;
background-color: white;
padding: 10px;
border-radius: 8px;
}
/* ボタンのスタイル設定 */
button {
margin-top: 10px;
padding: 5px 10px;
}
</style>
</head>
<body>
<!-- コントロールパネル -->
<div id="controls">
<label for="payload">ペイロードの重さ (kg): </label>
<input type="range" id="payload" min="100" max="2000" value="1000">
<span id="payloadValue">1000</span> kg
<br>
<label for="thrust">推力 (N): </label>
<input type="range" id="thrust" min="10" max="500" value="50">
<span id="thrustValue">50</span> N
<br>
<label for="altitude">投入軌道の高度 (km): </label>
<input type="range" id="altitude" min="200" max="1000" value="500">
<span id="altitudeValue">500</span> km
<p>速度: <span id="velocity">0</span> m/s</p>
<p>軌道速度: 7800 m/s (地球周回軌道)</p>
<p>高度: <span id="currentAltitude">0</span> km</p>
<button id="startLanding">着陸シーケンス開始</button>
</div>
<!-- Three.jsライブラリをCDN経由で読み込む -->
<script src="https://cdnjs.cloudflare.com/ajax/libs/three.js/r128/three.min.js"></script>
<script>
// シーン、カメラ、レンダラーのセットアップ
const scene = new THREE.Scene();
const camera = new THREE.PerspectiveCamera(75, window.innerWidth / window.innerHeight, 0.1, 1000);
const renderer = new THREE.WebGLRenderer();
renderer.setSize(window.innerWidth, window.innerHeight);
document.body.appendChild(renderer.domElement);
// 地球のオブジェクトを作成 (青色の球体)
const earthGeometry = new THREE.SphereGeometry(1, 32, 32);
const earthMaterial = new THREE.MeshBasicMaterial({ color: 0x0000ff });
const earth = new THREE.Mesh(earthGeometry, earthMaterial);
scene.add(earth);
// ロケットを表す小さな赤い球体を作成
const rocketGeometry = new THREE.SphereGeometry(0.05, 16, 16);
const rocketMaterial = new THREE.MeshBasicMaterial({ color: 0xff0000 });
const rocket = new THREE.Mesh(rocketGeometry, rocketMaterial);
scene.add(rocket);
// 軌道の軌跡を描画するためのラインオブジェクトを作成
const orbitPoints = [];
const orbitGeometry = new THREE.BufferGeometry().setFromPoints(orbitPoints);
const orbitMaterial = new THREE.LineBasicMaterial({ color: 0x00ff00 });
const orbitLine = new THREE.Line(orbitGeometry, orbitMaterial);
scene.add(orbitLine);
// カメラの位置を調整
camera.position.z = 5;
// 初期変数の設定
let payloadWeight = document.getElementById("payload").value;
let thrust = document.getElementById("thrust").value;
let targetAltitude = document.getElementById("altitude").value;
let velocity = 0;
let altitude = 0;
const orbitalVelocity = 7800; // 地球周回軌道の速度
let inOrbit = false; // 軌道に乗っているかどうか
let landingPhase = false; // 着陸フェーズかどうか
let atmosphericDrag = 0.05; // 大気摩擦の強さ
// ペイロードの重さが変わったときにシミュレーションをリセット
document.getElementById("payload").addEventListener("input", function () {
payloadWeight = this.value;
document.getElementById("payloadValue").textContent = payloadWeight;
resetSimulation();
});
// 推力が変わったときにシミュレーションをリセット
document.getElementById("thrust").addEventListener("input", function () {
thrust = this.value;
document.getElementById("thrustValue").textContent = thrust;
resetSimulation();
});
// 高度が変わったときにシミュレーションをリセット
document.getElementById("altitude").addEventListener("input", function () {
targetAltitude = this.value;
document.getElementById("altitudeValue").textContent = targetAltitude;
resetSimulation();
});
// 着陸シーケンス開始ボタンが押されたとき
document.getElementById("startLanding").addEventListener("click", function () {
if (inOrbit) {
landingPhase = true;
}
});
// シミュレーションをリセットする関数
function resetSimulation() {
velocity = 0;
altitude = 0;
inOrbit = false;
landingPhase = false;
document.getElementById("velocity").textContent = velocity;
document.getElementById("currentAltitude").textContent = altitude;
orbitPoints.length = 0; // 軌跡のリセット
}
// シミュレーションの更新ロジック
function updateSimulation() {
if (!inOrbit) {
// 推力による加速度を計算
const acceleration = thrust / payloadWeight;
if (velocity < orbitalVelocity && altitude < targetAltitude) {
// 軌道速度および目標高度に到達するまで加速
velocity += acceleration;
altitude += velocity * 0.001;
} else if (velocity >= orbitalVelocity && altitude >= targetAltitude) {
inOrbit = true; // 軌道に乗る
} else if (velocity < orbitalVelocity && altitude >= targetAltitude) {
// 速度が足りない場合は高度を減少させる
altitude -= 1;
if (altitude <= 0) {
altitude = 0;
velocity = 0;
}
}
} else if (inOrbit && !landingPhase) {
velocity = orbitalVelocity; // 軌道を維持
} else if (landingPhase) {
// 着陸フェーズの処理
const deceleration = (thrust / payloadWeight) + atmosphericDrag;
if (velocity > 0) {
velocity -= deceleration; // 減速
}
if (altitude > 0) {
altitude -= 1; // 高度を減少
} else {
altitude = 0;
velocity = 0;
}
}
// 速度と高度をUIに表示
document.getElementById("velocity").textContent = velocity.toFixed(2);
document.getElementById("currentAltitude").textContent = altitude.toFixed(0);
// ロケットの位置を計算
const angle = (velocity / orbitalVelocity) * Math.PI * 2;
const distance = 1 + altitude / 6371; // 地球の半径6371kmに基づく
rocket.position.x = distance * Math.cos(angle);
rocket.position.y = distance * Math.sin(angle);
// 軌跡の描画
orbitPoints.push(new THREE.Vector3(rocket.position.x, rocket.position.y, rocket.position.z));
orbitGeometry.setFromPoints(orbitPoints);
// カメラの移動 (地球の周囲を回る)
const time = Date.now() * 0.0005;
camera.position.x = 5 * Math.cos(time);
camera.position.z = 5 * Math.sin(time);
camera.lookAt(earth.position); // 常に地球を向く
// レンダリング
renderer.render(scene, camera);
}
// アニメーションループ
function animate() {
requestAnimationFrame(animate);
updateSimulation(); // シミュレーションを更新
}
// 初期化
resetSimulation();
animate(); // アニメーション開始
// 画面サイズが変更された場合の処理
window.addEventListener('resize', () => {
camera.aspect = window.innerWidth / window.innerHeight;
camera.updateProjectionMatrix();
renderer.setSize(window.innerWidth, window.innerHeight);
});
</script>
</body>
</html>