Элементарный симулятор полёта спутника

в 12:23, , рубрики: canvas, симулятор, спутник, метки: ,

Решил недавно написать симулятор полёта спутника вокруг центрального тела. Сразу оговорюсь, что масса спутника принебрежительно мала, по сравнению с массой центрального тела.
image

Собственно первой частью работы было изучение математики. Тут было довольно просто: использовались элементарные уравнения кинематики.

/*
t - время шага
G - коэффициент притяжения(аналог гравитационной постоянной)
msun - масса центрально объекта (в условных еденицах)
*/
var r2=(xsun-xc)*(xsun-xc)+(ysun-yc)*(ysun-yc); //  Квадрат радиуса-вектора
var gs=G*msun/r2;       // Ускорение, сообщаемое спутнику
// Разложение пройденного пути по векторам                                  
var ivx=(t*t*gs/2)*(xsun-xc)/Math.sqrt(r2);            
var ivy=(t*t*gs/2)*(ysun-yc)/Math.sqrt(r2);
// прибавление средней арифметической скорости
vx+=ivx/t;                                               
vy+=ivy/t;
var V=Math.sqrt(vx*vx+vy*vy)                                   // модуль скорости 
/*
Координаты
*/
xc+=vx*t;
yc+=vy*t;

Собственно на этом математическая часть закончилась.

Интерфейс

По задумке планировалось, что пользователь сам выберет начальную точку и сам сообщит начальную скорость.
Реализовывал на JS через два слушателя событий:

var xc,yc,xc2,yc2,intervalID,vx,vy;
/* Кнопка нажата */
cnv.addEventListener('mousedown',function (event) {
/* получаем начальное положение спутника */
xc=event.offsetX;
yc=event.offsetY; 
/*  На всякий случай очищаем анимацию */
clearInterval(intervalID)
}, false)
/*
В это время юзер переносит мышь, задавая направление и модуль начальной скорости
*/
cnv.addEventListener('mouseup',function (event) {
/*  И тут тоже очищаем анимацию */
clearInterval(intervalID)
/* получаем координаты мыши */
xc2=event.offsetX;
yc2=event.offsetY;
/* разложение скорости по векторам*/
vx=(-xc+xc2)*0.4
/* начинаем анимацию*/
vy=(-yc+yc2)*0.4
intervalID=setInterval(dodo,70);
}, false)

Тестирование

Первое тестирование было довольно инетересным для меня, как для астронома))
Если орбита была очень эллиптична, то она вот так прецесировала:
image
С одной стороны было приятно смотреть на такое явление, а с другой, я понимал что дело здесь не в прецесии, а в неточности вычисления положения, ведь иногда были и такие орбиты:
image
На самом деле проблема оказалась проста: в идеале анимация должна быть дифференцирована по времени, то есть разбита на настолько малые временные шаги, что скорость, и её направление не успевали сильно измениться. А мы поставили постоянный шаг времени, и если этого шага было вполне достаточно для вычисления положения спутника в афелии, то в перегелии он должен быть в разы меньше. Для этого и был сделан плавающий шаг вычисления положения, в то время как шаг отрисовки остался постоянным.
Реализация:

var i=0;
do{
var r2=(xsun-xc)*(xsun-xc)+(ysun-yc)*(ysun-yc);
var gs=G*msun/r2;
var ivx=(t*t*gs/2)*(xsun-xc)/Math.sqrt(r2);
var ivy=(t*t*gs/2)*(ysun-yc)/Math.sqrt(r2);
vx+=ivx/t;
vy+=ivy/t;
var V=Math.sqrt(vx*vx+vy*vy)
xc+=vx*t;
yc+=vy*t;
i++
}while(i<=1/t)

Доводка

Для доводки сделал радиус-вектор спутника, который помогает понять где он находиться, когда спутник улетел из картинки:

ctx.moveTo(xc,yc)
ctx.lineTo(xsun,ysun)
ctx.stroke()

Находиться всё здесь: http://astrokot.ru/planetarium/vectors.html

Автор: Lord_Katler_Bekket

Источник

* - обязательные к заполнению поля


https://ajax.googleapis.com/ajax/libs/jquery/3.4.1/jquery.min.js