绘制 Space 随时间变化的船舶距离

Plotting Space Ship Distance over Time

我正在研究使用力、加速度和质量在笛卡尔地图上进行点对点宇宙飞船旅行的一些逻辑。船将以1G加速燃烧驶向目的地,在中途标记处翻转180度,并以1G减速到达目的地的相对停靠点。

我遇到的问题是使用船在加速或减速时经过的时间来确定 (x, y) 坐标。

以下是 ship 的规格:

ship = {
  mass: 135000, // kg
  force: 1324350, // Newtons
  p: { x: -1, y: -5 } // (x,y) coordinates
}

dest: {
  p: { x: 15, y: 30 }  // (x,y) coordinates
}

对于问题的第一部分,我计算到达目的地的时间:

var timeToDestination = function(ship, dest) {

  // calculate acceleration (F = ma)
  var acceleration = ship.force / ship.mass; // ~9.81 (1G)

  // calculate distance between 2 points (Math.sqrt((a - x)^2+(b - y)^2))
  var totalDistance = Math.sqrt(
    Math.pow(dest.p.x - ship.p.x, 2) + 
    Math.pow(dest.p.y - ship.p.y, 2)
  ); // 38.48376280978771

  // multiply grid system to galactic scale
  var actualDistance = totalDistance * 1e9; // 1 = 1Mkm (38,483,763km) Earth -> Venus

  // determine the mid-point where ship should flip and burn to decelerate
  var midPoint = actualDistance / 2;

  // calculate acceleration + deceleration time by solving t for each: (Math.sqrt(2d/a))
  return Math.sqrt( 2 * midPoint / acceleration ) * 2; // 125,266s or 34h or 1d 10h
}

第二部分有点棘手,在delta time 之后得到(x, y) 坐标。这是我卡住的地方,但这是我目前所拥有的:

var plotCurrentTimeDistance = function(ship, dest, time) {

  // recalculate acceleration (F = ma)
  var acc = ship.force / ship.mass; //~9.81m/s^2

  // recalculate total distance
  var distance = Math.sqrt(
    Math.pow(dest.p.x - ship.p.x, 2) + 
    Math.pow(dest.p.y - ship.p.y, 2)
  ) * 1e9; // 38,483,762,810m

  // get distance traveled (d = (1/2) at^2)
  var traveled = (acc * Math.pow(time, 2)) / 2;

  // get ratio of distance traveled to actualDistance
  var ratio = traveled / distance;

  // midpoint formula to test @ 50% time ((x+a)/2,(y+b)/2)
  console.log({ x: (ship.p.x+dest.p.x)/2, y: (ship.p.y+dest.p.y)/2})

  // get the point using this formula (((1−t)a+tx),((1−t)b+ty))
  return { 
    x: (( 1 - ratio ) * ship.p.x) + (ratio * dest.p.x), 
    y: (( 1 - ratio ) * ship.p.y) + (ratio * dest.p.y) 
  };
}

@50%时间,62633s点returns为(~7,~12.5),与returns为(~7,~12.5)的中点公式相匹配。但是,您输入的任何其他 distance/time 都会大错特错。我的猜测是加速打乱了计算,但我无法弄清楚如何更改公式以使其工作。谢谢你的时间。

首先,你说distance是总距离,其实是从船到目的地的剩余距离。我不完全理解你关于如何进行计算的计划,所以我会在下面提出一些不同的建议。

我们称起始位置为 start,它有一个 x 和 y 坐标:start.xstart.y。与 end 类似。

现在,要使这样的模拟正常工作,我们还需要船上的 属性 速度,所以

ship = {
    ...
    v : {x : 0, y : 0}
}

从休息开始,应该达到休息。理想情况下,它应该具有一般运动的加速度 a,但我们现在可以跳过它。我们会有两种不同的行为

  1. 飞船从静止开始,以9.8m/s^2加速向目标前进,直至到达半点。
  2. 船在中点以v的速度开始,以-9.8减速m/s^2朝向目标,直到速度为0。现在我们应该已经到达目标了。

我们使用 v = v_start + a*time 从加速度获取速度,我们使用 x = x_start + v*time 从速度获取位置。那么船的当前位置就是这两种情况

// Case 1
current = start + a*time*time
// the above is due to the fact that
//     current = start + v*time
// and the fact that v = v_start + a*time as I wrote previously,
// with v_start.x = v_start.y = 0

//Case 2
current = midpoint + (v_at_midpoint - a*time_since_midpoint)*time_since_midpoint

注意这里的 startcurrenta 是向量,所以它们会有 xy(并且可能 z) 坐标每个。

你通过以下算法得到的加速度

 a = (start - end)/totalDistance * 9.81 // 9.81 is the desired acceleration -- change it to whatever you want

如果你想了解上面的实际含义,它会计算出所谓的unit vector,它告诉我们力指向的方向

您现在需要做的事情如下:

  1. 计算总距离和加速度

  2. 根据函数中的输入 time,确定您是情况 1 还是情况 2。

  3. 到达中点后,存储速度和到达中点所需的时间,并使用它来确定情况 2 中的运动。

  4. 到达目的地后停下来,否则你最终会回到起点!

祝你好运!

P.S 我还要注意这里没有考虑 special relativity,所以如果你的距离相距太远,你将获得非物理速度。但是,如果你想考虑到这一点,它会变得更加混乱。

感谢@pingul,我能够根据他的建议获得答案。

var ship = {
  mass: 135000,
  force: 1324350,
  accel: 0,
  nav: {
   startPos: { x: 0, y: 0 },
    endPos: { x: 0, y: 0 },
   distanceToDest: 0,
    distanceTraveled: 0,
    departTime: 0,
    timeToDest: 0,
    arriveTime: 0,
    startDeceleration: 0
  }
};

var log = [];
var start = { x: -1, y: -5 };
var end = { x: 15, y: 30 };

var updateLog = function() {
 document.getElementById('ship').textContent = JSON.stringify(ship, null, 2);
 document.getElementById('pos').textContent = JSON.stringify(log, null, 2);
}

var plotCourse = function(ship, start, end) {

  // calculate acceleration (F = ma)
  var acceleration = ship.force / ship.mass; // ~9.81 (1G)

  // calculate distance between 2 points (Math.sqrt((a - x)^2+(b - y)^2))
  var totalDistance = Math.sqrt(
    Math.pow(end.x - start.x, 2) + 
    Math.pow(end.y - start.y, 2)
  ); // 38.48376280978771

  // multiply grid system to galactic scale
  var actualDistance = totalDistance * 1e9; // 1 = 1Mkm (38,483,763km) Earth -> Venus

  // determine the mid-point where ship should flip and burn to decelerate
  var midpoint = actualDistance / 2;
  
  // calculate acceleration + deceleration time by solving t for each: (Math.sqrt(2d/a))
  var time = Math.sqrt( 2 * midpoint / acceleration ) * 2; // 125,266s or 34h or 1d 10h
  
  // load data into ship nav
  ship.nav = {
   startPos: start,
    endPos: end,
   distanceToDest: actualDistance,
    timeToDest: time,
    startDeceleration: time / 2
  }
  ship.accel = acceleration

  //log it
 updateLog();  
};

var goUnderway = function(ship) {
 var arrivalEl = document.getElementById('arrivalTime');
  
 // set depart and arrive times
  var timeToDest = ship.nav.timeToDest * 1000; // convert to ms
  ship.nav['departTime'] = moment().valueOf(); // returns now as unix ms
  ship.nav['arriveTime'] = moment(ship.nav.departTime).add(timeToDest).valueOf();
  
  //log it
  arrivalEl.textContent = 'Your ship will arrive ' + moment(ship.nav.arriveTime).calendar();
 updateLog();  
};

var getPosition = function(ship, date) {
 var currentTime = date ? moment(date).valueOf() : moment().valueOf() // unix ms
  var elapsedTime = (currentTime - ship.nav.departTime) / 1000; // convert to s
  var remainingTime = (ship.nav.arriveTime - currentTime) / 1000;  // convert to s
  var distanceAtMidpoint = 0;
  var timeSinceMidpoint = 0;
  var pos = { x: 0, y: 0 };
  
  // calculate velocity from elapsed time
 if (elapsedTime < ship.nav.startDeceleration) {
  
   // if ship is accelerating use this function
    ship.nav.distanceTraveled = 0 + ship.accel * Math.pow(elapsedTime, 2) / 2;
  } else if (elapsedTime > ship.nav.startDeceleration) {
  
   // else if ship is decelerating use this function
   distanceAtMidpoint = 0 + ship.accel * Math.pow(ship.nav.startDeceleration, 2) / 2; // distance at midpoint
    timeSinceMidpoint = elapsedTime - ship.nav.startDeceleration;
   ship.nav.distanceTraveled = distanceAtMidpoint + ship.accel * Math.pow(timeSinceMidpoint, 2) / 2;
  }
  
  if (remainingTime <= 0) {
   ship.force = ship.vel = ship.accel = 0;
    pos = ship.nav.endPos;
  } else {
    // get ratio of distance traveled to actualDistance
    var ratio = ship.nav.distanceTraveled / ship.nav.distanceToDest;
   // get the point using this formula (((1−t)a+tx),((1−t)b+ty))
    pos = { 
      x: (( 1 - ratio ) * start.x) + (ratio * end.x), 
      y: (( 1 - ratio ) * start.y) + (ratio * end.y) 
    };
  }
  
  log.push({
   timestamp: moment(currentTime),
    pos: pos
  })
  
  //log it
  updateLog();
};

plotCourse(ship, start, end);
goUnderway(ship);
for (var i = 0; i < 35; i++) {
 getPosition(ship, moment().add(i, 'hour'));
}
pre {
  outline: 1px solid #ccc;
  padding: 5px;
  margin: 5px;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/moment.js/2.15.1/moment.min.js"></script>
Ship: <span id="arrivalTime"></span>
<pre id="ship"></pre> Last Known Positions:
<pre id="pos"></pre>