首页 > 解决方案 > 物理/向量问题 - 太阳系运动、向量和标量计算

问题描述

我正在处理一个课堂问题,要求我在 3D 空间中模拟太阳系内行星/卫星/小行星的运动。我们在学期的早些时候开始使用向量、质量和力,所以我仍在努力掌握它。

*我的问题在下面的第 4 步和第 5 步中有详细说明。如果我在此过程中遇到任何问题,请告诉我。任何输入和指导将不胜感激。

空间中的每个物体都有以下内容:

我必须使用牛顿万有引力定律:

F = G * mass1 * mass2 / distance^2

给定时间 t 更新空间中每个对象的位置和速度。因此,如果 t 是 10 秒,那么在给定时间,这些物体在太空中的什么位置?

我被告知在整个 t 中将加速度视为常数。为了简单起见,不要担心对象碰撞和对象可能非常小。给定空间中的对象可能是 1 到 100。

我不确定到目前为止我是否做得对,但这是我到目前为止所采取的步骤:

第 1 步:如果是 2 个对象,那么我会使用力公式。但是因为它是 X 数量的对象,所以我正在遍历每个对象,并且我正在计算自身与其他所有对象之间的力。我正在将这些添加到网络力量中。

第 2 步:我正在计算我的加速度:

a = Net Force / Mass

第 3 步:接下来我计算最终速度:

V = u + a*t u = 初始速度

第四步:计算物体的最终位置:

s = s0 + u*t + 1/2*a*t^2 

s0 = 初始位置,u = 初始速度

第 5 步:在其余对象上重复该过程

我的问题在第 4 步和第 5 步。我的位置和速度是向量。但是加速度是一个标量,所以我知道我不能把它加到向量上。那么我在这里做什么呢?我是否对每个矢量分量进行计算,然后将所有分量放回新的最终速度和最终位置矢量?我非常感谢您的帮助和任何意见。

标签: math3dsimulationphysicsorbital-mechanics

解决方案


首先看这个QA:

对于动态 n 体轨道力学,您的步骤完全错误!

因为您的身体沿曲线移动您需要使用Newton D'ALembert 积分来迭代积分,而不是立即计算整个事物,因为方向和力会沿途变化,否则您的轨道会扭曲甚至旋转或偏离晒太阳甚至及时逃走。还有一些集成方法可以为此保留能量……

此外,您必须在任何计算更改您的身体位置之前计算来自所有身体的所有力,否则您将实施错误的方向,因为一些已经计算的身体处于新位置而其他身体还没有。这通常会给卫星等近距离天体带来问题,或者飞过......

我改用这个逻辑:

  1. 对于每个身体,您需要拥有这些:

    struct _body
     {
     double mass;
     dvec3 pos; // position
     dvec3 vel; // velocity
     dvec3 acc; // acceleration
     } body[n];
    

    为此也至少使用 64 位double浮点数。如果你有更多它甚至更好,因为即使是 64 位浮点数也处于这种计算的极限。

  2. 对于每个身体计算加速度

    所以简单地总结每个物体的所有加速度

    for (i=0;i<n;i++) body[i].acc = dvec3(0,0,0);
    for (i=0;i<n;i++)
     for (j=i+1;j<n;j++) 
      {
      dvec3 d = body[i].pos - body[j].pos;
      dvec3 F = G * body[i].mass * body[j].mass * d / pow(length(d),3);
      body[i].acc -= F/body[i].mass; // the same force is aplied to both bodies
      body[j].acc += F/body[j].mass; // just in reverse direction
      }
    

    d / pow(length(d),3);将为您提供方向d和大小的向量1/d^2。其中length(d)=sqrt(d.x*d.x + d.y*d.y + d.z*d.z)此项将您的标量方程转换为向量一...

    您还可以为d大小添加一些健全性检查,这样一旦您的身体相互碰撞,您就可以避免除以太小或零值...

  3. 现在您为每个身体应用更改

    for (i=0;i<n;i++)
      {
      // Newton D'ALembert integration
      body[i].vel += body[i].acc*dt; // this is instead of V = u + a*t
      body[i].pos += body[i].vel*dt; // this is instead of s = s0 + u*t + 1/2*a*t^2
      }
    

    您的迭代时间步长在哪里dt,例如 0.1 秒(或计时器间隔或经过或模拟的时间步长)迭代时间步长会极大地影响精度所以如果您需要更高的精度,我建议使用上面链接答案中的精度增强技巧,它可以极大地改善事情没有明显降低dt

    另请注意,步骤 #2 和 #3 位于单独的循环中,不要将它们合并在一起,这一点至关重要!

  4. 去#2

    所以你在你的模拟过程中使用计时器重复步骤#2,#3sleep(dt) ,或者使用你的模拟引擎用于计时的一些或任何机制的线程。


推荐阅读