万有引力の数値計算

ロケットの軌道計算

地球上からロケットを発射すると、ロケットは地球の引力の影響を受けて運動する。 宇宙空間は3次元空間だが、地球の引力による運動では2次元平面上で考えることができる。


rbCanvas プログラム

プログラム rocket_orbit.rb は、地球上から発射した推進力のないロケット(SpinLaunch)がどのように運動するかをシミュレーションする。

ロケットの初期値

プログラムは rbCanvas で動作する。 rbCanvas editor に入力して[▶]をクリックしてみよう。

rocket_orbit.rb
  1. # coding: utf-8
  2. # ロケットの運動を描画する
  3. # 動作環境:rbCanvas
  4. # 作者:山本裕樹
  5.  
  6. # 画像サイズ
  7. WIDTH = 800
  8. HEIGHT = 800
  9.  
  10. # 画像上の中心座標
  11. IOX = WIDTH / 2
  12. IOY = HEIGHT / 2
  13.  
  14. # 空間のスケール [pix/m]
  15. SCALE = 5e-6
  16.  
  17. # 物理定数
  18. G = 6.67430e-11 # 万有引力定数 [m^3/kg/s^2]
  19. ME = 5.9724e24 # 地球の質量 [kg]
  20. RE = 6.3781e6 # 地球の半径 [m]
  21.  
  22. # 経過時間 [s]
  23. t = 0
  24.  
  25. # $dt:時間の刻み [s]
  26. $dt = 60
  27.  
  28. # ロケットの初期値
  29. # (x0, y0):ロケットの発射位置 [m]
  30. x0 = RE + 50
  31. y0 = 0
  32.  
  33. # (x, y):ロケットの空間座標 [m]
  34. x = x0
  35. y = y0
  36.  
  37. # (u, v):ロケットの速度 [m/s]
  38. u = 0
  39. v = 0
  40.  
  41. # ロケットの軌跡
  42. tr = []
  43. trmax = 1000
  44.  
  45. # 原点から (x, y) までの距離
  46. def r(x, y) return Math.sqrt(x ** 2 + y ** 2) end
  47.  
  48. # 運動方程式の右辺1
  49. def f(x, y) return - G * ME * x / r(x, y) ** 3 end
  50.  
  51. # 運動方程式の右辺2
  52. def g(x, y) return - G * ME * y / r(x, y) ** 3 end
  53.  
  54. # ku, kv, kx, ky の計算
  55. def calc_k(u, v, x, y, du, dv, dx, dy)
  56. return f(x + dx, y + dy) * $dt,
  57. g(x + dx, y + dy) * $dt,
  58. (u + du) * $dt,
  59. (v + dv) * $dt
  60. end
  61.  
  62. # ルンゲ=クッタ法で $dt 後の (x,y) と (u,v) を求める
  63. def next_step(u, v, x, y)
  64. ku1, kv1, kx1, ky1 = calc_k(u, v, x, y, 0, 0, 0, 0)
  65. ku2, kv2, kx2, ky2 = calc_k(u, v, x, y,
  66. ku1 * 0.5, kv1 * 0.5, kx1 * 0.5, ky1 * 0.5)
  67. ku3, kv3, kx3, ky3 = calc_k(u, v, x, y,
  68. ku2 * 0.5, kv2 * 0.5, kx2 * 0.5, ky2 * 0.5)
  69. ku4, kv4, kx4, ky4 = calc_k(u, v, x, y, ku3, kv3, kx3, ky3)
  70. return u + (ku1 + 2 * ku2 + 2 * ku3 + ku4) / 6.0,
  71. v + (kv1 + 2 * kv2 + 2 * kv3 + kv4) / 6.0,
  72. x + (kx1 + 2 * kx2 + 2 * kx3 + kx4) / 6.0,
  73. y + (ky1 + 2 * ky2 + 2 * ky3 + ky4) / 6.0
  74. end
  75.  
  76. # 空間座標 (x,y) から画像座標 (ix,iy) へ変換
  77. def x2ix(x) return (IOX + x * SCALE).round end
  78. def y2iy(y) return (IOY - y * SCALE).round end
  79.  
  80. # 背景の設定
  81. Window.width = WIDTH
  82. Window.height = HEIGHT
  83. Window.bgcolor = 'black'
  84.  
  85. # 発射角度のスライダーとラベル
  86. label1_angle = UI.label(WIDTH + 20, 120, 100, 30, '発射角度')
  87. label2_angle = UI.label(WIDTH + 370, 120, 180, 30, '')
  88. slider_angle = UI.slider(WIDTH + 150, 120, 200, [-90, 90, 30, 1])
  89.  
  90. # 発射速度のスライダーとラベル
  91. label1_speed = UI.label(WIDTH + 20, 170, 100, 30, '発射速度')
  92. label2_speed = UI.label(WIDTH + 370, 170, 180, 30, '')
  93. slider_speed = UI.slider(WIDTH + 150, 170, 200, [5, 15, 10, 0.1])
  94.  
  95. # 発射ボタンとラベル
  96. $launch = false
  97. button_launch = UI.button(WIDTH + 20, 220, 100, 30, '発射')
  98. button_launch.on_action do
  99. $launch = true
  100. end
  101.  
  102. flight = false
  103.  
  104. Window.loop do
  105.  
  106. # 発射時
  107. if $launch
  108. # 発射角度 [rad]
  109. alpha = slider_angle.value.to_f * Math::PI / 180
  110. # 発射速度 [m/s]
  111. speed = slider_speed.value.to_f * 1e3
  112.  
  113. u = speed * Math.cos(alpha)
  114. v = speed * Math.sin(alpha)
  115. x = x0
  116. y = y0
  117. t = 0
  118. tr = []
  119. $launch = false
  120. flight = true
  121. end
  122.  
  123. # ロケットの空間座標から画像座標への変換
  124. ix = x2ix(x)
  125. iy = y2iy(y)
  126.  
  127. # 飛行中
  128. if flight
  129. # 軌跡の記録
  130. if tr.length > trmax
  131. tr.shift
  132. end
  133. tr.push([ix, iy])
  134. end
  135.  
  136. # ロケットの描画
  137. Window.draw_circle_fill(ix, iy, 3, 'green')
  138.  
  139. # 軌跡の描画
  140. (1..(tr.length - 1)).each do |i|
  141. Window.draw_dot(tr[i - 1][0], tr[i - 1][1], 'cyan', weight: 1)
  142. end
  143.  
  144. # 地球の描画
  145. Window.draw_circle_fill(x2ix(0), y2iy(0), RE * SCALE, 'blue')
  146.  
  147. # ラベルの更新
  148. label2_angle.value = "#{slider_angle.value}度"
  149. label2_speed.value = "#{slider_speed.value}km/s"
  150.  
  151. # 経過時間の表示
  152. Window.draw_font(0, 25, sprintf("経過時間:%d秒", t),
  153. Font.default, color: 'yellow')
  154.  
  155. if flight
  156. # 次のステップ
  157. u, v, x, y = next_step(u, v, x, y)
  158. t += $dt
  159.  
  160. # 地球に衝突ならストップ
  161. if r(x, y) < RE
  162. flight =false
  163. end
  164. end
  165. end

ロケットの発射速度と発射角度を色々変えてみよう。

発射速度 [m/s] 発射角度 [度] 結果
8 90 y方向に発射されたロケットは地上すれすれを周り続ける。この速度を第一宇宙速度という。
11.2 y方向に発射されたロケットは地球の引力を振り切って戻ってこない。この速度を第二宇宙速度という。

理論

地球の中心を原点としたロケットの座標を $(x,y)$ とする。 ロケットは地球の引力を受けて運動するため、$(x,y)$ は時間 $t$ で変化する。

ロケットの速度を $(v_{x},v_{y})$ とすると、$(x,y)$ と以下の関係にある。 \begin{eqnarray*} \frac{dx}{dt}&=&v_{x}\\ \frac{dy}{dt}&=&v_{y} \end{eqnarray*} ここで $\frac{dx}{dt}$ と $\frac{dy}{dt}$ は $x$ と $y$ をそれぞれ時間 $t$ で微分することを意味する。

ロケットは地球の引力を受けて運動するため、万有引力の法則から次の運動方程式が成り立つ。 \begin{eqnarray*} m\frac{dv_{x}}{dt}&=&-\frac{GM_{\mathrm{E}}m}{r^{3}}x\\ m\frac{dv_{y}}{dt}&=&-\frac{GM_{\mathrm{E}}m}{r^{3}}y \end{eqnarray*} ここで $G$ は万有引力定数、$M_{\mathrm{E}}$ は地球の質量、$m$ はロケットの質量である。 \[ G=6.67430\times 10^{-11}\mathrm{[m^{3}kg^{-1}s^{-2}]} \] \[ M_{\mathrm{E}}=5.9724\times 10^{24}\mathrm{[kg]} \] 両辺を $m$ で割ると $m$ は消えるため、この計算にロケットの質量は不要である。 \begin{eqnarray*} \frac{dv_{x}}{dt}&=&-\frac{GM_{\mathrm{E}}}{r^{3}}x\\ \frac{dv_{y}}{dt}&=&-\frac{GM_{\mathrm{E}}}{r^{3}}y \end{eqnarray*} $r$ は地球の中心からロケットまでの距離で、三平方の定理(ピタゴラスの定理)から次の式で求められる。 \[ r=\sqrt{x^{2}+y^{2}} \]

以上の式を解くとロケットの座標 $(x,y)$ が時間 $t$ とともにどのように変化するか、ロケットの軌道を求めることができる。


数値計算

以下の4つの方程式(微分方程式という)を解くとロケットの運動の軌道が求められる。 \begin{eqnarray*} \frac{dx}{dt}&=&v_{x}\\ \frac{dy}{dt}&=&v_{y}\\ \frac{dv_{x}}{dt}&=&f(x,y)\\ \frac{dv_{y}}{dt}&=&g(x,y) \end{eqnarray*} ここで \begin{eqnarray*} f(x,y)&=&-\frac{GM_{\mathrm{E}}}{r^{3}}x\\ g(x,y)&=&-\frac{GM_{\mathrm{E}}}{r^{3}}y \end{eqnarray*} とした。

微分方程式はオイラー法やルンゲ=クッタ法などを用いて数値的に計算できる。