Вы сделали две очевидные ошибки и плохой выбор алгоритма.
Во-первых, вы смоделировали положение Луны как единое число, а не как вектор в 3-м пространстве, поэтому вы моделируете здесь простое гармоническое движение, как пружина, ограниченная одним измерением, а не орбитой. Начните с моделирования положений и скоростей как трехмерных векторов, а не двойников.
Во-вторых, вы сделали знак гравитационной силы положительным, так что это сила отталкивания между двумя телами, а не притяжения. Знак силы должен быть в направлении земли.
В-третьих, ваша реализация алгоритма Эйлера кажется правильной, но Эйлер - плохой выбор для численного решения орбитальных задач, потому что он неконсервативен; вы можете легко попасть в ситуации, когда Луна набирает или теряет немного инерции, а это складывается и разрушает вашу красивую эллиптическую орбиту.
Поскольку орбита Луны гамильтонова, используйте вместо нее симплектический алгоритм; он предназначен для моделирования консервативных систем.
https://en.wikipedia.org/wiki/Symplectic_integrator
Этот подход и ваш подход Эйлера в основном касаются поиска векторов состояния:
https://en.wikipedia.org/wiki/Orbital_state_vectors
Однако для вашей простой системы из двух частей есть более простые методы. Если вы хотите создать симуляцию наподобие Kerbal Space Program, в которой только тело, на орбите которого вы вращаетесь, влияет на вашу орбиту, а планеты с несколькими лунами находятся «на рельсах», вам не нужно моделировать систему на каждой единице времени. разработать последовательность векторов состояния; вы можете вычислить их напрямую с учетом кеплеровских элементов:
https://en.wikipedia.org/wiki/Orbital_elements
Мы знаем шесть элементов Луны с высокой степенью точности; по ним вы можете вычислить положение Луны в 3-м пространстве в любое время, опять же, предполагая, что ничто не нарушает ее орбиту. (На самом деле орбита Луны изменяется из-за Солнца, из-за того, что Земля не является сферой, из-за приливов и т. Д.)
ОБНОВИТЬ:
Во-первых, поскольку это курсовая работа, вы должны указать все свои источники, включая получение помощи из Интернета. Ваши инструкторы должны знать, какую работу вы выполняете и какую работу за вас выполнял кто-то другой.
Вы спросили, как выполнить эту работу в двух измерениях; это кажется неправильным, но как бы то ни было, делайте то, что сказано в курсовой работе.
Правило, которому я бы хотел научить больше новичков: создайте тип, метод или переменную, которые решают вашу проблему. В этом случае мы хотим представить поведение сложного значения, поэтому оно должно быть типом, а этот тип должен быть типом значения em >. Типы значений struct
в C #. Так что давай сделаем это.
struct Vector2
{
double X { get; }
double Y { get; }
public Vector2(double x, double y)
{
this.X = x;
this.Y = y;
}
Обратите внимание, что векторы неизменяемы, как и числа. Вы никогда не мутируете вектор. Когда вам нужен новый вектор, вы создаете новый.
Какие операции нам нужно выполнить с векторами? Сложение векторов, скалярное умножение и скалярное деление - это всего лишь причудливое умножение. Реализуем их:
public static Vector2 operator +(Vector2 a, Vector2 b) =>
new Vector2(a.X + b.X, a.Y + b.Y);
public static Vector2 operator -(Vector2 a, Vector2 b) =>
new Vector2(a.X - b.X, a.Y - b.Y);
public static Vector2 operator *(Vector2 a, double b) =>
new Vector2(a.X * b, a.Y * b);
public static Vector2 operator /(Vector2 a, double b) =>
a * (1.0 / b);
Мы можем производить умножение и в другом порядке, поэтому давайте реализуем это:
public static Vector2 operator *(double b, Vector2 a) =>
a * b;
Сделать вектор отрицательным - это то же самое, что умножить его на -1:
public static Vector2 operator -(Vector2 a) => a * -1.0;
И чтобы помочь нам отладить:
public override string ToString() => $"({this.X},{this.Y})";
}
На этом мы закончили с векторами.
Мы пытаемся смоделировать эволюцию параметров орбитального состояния, поэтому снова создайте тип. Какие параметры состояния? Положение и скорость:
struct State
{
Vector2 Position { get; }
Vector2 Velocity { get; }
public State(Vector2 position, Vector2 velocity)
{
this.Position = position;
this.Velocity = velocity;
}
Теперь мы переходим к основному алгоритму. Что у нас есть? состояние и ускорение. Что мы хотим? Новое состояние. Создайте метод:
public State Euler(Vector2 acceleration, double step)
{
Vector2 newVelocity = this.Velocity + acceleration * step;
Vector2 newPosition = this.Position + this.Velocity * step;
return new State(newPosition, newVelocity);
}
}
Супер. Что осталось? Нам нужно отработать ускорение. Сделайте метод:
static Vector2 AccelerationOfTheMoon(Vector2 position)
{
// You do this. Acceleration is force divided by mass,
// force is a vector, mass is a scalar. What is the force
// given the position? DO NOT MAKE A SIGN MISTAKE AGAIN.
}
И теперь у вас есть все необходимые детали. Начиная с начального состояния, вы можете многократно вызывать AccelerationOfTheMoon, чтобы получить новое ускорение, а затем вызывать Эйлера, чтобы получить новое состояние, и повторять.
Начинающий внимательно изучите эти методы. Обратите внимание на то, что я сделал: я создал типы для представления концепций и методы для представления операций с этими концепциями. Как только вы это сделаете, программа станет предельно понятной для чтения.
Подумайте, как бы вы расширили эту программу, используя эти методы; мы сделали жестко запрограммированный AccelerationOfTheMoon
метод, но что, если мы хотим вычислить ускорения нескольких тел? Опять же, создайте тип для представления Body
; тело характеризуется State
и массой. Что, если бы мы хотели решить проблему n тел? Наше вычисление ускорения должно было бы принять другие тела в качестве параметра. И так далее.
person
Eric Lippert
schedule
17.04.2019