我制作了一个模拟太阳系中物体运动的程序,然而,我的结果却出现了各种不准确之处。
我认为它可能与我的集成方法有关。
<小时/> tl; dr我的模拟和NASA数据之间的地球位置和速度之间略有差异,如果你能查看我下面的代码并告诉我数学是否错误。
我运行的测试是10天(864000秒)模拟,从Thu Mar 13 18:30:59 2006
开始,到Thu Mar 23 18:30:59 2006
结束。
模拟结束后,该计划报告了以下地球统计数据:
Earth position: (-1.48934630382e+11, -7437423391.22)
Earth velocity: (990.996767368, -29867.6967867)
测量单位当然是米/米/秒。
我使用了HORIZONS系统来获取太阳系中Thu Mar 13 18:30:59 2006
的大多数大体的起始位置和速度向量,并将它们放入模拟中。
测试结束后,我再次查询HORIZONS的Thu Mar 23 18:30:59 2006
地球数据,得到了以下结果:
Earth position: (-1.489348720130393E+11, -7437325664.023257)
Earth velocity: (990.4160633376971, -2986.736541327986)
如您所见,结果的前四位数几乎总是相同。然而,这仍然是一个非常大的错过!我很担心,因为我必须模拟几年的时间,错误可能会升级。
请您查看我的模拟核心并告诉我数学是否不正确?
def update (self, dt):
"""Pushes the uni 'dt' seconds forward in time."""
self.time += dt
for b1, b2 in combinations(self.bodies.values(), 2):
fg = self.Fg(b1, b2)
if b1.position.x > b2.position.x:
b1.force.x -= fg.x
b2.force.x += fg.x
else:
b1.force.x += fg.x
b2.force.x -= fg.x
if b1.position.y > b2.position.y:
b1.force.y -= fg.y
b2.force.y += fg.y
else:
b1.force.y += fg.y
b2.force.y -= fg.y
for b in self.bodies.itervalues():
ax = b.force.x/b.m
ay = b.force.y/b.m
b.position.x += b.velocity.x*dt
b.position.y += b.velocity.y*dt
nvx = ax*dt
nvy = ay*dt
b.position.x += 0.5*nvx*dt
b.position.y += 0.5*nvy*dt
b.velocity.x += nvx
b.velocity.y += nvy
b.force.x = 0
b.force.y = 0
我有这个方法的另一个版本,应该表现更好,但它的表现要差得多:
def update (self, dt):
"""Pushes the uni 'dt' seconds forward in time."""
self.time += dt
for b1, b2 in combinations(self.bodies.values(), 2):
fg = self.Fg(b1, b2)
if b1.position.x > b2.position.x:
b1.force.x -= fg.x
b2.force.x += fg.x
else:
b1.force.x += fg.x
b2.force.x -= fg.x
if b1.position.y > b2.position.y:
b1.force.y -= fg.y
b2.force.y += fg.y
else:
b1.force.y += fg.y
b2.force.y -= fg.y
for b in self.bodies.itervalues():
#Acceleration at (t):
ax = b.force.x/b.m
ay = b.force.y/b.m
#Velocity at (t):
ovx = b.velocity.x
ovy = b.velocity.y
#Velocity at (t+dt):
nvx = ovx + ax*dt
nvy = ovy + ay*dt
#Position at (t+dt):
b.position.x = b.position.x + dt*(ovx+nvx)/2
b.position.y = b.position.y + dt*(ovy+nvy)/2
b.force.null() #Reset the forces.
答案 0 :(得分:11)
集成方法非常很重要。您正在使用Euler显式方法,该方法具有低阶精度,对于正确的物理模拟而言太低。现在,你得到了选择
此外,对于大量步骤,时间=时间+ dt将具有增加的精度损失。考虑time = epoch * dt,其中epoch是一个整数,会使时间变量的精度与步数无关。