弾道計算
参考数値:
第一宇宙速度 (地表すれすれを円軌道で運動) 約 7.9 km/s (= 28,400 km/h)
第二宇宙速度 (地球脱出速度) 約 11.2 km/s(40,300 km/h)
第三宇宙速度 (太陽系脱出速度) 約 16.7 km/s (60,100 km/h)
Download script from .\cannonball_round.py
import sys
import numpy as np
from numpy import sqrt, exp, sin, cos, tan, arctan, pi
from matplotlib import pyplot as plt
"""
弾道計算
参考数値:
第一宇宙速度 (地表すれすれを円軌道で運動) 約 7.9 km/s (= 28,400 km/h)
第二宇宙速度 (地球脱出速度) 約 11.2 km/s(40,300 km/h)
第三宇宙速度 (太陽系脱出速度) 約 16.7 km/s (60,100 km/h)
"""
#===================================
# 定数
#===================================
# 円周率
pi = 3.14159265358979323846
# 万有引力定数
G = 6.67430e-11 # m^3/kg/s^2
# 太陽の質量
Ms = 1.99e30 # kg
# 地球の質量、半径、公転半径
Me = 5.972e24 # kg
Re = 12756.274e3 * 0.5 # m
Rrev = 1.50e11 # m
# 重力加速度 g = G*Me/Re^2
g = 9.8 # m/s^2
# 砲弾 (cannonball) の質量 計算結果には影響しない
mc = 1.0 # kg
# 射出速度、角度
v0 = 100.0 # m/s
Q0 = 45.0 # 度
# 計算時間間隔
dt = 1
# 最大ステップ数
nmax = 100
#===================================
# グラフ設定
#===================================
fontsize = 20
# グラフの更新時間
tsleep = 0.1 # s
#============================
# 起動時引数で初期値を更新
#============================
argv = sys.argv
if len(argv) >= 2:
v0 = float(argv[1])
if len(argv) >= 3:
Q0 = float(argv[2])
if len(argv) >= 4:
dt = float(argv[3])
if len(argv) >= 5:
nmax = int(argv[4])
if len(argv) >= 6:
tsleep = float(argv[5])
def usage():
print("")
print("使い方: python cannonball_round.py 初速度(m/s) 射出角度(度) 時間間隔(s) 繰り返し回数 描画更新時間(s)")
print("例1: python cannonball_round.py")
print(" 初期値 v0 = 100.0 m/s, Q0 = 45度, dt = 1 sで計算")
print("例2: python cannonball_flat.py 10000 20 10")
print(" v0 = 10000.0 m/s, Q0 = 20度, dt = 10 sで計算")
print("")
# 質点に係る力のベクトル Fx, Fy を返す
def force(x, y):
global g, mc
r = sqrt(x * x + y * y)
f = -mc * g * (Re / r)**2
return f * x / r, f * y / r
def main():
vx0 = v0 * cos(Q0 * pi / 180.0)
vy0 = v0 * sin(Q0 * pi / 180.0)
print("g(R0={:12.4g} m)={:10.4f} m/s^2".format(Re, G * Me / Re / Re))
print("g={:10.4f} m/s^2".format(g))
print("vx0 = {:10.4f} m/s".format(vx0))
print("vy0 = {:10.4f} m/s".format(vy0))
print("dt = {} s".format(dt))
# 宇宙速度の計算
# 地表での自転速度
vrot = 2.0 * pi * Re / 24.0 / 60.0 / 60.0
# 地球の公転速度
vrev = 2.0 * pi * Rrev / 365.24 / 24.0 / 60.0 / 60.0
# 第一宇宙速度: 遠心力と重力のつり合い: mc * v1^2 / Re = G * Me * mc / Re^2
v1 = sqrt(G * Me / Re)
# 第二宇宙速度: EU + 0.5 * mc * v2 * v2 >= 0: v2 = sqrt(2.0 * G * Me / Re) = sqrt(2.0) * v1
v2 = sqrt(2.0 * G * Me / Re)
# 地球の公転からの脱出速度: 太陽と地球の重力より初期運動エネルギーが大きい
# -G * Ms * mc / Rrev + 0.5 * mc * (vrev3 - vrev)^2 >= 0
# vrev3 = -vrev + sqrt(2.0 * G * Ms / Rrev)
vrev3 = sqrt(2.0 * G * Ms / Rrev) - vrev
# 第三宇宙速度: 地球の重力を振り払った後にvrev3になる速度
# -G * Me * mc / Re + 0.5 * mc * v3^2 >= 0.5 * mc * vrev3^2
# v3 = sqrt(2.0 * G * Ms / Rrev + vrev3^2)
v3 = sqrt(2.0 * G * Me / Re + vrev3 * vrev3)
print("")
print("宇宙速度")
print(" 地表における自転速度: vrot = {:14.4g} m/s".format(vrot))
print(" 地球の公転速度 : vrev = {:14.4g} m/s".format(vrev))
print(" 第一宇宙速度 : v1 = {:14.4g} m/s".format(v1))
print(" 第二宇宙速度 : v2 = {:14.4g} m/s".format(v2))
print(" 公転脱出速度 : vrev3 = {:14.4g} m/s".format(vrev3))
print(" 第三宇宙速度 : v3 = {:14.4g} m/s".format(v3))
# 初期状態におけるエネルギー保存則関係の計算
# 重力のポテンシャルエネルギー
EU = -G * Me * mc / Re
# 運動エネルギー
EK = 0.5 * mc * v0 * v0
# 全エネルギー
Etot = EU + EK
# 最大到達高度 hmax: Etot = -G * Me * mc / (Re + hmax) => hmax = -Re - G * Me * mc / Etot
hmax = -Re - G * Me * mc / Etot
print("")
print("初期状態")
print(" 重力のポテンシャルエネルギー: EU = {:14.4g} J".format(EU))
print(" 運動エネルギー : EK = {:14.4g} J".format(EK))
print(" 全エネルギー : Etot= {:14.4g} J".format(Etot))
print("最大到達高度: hmax = {:14.4g} m".format(hmax))
# 初期値を配列に設定
t = [0.0]
vx = [vx0]
vy = [vy0]
x = [0.0]
y = [Re]
# グラフの作成
fig = plt.figure(figsize = (8, 8))
ax1 = fig.add_subplot(1, 1, 1)
ax1.set_xlabel("x (m)", fontsize = fontsize)
ax1.set_ylabel("y (m)", fontsize = fontsize)
ax1.set_aspect('equal')
ax1.tick_params(labelsize = fontsize)
plotdata, = ax1.plot(x, y, linestyle = '-', linewidth = 0.5, marker = 'o', markersize = 2.0)
# 地表を描画
Qg = range(361)
xg = [Re * sin(iQg * pi / 180.0) for iQg in Qg]
yg = [Re * cos(iQg * pi / 180.0) for iQg in Qg]
ax1.plot(xg, yg, linestyle = '-', linewidth = 0.5, color = 'red')
# 計算ループ開始
print("")
print("{:8}: {:10}\t{:10}\t{:10}\t{:10}\t{:10}\t{:10}\t{:10}"
.format('t(s)', 'vx(m/s)', 'vy(m/s)', 'x(m)', 'y(m)', 'Ekin(J)', 'EU(J)', 'Etot(J)'))
for i in range(1, nmax):
tt = i * dt
# m(vx[i] - vx[i-1]) / dt = 0
# m(vy[i] - vy[i-1]) / dt = -mg
fx, fy = force(x[i-1], y[i-1])
vxt = vx[i-1] + dt * fx / mc
vyt = vy[i-1] + dt * fy / mc
# (x[i] - x[i-1]) / dt = vx[i-1]
# (y[i] - y[i-1]) / dt = vy[i-1]
xt = x[i-1] + dt * vx[i-1]
yt = y[i-1] + dt * vy[i-1]
vx.append(vxt)
vy.append(vyt)
x.append(xt)
y.append(yt)
# エネルギー保存則の確認: 計算誤差があるので、計算結果では全エネルギーは一定にならない
Ekin = 0.5 * mc * (vxt * vxt + vyt * vyt)
EU = -G * Me * mc / sqrt(xt*xt + yt*yt)
Etot = Ekin + EU
print("{:8g}: {:10.4g}\t{:10.4g}\t{:10.4g}\t{:10.4g}\t{:10.4g}\t{:10.4g}\t{:10.4g}"
.format(tt, vxt, vyt, xt, yt, Ekin, EU, Etot))
# グラフの表示データを更新
plotdata.set_data(x, y)
# グラフ表示を更新
ax1.set_xlim([min(x), max(x)])
ax1.set_ylim([min(y), max(y)])
plt.tight_layout()
plt.pause(tsleep)
# 地表に激突したら計算ループ終了
r = sqrt(xt * xt + yt * yt)
if r < Re:
break
print("プログラムを終了するにはENTERキーを押してください")
input()
usage()
print("")
if __name__ == "__main__":
main()