新的一天新问题...
我按照埃里克(Eric)所说的做,并为Acceleration创建了一个方法!
它看起来像这样:
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的方法会收到带有位置的向量2。 现在,我想使用此向量,因此我创建了另一个方法,该方法应将我的Magnitude作为标量(双精度)返回。 为此,我创建了一种方法来计算向量的幅度并将其平方。 当我在ForceAsVector-Method内调用MagnitudeOfForce-Method时,我正在尝试将负单位矢量与标量相乘,并将其作为Vector2返回。
也许我在这里做得很糟糕,但是我正在努力了解Eric所做的一切,仍然需要您的帮助!
谢谢。
答案 0 :(得分:11)
您犯了两个明显的错误,并且算法选择不正确。
首先,您将月球的位置建模为单个数字,而不是3空间中的向量,因此此处要建模的是简单的谐波运动,例如将弹簧限制在一个维度上,而不是一个轨道。首先将位置和速度建模为3空间向量,而不是双精度。
第二,您已使引力的符号为正,因此它是两个物体之间的排斥力,而不是有吸引力。力的符号必须是在地球方向上。
第三,您对Euler算法的实现似乎是正确的,但是Euler对于数值求解轨道问题不是一个好的选择,因为它并不保守。您可以轻松地进入月球获得或失去一点动量,并加起来并破坏您的椭圆形轨道的情况。
由于月球的轨道是哈密顿量,请使用辛算法。它旨在模拟保守系统。
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空间中的位置。 (实际上,月球的轨道因太阳,地球不是球体,因潮汐等而改变。)
更新:
首先,由于这是课程工作,您必须引用所有资料,包括从互联网上获取帮助。您的讲师必须知道您的工作是什么,以及其他人为您所做的工作。
您问过如何在两个方面进行这项工作;这似乎是错误的,但是无论如何,要按照课程的要求去做。
我希望能教给更多初学者的规则是:创建一个类型,方法或变量来解决您的问题。在这种情况下,我们希望表示一个复杂的 value 的行为,因此它应该是一个 type ,而该类型应该是一个 value类型 >。值类型在C#中为struct
。因此,让我们这样做。
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获取新的加速度,然后调用Euler获取新的状态并重复。
作为初学者,请仔细研究这些技术。注意我做了什么:我创建了表示概念的类型,并表示了这些概念上的操作的方法。完成此操作后,该程序将变得非常清晰易读。
考虑如何使用这些技术扩展该程序;我们制作了一个硬编码的AccelerationOfTheMoon
方法,但是如果我们想计算多个物体的加速度怎么办?同样,创建一个类型以表示Body
;身体的特征是State
和质量。如果我们想解决n体问题怎么办?我们的加速度计算必须将其他物体作为参数。依此类推。