Невозможно получить правильную орбиту на моей модели солнечной системы - PullRequest
2 голосов
/ 05 августа 2020

Я делаю модель солнечной системы, используя только 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 перпендикулярно оси x A и позволяю им взаимодействовать. на этот раз 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);
  }
}

1 Ответ

1 голос
/ 05 августа 2020

первая проблема обычно вызвана слишком большим временным шагом симуляции в сочетании с отсутствующей обработкой коллизий. когда ваши объекты приближаются, силы становятся большими, и шаг приращения в моделировании становится слишком большим, поэтому следующая итерационная позиция находится после столкновения и обычно дальше, чем до него, поэтому разрушающая сила меньше, что приводит к все большим и большим орбитам во времени. .

Чтобы исправить это, вы можете:

  • добавить обработку столкновений
  • ограничить максимальную скорость или силу до некоторого разумного предела

Я никогда не сталкивался с вашей второй проблемой , и без кода я даже не могу догадаться ... кроме ошибок округления

Взгляните на это:

а также все там подссылки ...

[Edit1] после того, как я увидел ваш код

Архитектура кода выглядит нормально, проблема в том, что ваши уравнения немного неверны. он должен быть:

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

вместо вашего:

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

, поэтому вы ошиблись порядком и пропустили *dt , где dt - временной шаг. Из-за этого, независимо от того, как вы меняете интервал таймера, результат один и тот же (только медленнее / быстрее), а также направление ускорения применяется на один шаг позже, чем должно вызывать вращение орбиты (потому что ускорение было вычислено из другого положения, чем оно был применен к конечной позиции, поэтому его направление всегда выключено).

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...