问题
I've been trying to solve the two body problem using rk4 in python. I have some problem with the plot however and can't seem to get an orbit instead it's just a slightly bent line.
I've tried to change the stepsize and initial values but it hasn't gotten me anywhere. Here is my code of the sun and earth system.
from __future__ import division
import numpy as np
from numpy import linalg as LA
import matplotlib.pyplot as plt
#from VPython import *
#from VPython.graph import *
AU=1.5e11
a=AU #semi major axis
e=0.1 #eccentricity
ms = 2E30
me = 5.98E24
h=10**(-6)
G=6.67e-11
step=600 #timestep
#sun=sphere(pos=vec(0,0,0),radius=0.1*AU,color=color.yellow)
#earth=sphere(pos=vec(1*AU,0,0),radius=0.1*AU)
sunpos=np.array([0,0,0])
earthpos=np.array([a,0,0])
#scene.range=1.3*AU
#scene.autoscale=0
earthv=np.array([0,35000,0])
sunv=np.array([0,-35000,0])
norme=np.sqrt(abs(earthpos[0]**2+earthpos[1]**2+earthpos[2]**2-sunpos[0]**2+sunpos[1]**2+sunpos[2]**2))
norma=np.sqrt(abs(-(earthpos[0]**2+earthpos[1]**2+earthpos[2]**2)+(sunpos[0]**2+sunpos[1]**2+sunpos[2]**2)))
eartha=G*ms*(earthpos-sunpos)/norme**3
suna=G*me*(sunpos-earthpos)/norma**3
xarray=[]
yarray=[]
zarray=[]
xarray.append(earthpos[0])
yarray.append(earthpos[1])
zarray.append(earthpos[2])
#trail = curve(color = earth.color)
#k1 = [vector(0,0,0),vector(0,0,0), vector(0,0,0), vector(0,0,0)]
#k2 = [vector(0,0,0),vector(0,0,0), vector(0,0,0), vector(0,0,0)]
#k3 = [vector(0,0,0),vector(0,0,0), vector(0,0,0), vector(0,0,0)]
#k4 = [vector(0,0,0),vector(0,0,0), vector(0,0,0), vector(0,0,0)]
t=0
T=10**9
while t<T:
k1v1=h*earthv
k1v2=h*sunv
k1a1=eartha
k1a2=suna
earthpos=earthpos+.5*k1v1
sunpos=sunpos+.5*k1v2
earthv=earthv+.5*k1a1
sunv=sunv+.5*k1a2
norme=np.sqrt(abs(earthpos[0]**2+earthpos[1]**2+earthpos[2]**2-sunpos[0]**2+sunpos[1]**2+sunpos[2]**2))
norma=np.sqrt(abs(-(earthpos[0]**2+earthpos[1]**2+earthpos[2]**2)+(sunpos[0]**2+sunpos[1]**2+sunpos[2]**2)))
eartha=G*ms*(earthpos-sunpos)/norme**3
suna=G*me*(sunpos-earthpos)/norma**3
k2v1=h*earthv
k2v2=h*sunv
k2a1=eartha
k2a2=suna
earthpos=earthpos+.5*k2v1
sunpos=sunpos+.5*k2v2
earthv=earthv+.5*k2a1
sunv=sunv+.5*k2a2
norme=np.sqrt(abs(earthpos[0]**2+earthpos[1]**2+earthpos[2]**2-sunpos[0]**2+sunpos[1]**2+sunpos[2]**2))
norma=np.sqrt(abs(-(earthpos[0]**2+earthpos[1]**2+earthpos[2]**2)+(sunpos[0]**2+sunpos[1]**2+sunpos[2]**2)))
eartha=G*ms*(earthpos-sunpos)/norme**3
suna=G*me*(sunpos-earthpos)/norma**3
k3v1=h*earthv
k3v2=h*sunv
k3a1=eartha
k3a2=suna
earthpos=earthpos+k3v1
sunpos=sunpos+k3v2
earthv=earthv+k3a1
sunv=sunv+k3a2
norme=np.sqrt(abs(earthpos[0]**2+earthpos[1]**2+earthpos[2]**2-sunpos[0]**2+sunpos[1]**2+sunpos[2]**2))
norma=np.sqrt(abs(-(earthpos[0]**2+earthpos[1]**2+earthpos[2]**2)+(sunpos[0]**2+sunpos[1]**2+sunpos[2]**2)))
eartha=G*ms*(earthpos-sunpos)/norme**3
suna=G*me*(sunpos-earthpos)/norma**3
k4v1=h*earthv
k4v2=h*sunv
k4a1=eartha
k4a2=suna
earthpos=earthpos+1/6*(k1v1+2*k2v1+2*k3v1+k4v1)
sunpos=sunpos+1/6*(k1v2+2*k2v2+2*k3v2+k4v2)
earthv=earthv+1/6*(k1a1+2*k2a1+2*k3a1+k4a1)
sunv=sunv+1/6*(k1a2+2*k2a2+2*k3a2+k4a2)
norme=np.sqrt(abs(earthpos[0]**2+earthpos[1]**2+earthpos[2]**2-sunpos[0]**2+sunpos[1]**2+sunpos[2]**2))
norma=np.sqrt(abs(-(earthpos[0]**2+earthpos[1]**2+earthpos[2]**2)+(sunpos[0]**2+sunpos[1]**2+sunpos[2]**2)))
eartha=G*ms*(earthpos-sunpos)/norme**3
suna=G*me*(sunpos-earthpos)/norma**3
xarray.append(earthpos[0])
yarray.append(earthpos[1])
zarray.append(earthpos[2])
t=t+step
plt.plot(xarray,yarray)
Here is the plot I'm getting.
回答1:
Please read again what the Euclidean distance is. In the most simple python implementation
norme=sum( (earthpos-sunpos)**2 )**0.5
That is, first compute the coordinate differences, then square them, then add them, then take the square root of the sum.
Also, it seems that you at no point multiply the accelerations with the step size.
The force directions seem to be pointing outwards, not inwards like an attracting force.
During the RK4 step, the base state is not to be changed, all modifications are relative to that unchanged base state.
To correct all that and make the code more compact, you can use the following ideas:
Define the gravitation force/acceleration computations as
def accelerations(earthpos, sunpos):
norme=sum( (earthpos-sunpos)**2 )**0.5
gravit = G*(earthpos-sunpos)/norme**3
suna = me*gravit
eartha = -ms*gravit
return eartha, suna
and then the RK4 step can be shortened to
eartha, suna = accelerations(earthpos, sunpos)
k1v1 = h*earthv
k1v2=h*sunv
k1a1=h*eartha
k1a2=h*suna
eartha, suna = accelerations(earthpos+0.5*k1v1, sunpos+0.5*k1v2)
k2v1 = h*(earthv+0.5*k1a1)
k2v2=h*(sunv+0.5*k1a2)
k2a1=h*eartha
k2a2=h*suna
eartha, suna = accelerations(earthpos+0.5*k2v1, sunpos+0.5*k2v2)
k3v1 = h*(earthv+0.5*k2a1)
k3v2=h*(sunv+0.5*k2a2)
k3a1=h*eartha
k3a2=h*suna
etc.
来源:https://stackoverflow.com/questions/57253590/plot-orbit-of-two-body-using-rk4