ユーザ用ツール

サイト用ツール


ruby:rbcanvas-gravity

文書の過去の版を表示しています。


万有引力の数値計算

ロケットの軌道計算

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

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

ruby/rbcanvas-gravity.1748055199.txt.gz · 最終更新: 2025/05/24 02:53 by you