0

新的一天新的问题...

我按照 Eric 所说的方式进行了操作,并为加速创建了一个方法!

它看起来像这样:

static Vector2 AccelerationOfTheMoon(Vector2 position)
    {
        double Mm = 7.349 * Math.Pow(10, 22);

        double MagnitudeOfForce()
        {
            double MagF = position.LengthSquared();
            return MagF;
        }

        Vector2 ForceAsVector()
        {
            return position.NegativeUnitVector() * MagnitudeOfForce();
        }

        Vector2 acceleration = ForceAsVector() / Mm;


    }

我看到它的方式是,我的称为 AccelerationOfTheMoon 的方法接收带有位置的 Vector 2。现在我想使用这个向量,所以我创建了另一个方法,它应该将我的 Magnitude 作为标量(双精度)返回。为此,我创建了一个方法来计算向量的大小并将其平方。当我在 ForceAsVector-Method 中调用 MagnitudeOfForce-Method 时,我试图将负单位向量与标量相乘并将其作为 Vector2 返回。

也许我在这里做得非常糟糕,但我正在努力理解 Eric 所做的一切,仍然需要你的帮助!

谢谢。

4

1 回答 1

12

你犯了两个明显的错误和一个糟糕的算法选择。

首先,您已将月球的位置建模为单个数字而不是 3 空间中的矢量,因此您在此处建模的是简单的谐波运动,例如受限于单一维度的弹簧,而不是轨道。首先将位置和速度建模为 3 空间向量,而不是两倍。

其次,你把万有引力的符号设为,所以它是两个物体之间的排斥力,而不是吸引力。力的符号必须在地球的方向

第三,您对欧拉算法的实现似乎是正确的,但欧拉在数值求解轨道问题时是一个糟糕的选择,因为它不保守;你很容易陷入月球获得或失去一点动量的情况,这些情况加起来会破坏你漂亮的椭圆轨道。

由于月球的轨道是哈密顿轨道,因此请改用辛算法;它旨在模拟保守系统。

https://en.wikipedia.org/wiki/Symplectic_integrator

这种方法和您的欧拉方法基本上是关于找到状态向量:

https://en.wikipedia.org/wiki/Orbital_state_vectors

但是,对于您的简单 2 体系统,有更简单的方法。如果你想做一个像 Kerbal Space Program 这样的模拟,只有你在轨道上运行的物体会影响你的轨道,并且有多个卫星的行星“在轨道上”,你不需要在每个时间单位上模拟系统计算出状态向量的序列;您可以在给定开普勒元素的情况下直接计算它们:

https://en.wikipedia.org/wiki/Orbital_elements

我们非常精确地了解月球的六种元素;从那些你可以随时计算月球在 3 空间中的位置,再次假设没有任何东西干扰它的轨道。(实际上,月球的轨道会因太阳、地球不是球体这一事实、潮汐等因素而改变。)


更新:

首先,由于这是课程作业,您需要引用所有资源,包括从互联网获得帮助。你的导师必须知道你的工作是什么,以及你让别人为你做的工作。

您问如何在两个维度上完成这项工作;这似乎是错误的,但无论如何,按照课程作业所说的去做。

我希望更多的初学者被教导的规则是:制作一个类型、一个方法或一个变量来解决你的问题。在这种情况下,我们希望表示一个复杂的行为,所以它应该是一个类型,而那个类型应该是一个值类型。值类型struct在 C# 中。所以让我们这样做。

struct Vector2
{
    double X { get; }
    double Y { get; }
    public Vector2(double x, double y)
    {
        this.X = x;
        this.Y = y;
    }

请注意,向量是不可变的,就像数字一样。你永远不会改变 vector。当你需要一个新的向量时,你就创建一个新的。

我们需要对向量执行哪些操作?向量加法、标量乘法和标量除法只是花式乘法。让我们实现这些:

    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})";

}

我们已经完成了向量。

我们正在尝试模拟轨道状态参数的演变,所以再次制作一个 type。什么是状态参数?位置和速度:

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 来获取新的加速度,然后调用 Euler 来获取新的状态,然后重复。

作为初学者,请仔细研究这些技巧。请注意我所做的:我创建了表示概念的类型,以及表示对这些概念的操作的方法。一旦你这样做了,程序就会变得非常清晰易读。

想想你将如何使用这些技术来扩展这个程序;我们做了一个硬编码的AccelerationOfTheMoon方法,但是如果我们想计算几个物体的加速度怎么办?再次,创建一个类型来表示Body;身体的特点是State质量。如果我们想解决 n 体问题怎么办?我们的加速度计算必须将其他物体作为参数。等等。

于 2019-04-17T13:29:52.350 回答