
# Import Python Modules
import numpy as np # 数値計算ライブラリ
import matplotlib.pyplot as plt # 描画ライブラリ
from scipy.integrate import odeint # 常微分方程式を解くライブラリ
# 定数
# G = 6.67430 * 10 **(-20) [km^3 kg^-1 s^-2] 万有引力定数(km)
# M = 5.972 * 10 ** 24 # [kg] 地球質量
GM = 398600 # [km^3 s^-2] 地球の重力定数
# 二体問題の運動方程式
def func(x, t):
r_E = np.linalg.norm([x[0],x[1],x[2]])
dxdt = [x[3],
x[4],
x[5],
-GM*x[0]/(r_E**3),
-GM*x[1]/(r_E**3),
-GM*x[2]/(r_E**3)]
return dxdt
# 微分方程式の初期条件
x0 = [6400, 0, 0, 0, 9, 0] # 位置(x,y,z)+速度(vx,vy,vz)
t = np.linspace(0, 30000, 1000) # (開始、終了、ステップ数) 1日分 軌道伝播
# 微分方程式の数値計算
sol = odeint(func, x0, t)
# 二次元描画
fig = plt.figure()
ax = fig.add_subplot(1, 1, 1)
ax.set_xlabel('km')
ax.set_ylabel('km')
#地球をプロット
ax.plot(0,0,'.', c='black') #点をプロットする場合
ax.plot(sol[:, 0],sol[:, 1], 'black') #numpyのnparrayの記法で、各時間の0列目(x座標)、1列目(y座標)を抽出
ax.set_aspect('equal') # グラフのアスペクト比を揃える
plt.savefig('orbit.png') # 画像を保存
plt.show()
kmで計算しているので、万有引力定数が-11乗でなく-20乗になっている。万有引力を万有引力定数Gと地球質量Mから計算すると誤差が大きくなるため、重力定数GMとしてハードコードしている

# Import Python Modules
import numpy as np # 数値計算ライブラリ
import matplotlib.pyplot as plt # 描画ライブラリ
from scipy.integrate import odeint # 常微分方程式を解くライブラリ
from matplotlib import patches
# 定数
# G = 6.67430 * 10 **(-20) [km^3 kg^-1 s^-2] 万有引力定数(km)
# M = 5.972 * 10 ** 24 # [kg] 地球質量
GM = 398600 # [km^3 s^-2] 地球の重力定数
R = 6378
# 二体問題の運動方程式
def func(x, t):
r_E = np.linalg.norm([x[0],x[1],x[2]])
dxdt = [x[3],
x[4],
x[5],
-GM*x[0]/(r_E**3),
-GM*x[1]/(r_E**3),
-GM*x[2]/(r_E**3)]
return dxdt
# 微分方程式の初期条件
x0 = [R+600, 0, 0, 0, 9, 0] # 位置(x,y,z)+速度(vx,vy,vz)
t = np.linspace(0, 30000, 1000) # (開始、終了、ステップ数) 1日分 軌道伝播
# 微分方程式の数値計算
sol = odeint(func, x0, t)
# 二次元描画
fig = plt.figure()
ax = fig.add_subplot(1, 1, 1)
ax.set_xlabel('km')
ax.set_ylabel('km')
#地球をプロット
c = patches.Circle( (0,0), R)
ax.add_patch(c)
# ax.plot(0,0,'.') #点をプロットする場合
ax.plot(sol[:, 0],sol[:, 1], 'black') #numpyのnparrayの記法で、各時間の0列目(x座標)、1列目(y座標)を抽出
ax.set_aspect('equal') # グラフのアスペクト比を揃える
plt.savefig('orbit.png') # 画像を保存
plt.show()

# Import Python Modules
import numpy as np # 数値計算ライブラリ
import matplotlib.pyplot as plt # 描画ライブラリ
from scipy.integrate import odeint # 常微分方程式を解くライブラリ
# 定数
# G = 6.67430 * 10 **(-20) [km^3 kg^-1 s^-2] 万有引力定数(km)
# M = 5.972 * 10 ** 24 # [kg] 地球質量
GM = 398600 # [km^3 s^-2] 地球の重力定数
# 二体問題の運動方程式
def func(x, t):
r_E = np.linalg.norm([x[0],x[1],x[2]])
dxdt = [x[3],
x[4],
x[5],
-GM*x[0]/(r_E**3),
-GM*x[1]/(r_E**3),
-GM*x[2]/(r_E**3)]
return dxdt
# 微分方程式の初期条件
x0 = [6000, 0, 0, 0, 8, 1] # 位置(x,y,z)+速度(vx,vy,vz)
t = np.linspace(0, 30000, 1000) # (開始、終了、ステップ数) 1日分 軌道伝播
# 微分方程式の数値計算
sol = odeint(func, x0, t)
# 三次元描画
fig = plt.figure()
ax = fig.add_subplot(1, 1, 1, projection='3d')
ax.plot(0,0,0,'.')#地球をプロット
ax.plot(sol[:, 0], sol[:, 1], sol[:, 2],linewidth = 0.5)
ax.set_aspect('equal') # グラフのアスペクト比を揃える
plt.show()
初速のz成分を0km/sから1km/sに変更し、三次元でプロットした

import numpy as np
import matplotlib.pyplot as plt
import matplotlib.animation as animation
from scipy.integrate import odeint # 常微分方程式を解くライブラリ
GM_E = 398600 # km3/s2 地球の重力定数
L_E = [0,0,0]
def func(x, t):
r_E = np.linalg.norm([x[0]-L_E[0],x[1]-L_E[1],x[2]-L_E[2]])
dxdt = [x[3],
x[4],
x[5],
-GM_E*x[0]/(r_E**3),
-GM_E*x[1]/(r_E**3),
-GM_E*x[2]/(r_E**3)]
return dxdt
def update(i, x, y):
plt.plot(x[0:i], y[0:i],c="blue")
def draw():
# 微分方程式の初期条件
r0 = [6500, 0, 0, 0, 9, 0] # 位置(x,y,z)+速度(vx,vy,vz)
t = np.linspace(0, 10000, 1000) # 1日分 軌道伝播
sol = odeint(func, r0, t)
print("keisan owari")
# 抽出して二次元化
x1, y1, z1 = sol[:, 0], sol[:, 1], sol[:, 2]
x = x1[::10]
y = y1[::10]
fig = plt.figure() #figure objectを取得
plt.plot(0,0,'.',c='blue')# 地球をプロット
plt.xlim(min(x),max(x))
plt.ylim(min(y),max(y))
plt.gca().set_aspect('equal')
ani = animation.FuncAnimation(fig, update, fargs = (x, y), frames = len(x),interval = 10)
ani.save("orbit.gif", writer = 'pillow',fps=30)
draw()
mp4を書き出す場合は、writerをpillowから次のように変える
ani = animation.FuncAnimation(fig, update, fargs = (x, y), frames = len(x),interval = 10)
writer = animation.writers['ffmpeg'](fps=60, metadata=dict(artist='mika'), bitrate=200)
ani.save("orbit.mp4", writer = writer)
import numpy as np
import matplotlib.pyplot as plt
import matplotlib.animation as animation
from scipy.integrate import odeint # 常微分方程式を解くライブラリ
import glob
# G = 6.67430 * 10 **(-11) [m3 kg-1 s-2] 万有引力定数(mksa)
# G = 6.67430 * 10 **(-20) [km3 kg-1 s-2] 万有引力定数(km)
# ME = 5.972 * 10 ** 24 # [kg] 地球質量
# MM = 7.345 * 10 ** 22 # [kg] 月質量
MS = 1.989 * 10 ** 30 # [kg] 太陽質量
GM_E = 398600.4354360959 # [km3 s-2] 地球の重力定数
GM_M = 4902.8072 # [km3/s2] 月の重力定数
GM_S = 13.27 * 10 ** 10 # [km3 s-2] 太陽の重力定数
L_E = [0,0,0] # 地球の座標[km]
# R_SE = 1.496 * 10 ** 8 # [km] 地球公転半径
R_EM = 3.8 * 10 ** 5 # [km] 月公転半径
# A = 5.927 * 10 ** -6 # [km s-2] 地球付近での太陽重力の加速度
# GM_S/R_SE
W = 2*np.pi/(86400*365)
w = 2*np.pi/(86400*30)
gradA = 17.74 * 10 ** (-14) # GM_S/R_SE ** 3 # [km s-2] 地球付近での太陽重力と遠心力による加速度の傾斜 GM_S/R_SE**2 + W**2
def L_M(t):
# 月の運動
offset = 170/360 * 2*np.pi
return [-384400*np.cos(w*t+offset),-384400*np.sin(w*t+offset),0]
def F(r, t):
r_E = np.linalg.norm([r[0]-L_E[0],r[1]-L_E[1],r[2]-L_E[2]])
r_M = np.linalg.norm([r[0]-L_M(t)[0],r[1]-L_M(t)[1],r[2]-L_M(t)[2]])
LM = L_M(t)
dxdt = [r[3],
r[4],
r[5],
GM_E*(L_E[0]-r[0])/(r_E**3) + GM_M*(LM[0]-r[0])/(r_M**3) + gradA * r[0] * np.cos(W*t),
GM_E*(L_E[1]-r[1])/(r_E**3) + GM_M*(LM[1]-r[1])/(r_M**3) + gradA * r[1] * np.sin(W*t),
GM_E*(L_E[2]-r[2])/(r_E**3) + GM_M*(LM[2]-r[2])/(r_M**3)]
return dxdt
def update(i, x, y, unittime,framew):
t = i*unittime
LM = L_M(t)
plt.cla() #現在描写されているグラフを消去
plt.plot(0,0,0,'.',c='blue')# 地球をプロット
plt.plot(LM[0]*np.cos(framew*t)+LM[1]*np.sin(framew*t),
-LM[0]*np.sin(framew*t)+LM[1]*np.cos(framew*t),
'.',c='red')# 月をプロット
plt.xlim(-2000000,1500000)
plt.ylim(-1500000,1500000)
plt.plot(x[0:i], y[0:i],c="blue") #plot
plt.text(-1500000,-1000000,f'day = {int(t/86400)}', fontsize=10)
def draw():
# 微分方程式の初期条件r0
v0 = 11.48964 #初速12.5922 12.592
h0 = 6000 # 初期高度
th0 = np.pi*1 # 初期位置の経度(太陽側が0、反時計回り)
r0 = [-h0*np.cos(th0), -h0*np.sin(th0), 0, v0*np.sin(th0), -v0*np.cos(th0), 0] # 位置[km](x,y,z)+速度[km/s](vx,vy,vz)
# 微分方程式の計算設定
timeRange = int(86400 * 320) #時間範囲[s] (参考 1d=86400s)
calcStep = 40 #時間ステップ[s]
t = np.linspace(0, timeRange, int(timeRange/calcStep)) # 時間範囲(開始[s],終了[s],分割数)
# 微分方程式を解く
sol = odeint(F, r0, t) # [x, y, z, u, v, w]
# print(sol[5])
x1 = []
y1 = []
z1 = []
framew = W
for i, raw in enumerate(sol):
t = i*calcStep
x1.append(raw[0]*np.cos(framew*t) + raw[1]*np.sin(framew*t))
y1.append(-raw[0]*np.sin(framew*t) + raw[1]*np.cos(framew*t))
z1.append(raw[2])
# 動画保存用にフレームを抜き出す
skiprate = int(1440/calcStep*15) #144skiprateで、60fps 10秒step計算で1秒が一日になる
x = x1[::skiprate]
y = y1[::skiprate]
dic = calcStep*skiprate
fig = plt.figure() #figure objectを取得
plt.gca().set_aspect('equal')
ani = animation.FuncAnimation(fig, update, fargs = (x, y,dic,framew), frames = len(x),interval = 10)
# savemp4(ani,'ww.mp4')
savegif(ani,'16.gif')
# savemp4(ani,getname())
def getname():
filelist = [int(filename.split('.')[0].replace('test','')) for filename in glob.glob('*.mp4')]
return f'test{max(filelist)+1}.mp4'
def savemp4(ani,filename):
writer = animation.writers['ffmpeg'](fps=60, metadata=dict(artist='mika'), bitrate=200)
ani.save(filename, writer = writer)
def savegif(ani,filename):
ani.save(filename, writer = 'pillow', fps=30)
draw()