是否有可能在尺寸和质量方面进行逼真的n体太阳系模拟?

时间:2015-01-18 21:18:06

标签: simulation physics game-physics

重要提示:此问题与<#34; PhysX&#34; 完全没有 关系,这是一个计算机游戏物理系统(对物理有用)在街机游戏,如球类运动等); PhysX是Unity3D和其他游戏引擎内置的系统; PhysX在这里完全不相关。

////////////////////更新(先读到底部)/////////////////////

我一直在记录值并搜索确切问题的位置,我想我找到了它。 我的代码中有类似的东西

Velocity += Acceleration * Time.deltaTime;
position += Velocity * Time.deltaTime;

加速度就像0,0000000000000009 ..现在。当代码流动时,速度应该增加,浮动没有问题。 但是在开始时,地球的初始位置是(0,0,23500f)你可以在我最后给出的图表中看到这一点。

现在,当我将速度* timedelta(此时类似于0,00000000000000005)添加到23500的位置时,它基本上没有添加它。位置仍然是(0,0,23500)不像(0,0,23500.00000000000005),因此地球不会移动,因此加速度不会改变。

如果我将地球的初始位置设置为0,0,0并且仍然将加速度设置为0.0000000000000000009以使其保持位置为(0,0,23500) 然后&#34; ADDS&#34;速度* timedelta。 它变得类似于(0,0,000000000000000000005)并且继续增加。当float为0时,添加这么小的值没有问题。但是如果浮点数类似于23500,那么它就不会加上小值。

我不知道它是否完全是团结问题或c#的浮动。

这就是为什么我无法使用小值的方法。如果我能克服这一点,我的问题就会得到解决。

/////////////////////////////////////////////// ////////////////////////////////

我一直在开发n-body phyics来模拟我们的太阳系,所以我一直在收集数据,以使其尽可能逼真。但是数据大小存在问题。我搜索了每一点互联网,我无法找到一个解释人们如何克服这一点的单一解释。 (如果是这样的话)所以我在这里尝试拍摄。

因此,要保持距离,半径和&#34;质量&#34;的比率。在行星固定之间,我创建了一个excel文件来计算所有数据。 (因为有人为什么会放弃&#34;如果地球上有#34;那么&#34;半径图表&#34;在互联网上会是什么?) 我会把ss作为附件。它基本上&#34;规范化&#34;或换句话说&#34; scale&#34;行星的每个属性给定的参考。在这种情况下,我将参考作为&#34;地球的半径。&#34;

我团结一致,你知道,你可以和#34;太大&#34;或者&#34;太小&#34;统一的价值观。所以我不得不缩小太阳能系统,很多!&#34;

所以我使用牛顿万有引力定律,即F = GMm / r ^ 2, 为了简单起见,我直接计算a = GM / r ^ 2,来自所有其他身体的给定身体。

因此,地球引力加速度的真正价值在于对太阳的影响。大概是0,000006 km / s ^ 2,这甚至是非常小的价值,可以统一使用,但它可以工作。然而,为了获得这个值,1我需要将地球的半径(比例)设置为6371单位,并将太阳比例设置为696,342 !,这对于将它统一起来来说太大了。

所以我说,让地球的半径为1,以统一为单位。 所以,当半径变化时,一切都会改变,质量,距离...... 我保留了行星的密度,并用新半径计算新体积的质量。 所有计算都在附件中。

所以事实是,当我将地球的半径设为1时,对太阳的引力加速变为0,0000000000009 这太可笑了。当然,Unity并没有使用这个价值。

所以,如果我改变地球的半径,那么太阳的质量和半径变得非常大,然后再次,我无法使用它。

我不知道其他人如何解决这个问题,他们为解决这个问题做了什么,但正如我从这里看到的那样,看起来不可能对太阳系进行逼真的n体模拟。 (至少统一)

所以我需要10个代表发布图片-_-,我会给出链接。 http://berkaydursun.com/solar_system_simulator/data.PNG 另外一个目录是使用n体计算但具有UNREALISTIC值的工作实验太阳系模拟。 它工作得很好,甚至看起来有点接近真实,但不,它没有正确的比率^^ 如果您希望http://berkaydursun.com/solar_system_simulator/

,可以在此处进行测试

编辑:我几乎开始用#34;所以&#34; ^^

2 个答案:

答案 0 :(得分:13)

我也进行了程序溶胶系统模拟,所以这是我的见解:

  1. <强>渲染

    我使用 OpenGL 并使用 1:1 缩放。所有单位均为 SI ,因此 [m,s,kg,...] 。问题从 Z-buffer 开始。通常的 Z缓冲区位宽为16/24/32 bit,这远不是您所需要的。我正在从 0.1m到1000 AU 呈现,那么如何克服这个问题呢?

    我通过组合 Z-sorting Z-buffering 同时渲染了3个frustrum来管理它(由于透明环......需要Z-sort ...其他影响)。首先,我将最远的部分渲染到zfar=1000AU。天空圆顶投影在z=750AU距离,然后清除 Z缓冲区,并将对象渲染到zfar=0.1AU。然后再次清除 Z-buffer 并将近似对象渲染到zfar=100000 m

    要完成这项工作,您必须拥有尽可能精确的投影矩阵。 The gluPerspective has unprecise cotangens因此需要修复有关元素(让我花很长时间才能发现)。 Z near值取决于 Z-buffer 位宽。如果编码正确,那么即使使用缩放10000x也能正常工作。我使用这个程序作为矿山望远镜对象的导航/搜索器:)从我的家庭视图实时。我结合了3D星,天文体,船只,真实地面(通过DTM和卫星纹理)。它甚至能够产生红 - 青色立体输出:)。可以从表面,大气,空间渲染......(不仅仅是锁定在地球上)。没有其他第三方lib然后使用OpenGL。这是它的样子:

    img img img img img

    正如你所看到的,它可以在任何高度或缩放上正常工作,气氛就像这样atmosphere scattering shader

  2. <强>模拟

    我没有使用 n-body 重力模拟,因为你需要很多非常难以获得的数据(并且几乎不可能达到所需的精度)。计算必须非常准确

    我使用 Kepler方程式来代替看看:

    如果您仍想使用重力模型,请使用 NASA 中的 JPL视野。我认为他们在C / C ++中也有源代码,但他们使用不兼容的参考框架和我的地图,所以它对我来说无法使用。

    一般来说,开普勒方程的误差较大,但不会随着时间的推移而增加。重力模型更精确,但其误差随着时间的推移而增加,您需要不断更新天体数据以使其正常工作......

  3. [edit1]整合精度

    您当前的实施是这样的:

    // object variables
    double  acc[3],vel[3],pos[3];
    // timer iteration
    double dt=timer.interval;
    for (int i=0;i<3;i++)
     {
     vel[i]+=acc[i]*dt;
     pos[i]+=vel[i]*dt;
     }
    

    问题在于,当您添加非常小且非常大的值时,它们就是 在添加之前转移到相同的指数,这将使重要数据四舍五入 为了避免这种情况,只需将其更改为:

    // object variables
    double          vel0[3],pos0[3]; // low
    double          vel1[3],pos1[3]; // high
    double  acc [3],vel [3],pos [3]; // full
    // timer iteration
    double dt =timer.interval;
    double max=10.0; // precision range constant
    for (int i=0;i<3;i++)
     {
     vel0[i]+=acc[i]*dt; if (fabs(vel0[i]>=max)) { vel1[i]+=vel0[i]; vel0[i]=0.0; } vel[i]=vel0[i]+vel1[i];
     pos0[i]+=vel[i]*dt; if (fabs(pos0[i]>=max)) { pos1[i]+=pos0[i]; pos0[i]=0.0; } pos[i]=pos0[i]+pos1[i];
     }
    

    现在xxx0已整合到max,整个内容已添加到xxx1

    四舍五入仍然存在但不再累积。您必须选择集成本身安全的max值,并且添加xxx0+xxx1必须是安全的。因此,如果一个分裂的数字太不同,那么分割两次或更多......

    • 喜欢:xxx0+=yyy*dt; if (fabs(xxx0>max0))... if (fabs(xxx1>max1))...

    [Edit2]明星

    [Edit3]进一步提高Newton D&#39; ALembert集成精度

    迭代积分的基本问题是,基于当前身体位置来应用基于引力的加速将导致更大的轨道,因为在整合步骤dt中,位置改变了一点,这在初始积分中没有考虑。要解决这个问题,请看一下这张图片:

    integration

    假设我们的身体处于圆形轨道并处于0度位置。我没有使用基于当前位置的加速度方向,而是在0.5*dt之后使用了位置。这增加了加速度小位,从而产生了更高的精度(与开普勒轨道的对应关系)。通过这次调整,我能够成功地从开普勒轨道转换为Newton D&#39; Alembert,用于2体系。 (为n-body执行此操作是下一步)。与我们的太阳系的实际数据粗略相关只能用于不受​​潮汐效应和/或卫星影响的2体系统。要构建自己的虚构数据,您可以使用开普勒圆轨道和重力均衡重力:

    G = 6.67384e-11;
    v = sqrt(G*M/a);                           // orbital speed
    T = sqrt((4.0*M_PI*M_PI*a*a*a)/(G*(m+M))); // orbital period
    

    其中a是圆形轨道半径m是体重,M是焦点体质(太阳)。为了保持精度在可接受的容差范围内(对我而言),积分步骤dt应为:

    dt = 0.000001*T
    

    所以把新的身体用于测试只需将它放在:

    pos = (a,0,0)
    vel = (0,sqrt(G*M/a),0)
    

    主要焦点身体(太阳)位于:

    pos = (0,0,0)
    vel = (0,0,0)
    

    这将使您的身体处于圆形轨道,这样您就可以比较Kepler与Newton D&#39; Alembert来评估模拟的精确度。

答案 1 :(得分:0)

如你所发现的,缩小规模并不一定有帮助。以下是使用浮点数时需要考虑的一些好的阅读材料:http://docs.oracle.com/cd/E19957-01/806-3568/ncg_goldberg.html

基本上根据第一原理(牛顿定律)进行模拟对于数值准确性是不利的,因为你不会想象数值方法对重要效应的规模的想法,所以你最终投掷不同尺度的一大堆不同效果,效果不佳。

通常像行星,卫星等星历表这样的东西不是从牛顿定律开始的,它们首先假设轨道是开普勒,然后是小的扰动校正。

这是一个计算行星位置的算法(半永久性)。 http://ssd.jpl.nasa.gov/txt/aprx_pos_planets.pdf

如果你想进行N体模拟,你似乎需要更高的精度。如果unity阻止你使用双精度,那么我建议用普通的C#进行计算,然后在作业完成后转换为单精度。