【问题标题】:Unable to get a proper orbit on my solar system model无法在我的太阳系模型上获得正确的轨道
【发布时间】:2020-08-05 04:58:03
【问题描述】:

我正在制作一个仅使用 p5.js 而没有 box2D 的太阳系模型,尽管语言/平台对于这个问题并不重要。此外,用于描述问题的所有数字和变量并非 100% 准确,但行为是相同的。

我使用牛顿公式 ( F = G Mm / r^2 ) 来找到两个物体之间的相互引力,比如 A 和 B。现在为了将 A 吸引到 B,我将这个相互引力除以 A 的质量来找到A 上的向心加速度,然后将其乘以指向 B 的单位向量。将此关系应用于 A 和 B 时,它们都会相互吸引,与它们的质量成反比。

现在,如果我让它们彼此相互作用,A 的质量 = 1000 单位,B 的质量 = 10 单位,正如预期的那样,A 不会被拉动并保持静止,但 B 会向 A 加速。现在会发生什么当 B 到达中心并朝相反的方向飞行时,它会比我最初放置的距离更远。这在每个加速周期中都会滚雪球,并且在某些时候会离开屏幕。这似乎违反了能量守恒或我的物理学中的一些重大缺陷。

好的,然后继续第二个问题,我们有相同的对象和质量。不同之处在于我给 B(较轻的物体)某个值的初始速度,例如在 x 轴的正方向上的 x。现在我将 B 垂直于 A 的 x 轴并让它们相互作用。这一次,B 在一种椭圆轨道上运动,有两个问题。首先是A(较重的物体)不在椭圆的焦点之一,而是在它的确切中心,其次是随着时间的推移,轨道本身开始旋转。我觉得这种旋转是由提供的初始速度引起的,为了清楚起见,速度仅在最初应用,而不是在每一帧上应用。该轨道的轨迹如下:

还要注意每个轨道的最大范围如何比前一个多一点。这几乎就是之前的问题。

我目前正在尝试的下一件事是,应用与运动相切的恒定速度以及重力向心加速度。让我知道这是否有用,或者我的整个方法是否需要改变。

这也是我的模拟代码:

var constG;
var axisX;
var planets = [];

function setup() {
  createCanvas(500, 500);
  //createCanvas(displayWidth, displayHeight);
  //fullscreen(true);
  constG = 0.0001;//6.67 * pow(10, -11);
  axisX = createVector(1, 0);
}

function draw() {
  background(0, 5);
  for (var planet of planets) {   
    planet.update();
    planet.display();
  }

  for (var i = 0; i < planets.length; i++){
    var selfPlanet = planets[i];
    for (var j = 0; j < planets.length; j++){
      if (j == i){
        continue;
      }
      var otherPlanet = planets[j];
      var gravitalAcc = calcGravitalAcc(selfPlanet, otherPlanet);
      selfPlanet.applyForce(gravitalAcc);
    }
  }
  
  if (planets.length > 0){
    planets[0].radius = 15;
    planets[0].mass = 100;    // this just makes the first planet heavy so that i 
    planets[0].vel.mult(0);   // can test stuff while making it the sun.
    planets[0].speed = 0;
  }
}

function mousePressed() {
    planets.push(new CelestialBody(mouseX, mouseY, 7));
}

function calcGravitalAcc(self, other){
  var tempVec = p5.Vector.sub(other.pos, self.pos);
  return tempVec.normalize().mult(constG * (other.mass)/pow(tempVec.mag(), 2))
}

这是 Celestialbody 类,只是简单物理模拟中的任何典型类:

class CelestialBody {
  constructor(x, y, radius) {
    this.pos = createVector(x, y);
    this.radius = radius;
    this.color = color(255);
    
    this.mass = 1;
    this.speed = 1;
    this.vel = createVector(1, 0) //p5.Vector.random2D();
    this.vel.setMag(this.speed);
    this.acc = createVector(0, 0);
  }

  display() {
    fill(this.color);
    stroke(this.color);
    circle(this.pos.x, this.pos.y, this.radius * 2);
  }

  update() {
    this.pos.add(this.vel);
    this.vel.add(this.acc);
    this.acc.mult(0);
  }
  
  applyForce(vForce){
    this.acc.add(vForce);
  }
}

【问题讨论】:

    标签: math simulation physics orbital-mechanics


    【解决方案1】:

    第一个问题通常是由于模拟的时间步长过大以及缺少碰撞处理造成的。当您的物体靠近时,力会变大并且模拟中的增量步骤变得太大,因此下一个迭代位置是在碰撞之后并且通常比碰撞之前更远,因此破坏力更小,导致轨道越来越大。 .

    您可以采取的补救措施:

    • 添加碰撞处理
    • 将最大速度或力量限制在合理的范围内

    我从来没有遇到过你的第二个问题,没有代码我什至无法猜测......除了舍入错误

    看看这个:

    还有所有的子链接...

    在我看到你的代码之后[Edit1]

    代码的体系结构看起来不错,但问题是您的方程式略有偏差。应该是:

    vel+=acc*dt;
    pos+=vel*dt;
    acc=0.0;
    

    代替你的:

    pos+=vel;
    vel+=acc;
    acc=0.0;
    

    所以你的顺序有误,错过了*dt ,其中dt 是时间步长。因此,无论您如何更改计时器间隔,结果都是相同的(只是更慢/更快),并且加速度方向比应该导致轨道旋转晚一步(因为加速度是从不同的位置计算的而不是它被应用到最终位置,所以它的方向总是关闭)。

    【讨论】:

    • 对于第一个问题,我的时间步长非常低,我确实尝试在小数点后添加更多零,但我想即使是最小的错误也会发生。好的,那么我将暂时限制这些值。如果您想查看我的代码,我将编辑我的问题并将其放在那里。
    • 修复顺序确实有很大帮助,但与 dt 相乘会使它变得非常不可预测。我也尝试过 dt 的超高和低值。没关系,虽然我读了这篇关于轨道力学的论文并总结了我的问题 2,但螺旋呼啦圈的方向变化不是错误,而是现实中发生的事情。唯一的区别是变化是微不足道的。我更改了一些值并在我的 G 上工作,现在效果很好。感谢您抽出宝贵时间帮助我。
    • @Ontropy dt[s] 中,但为了使其正常工作,您需要将质量 G 恒定并将初始位置和速度设置为有效值/单位......你描述的轨道不会发生在牛顿达朗伯物理学中,它是由相对论效应引起的,不应该发生在你当前的模拟中。
    • @Ontropy 如果您查看有关太阳系模拟的链接 QA,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 可用于生成您的初始位置和速度 ...
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多