模拟行星绕太阳运行的轨迹。椭圆不闭合
Modeling the trajectory of the planet around the sun. Ellipse is not closing
我试图创建行星围绕太阳的投影。使用 RungeKutta 我正在尝试投影和创建 matplotlib 图。但是,out 椭圆没有关闭。你能帮我看看我到底哪里做错了吗?
使用 Runge Kutta 找到一个向量 R,其位置是时间的函数。当我使用绘图绘制轨迹时,它不会生成我应该找到的椭圆。
import numpy as np
import matplotlib.pyplot as plt
%matplotlib inline
#unités de normalisation
UA=149.59787e6 #distance moyenne Terre-Soleil
MASSE=6.0e24 #masse Terre
JOUR=24*3600
#données :
k=0.01720209895
G=(k**2) # constante de gravitation en km^3/kg/s²
r0= 1 # distance initiale terre soleil en m
Ms = 2.0e30/MASSE #masse Soleil
Mt = 1 #masse Terre
w0 = 30/(UA/JOUR) #vitesse angulaire en Km/s
C = r0*(w0**2)
m = (Ms*Mt/Ms+Mt) #masse réduite
K = G*m #on choisit K > 0
b = 2 #beta
def RK4(F, h, r, theta, t, *args):
k1=F(t,r,theta,)[0]
l1=F(t,r,theta,)[1]
k2=F(t+h/2,r+h*k1/2,theta+h*l1/2)[0]
l2=(t+h/2,r+h*k1/2,theta+h*l1/2)[1]
k3=F(t+h/2,r+h*k2/2,theta+h*l2/2)[0]
l3=F(t+h/2,r+h*k2/2,theta+h*l2/2)[1]
k4=F(t+h,r+h*k3,theta+h*l3/2)[0]
l4=F(t+h,r+h*k3,theta+h*l3/2)[1]
return [r +(h/6)*(k1+2*k2+2*k3+k4),theta +(h/6)*(l1+2*l2+2*l3+l4)]
def F1(t,r,theta):
return np.array([r[1],r[0]*theta[1]**2-K/r[0]**b]),np.array([theta[1],-2*r[1]*theta[1]/r[0]])
def RK4N(F1,N,r0,r1,theta0,theta1,ta,tb):
h=0.05
ri=np.array([r0,r1])
thetai=np.array([theta0,theta1])
ti=ta
R=np.zeros((N,2))
THETA=np.zeros((N,2))
lt=np.zeros(N)
lt[0], R[0],THETA[0] = ta , ri ,thetai
for i in range (1, N):
a = ri
ri = RK4(F1,h,ri,thetai,ti)[0]
thetai=RK4(F1,h,a,thetai,ti)[1]
ti=ti+h
R[i]=ri
THETA[i]=thetai
lt[i]=ti
return R,THETA,lt
def trace_position(F1,N,r0,r1,theta0,theta1,ta,tb):
R,THETA,lt=RK4N(F1,N,r0,r1,theta0,theta1,ta,tb)
lx,ly=[],[]
for i in range(N):
lx.append(R[i][0]*np.cos(THETA[i][0]))
ly.append(R[i][0]*np.sin(THETA[i][0]))
plt.plot(lx,ly)
plt.plot(0,0)
plt.show()
# rapport a/b
max_x,min_x,max_y,min_y= max(lx),min(lx),max(ly),min(ly)
rapport = (max_x-min_x)/(max_y-min_y)
print("rapport a/b = ",rapport)
if abs(rapport-1)< 10e-2:
print("le mouvement est presque circulaire")
else:
print("le mouvement est elliptique")
def trace_Ep(F1,N,r0,r1,theta0,theta1,ta,tb):
R,THETA,lt=RK4N(F1,N,r0,r1,theta0,theta1,ta,tb)
lEp = []
for i in range(N):
lEp.append(-K/R[i][0]**(b-1))
#fig, (ax1, ax2) = plt.subplots(1, 2)
#ax1.plot(lt,lEp)
#ax2.plot(R[:,0],lEp)
plt.plot(lt,lEp)
plt.show()
trace_position(F1,380,r0,0,0,w0,0,1)
输出:
Runge-Kutta 方法不能给你一个完美闭合的轨迹,因为存在能量漂移(能量逐渐减少)。
如果需要能量保持接近初始值,可以使用辛积分器。您可以在 Chris Rackauckas's answer on "What does 'symplectic' mean[...]".
中阅读更多相关信息
但是,正如 Lutz Lehmann 指出的那样,你的时间步长足够小,所以这不是你的轨迹不明显的原因关闭。此信息可能对其他人来说很有趣,因此我将此答案留在这里。
您犯了一个并不少见的复制粘贴错误。在
中有一个错误的二除法
k4=F(t+h,r+h*k3,theta+h*l3/2)[0]
l4=F(t+h,r+h*k3,theta+h*l3/2)[1]
另请注意 l2
行中缺少的 F
。
您可以缩短这些计算并避免冗余或重复计算,并将错误位置减少一半,方法是使用
中的元组赋值
k4,l4 = F(t+h,r+h*k3,theta+h*l3)
以后
ri, thetai = RK4(F1,h,ri,thetai,ti)
将步长计算更改为 h=(tb-ta)/N
可能最初打算,并使用 tb=150
获得闭环,对于细分的选择,通过 [=19= 获得越来越闭合的轨道]
for k in range(4):
N = [16,19,25,120][k]
plt.subplot(2,2,k+1,aspect='equal')
trace_position(F1,N,r0,0,0,w0,0,150)
我试图创建行星围绕太阳的投影。使用 RungeKutta 我正在尝试投影和创建 matplotlib 图。但是,out 椭圆没有关闭。你能帮我看看我到底哪里做错了吗?
使用 Runge Kutta 找到一个向量 R,其位置是时间的函数。当我使用绘图绘制轨迹时,它不会生成我应该找到的椭圆。
import numpy as np
import matplotlib.pyplot as plt
%matplotlib inline
#unités de normalisation
UA=149.59787e6 #distance moyenne Terre-Soleil
MASSE=6.0e24 #masse Terre
JOUR=24*3600
#données :
k=0.01720209895
G=(k**2) # constante de gravitation en km^3/kg/s²
r0= 1 # distance initiale terre soleil en m
Ms = 2.0e30/MASSE #masse Soleil
Mt = 1 #masse Terre
w0 = 30/(UA/JOUR) #vitesse angulaire en Km/s
C = r0*(w0**2)
m = (Ms*Mt/Ms+Mt) #masse réduite
K = G*m #on choisit K > 0
b = 2 #beta
def RK4(F, h, r, theta, t, *args):
k1=F(t,r,theta,)[0]
l1=F(t,r,theta,)[1]
k2=F(t+h/2,r+h*k1/2,theta+h*l1/2)[0]
l2=(t+h/2,r+h*k1/2,theta+h*l1/2)[1]
k3=F(t+h/2,r+h*k2/2,theta+h*l2/2)[0]
l3=F(t+h/2,r+h*k2/2,theta+h*l2/2)[1]
k4=F(t+h,r+h*k3,theta+h*l3/2)[0]
l4=F(t+h,r+h*k3,theta+h*l3/2)[1]
return [r +(h/6)*(k1+2*k2+2*k3+k4),theta +(h/6)*(l1+2*l2+2*l3+l4)]
def F1(t,r,theta):
return np.array([r[1],r[0]*theta[1]**2-K/r[0]**b]),np.array([theta[1],-2*r[1]*theta[1]/r[0]])
def RK4N(F1,N,r0,r1,theta0,theta1,ta,tb):
h=0.05
ri=np.array([r0,r1])
thetai=np.array([theta0,theta1])
ti=ta
R=np.zeros((N,2))
THETA=np.zeros((N,2))
lt=np.zeros(N)
lt[0], R[0],THETA[0] = ta , ri ,thetai
for i in range (1, N):
a = ri
ri = RK4(F1,h,ri,thetai,ti)[0]
thetai=RK4(F1,h,a,thetai,ti)[1]
ti=ti+h
R[i]=ri
THETA[i]=thetai
lt[i]=ti
return R,THETA,lt
def trace_position(F1,N,r0,r1,theta0,theta1,ta,tb):
R,THETA,lt=RK4N(F1,N,r0,r1,theta0,theta1,ta,tb)
lx,ly=[],[]
for i in range(N):
lx.append(R[i][0]*np.cos(THETA[i][0]))
ly.append(R[i][0]*np.sin(THETA[i][0]))
plt.plot(lx,ly)
plt.plot(0,0)
plt.show()
# rapport a/b
max_x,min_x,max_y,min_y= max(lx),min(lx),max(ly),min(ly)
rapport = (max_x-min_x)/(max_y-min_y)
print("rapport a/b = ",rapport)
if abs(rapport-1)< 10e-2:
print("le mouvement est presque circulaire")
else:
print("le mouvement est elliptique")
def trace_Ep(F1,N,r0,r1,theta0,theta1,ta,tb):
R,THETA,lt=RK4N(F1,N,r0,r1,theta0,theta1,ta,tb)
lEp = []
for i in range(N):
lEp.append(-K/R[i][0]**(b-1))
#fig, (ax1, ax2) = plt.subplots(1, 2)
#ax1.plot(lt,lEp)
#ax2.plot(R[:,0],lEp)
plt.plot(lt,lEp)
plt.show()
trace_position(F1,380,r0,0,0,w0,0,1)
输出:
Runge-Kutta 方法不能给你一个完美闭合的轨迹,因为存在能量漂移(能量逐渐减少)。
如果需要能量保持接近初始值,可以使用辛积分器。您可以在 Chris Rackauckas's answer on "What does 'symplectic' mean[...]".
中阅读更多相关信息但是,正如 Lutz Lehmann 指出的那样,你的时间步长足够小,所以这不是你的轨迹不明显的原因关闭。此信息可能对其他人来说很有趣,因此我将此答案留在这里。
您犯了一个并不少见的复制粘贴错误。在
中有一个错误的二除法k4=F(t+h,r+h*k3,theta+h*l3/2)[0]
l4=F(t+h,r+h*k3,theta+h*l3/2)[1]
另请注意 l2
行中缺少的 F
。
您可以缩短这些计算并避免冗余或重复计算,并将错误位置减少一半,方法是使用
中的元组赋值k4,l4 = F(t+h,r+h*k3,theta+h*l3)
以后
ri, thetai = RK4(F1,h,ri,thetai,ti)
将步长计算更改为 h=(tb-ta)/N
可能最初打算,并使用 tb=150
获得闭环,对于细分的选择,通过 [=19= 获得越来越闭合的轨道]
for k in range(4):
N = [16,19,25,120][k]
plt.subplot(2,2,k+1,aspect='equal')
trace_position(F1,N,r0,0,0,w0,0,150)