65.9K
CodeProject 正在变化。 阅读更多。
Home

命中移动目标:导弹制导系统

2007年6月22日

CPOL

27分钟阅读

viewsIcon

353294

downloadIcon

5882

目标定位和模拟导弹的数学原理:从微积分到四次方程

下载概览

模拟器本身是一个控制台窗口。可以通过调整 Program.cs 顶部的布尔常量值来开启或关闭内核蜂鸣多普勒效应输出以及保存到桌面的控制台窗口的 HTML 副本。

Screenshot - Simulator_Console.jpg

GUI 有助于可视化调整变量如何改变拦截目标所需的时间。请记住,红/蓝线与 x 轴的交点是拦截时间,而绿/紫线与 x 轴的交点是有效的最近接近点,如果该点小于容差半径,则为擦边球,而不是未命中。

Screenshot - GUI.jpg

简单的 UI 提供了一个简单应用程序的示例,该应用程序在图形界面中使用我的制导系统。概念非常简单:您是屏幕中间的小红飞船,绿色飞船正试图用白色导弹击中您。请注意,任何方向移动太远的东西都会环绕到另一侧,以防止其飞出屏幕。另请注意,您的飞船和绿色飞船的速度都有上限,以防止情况失控。此外,当您向前或向后推力时,您的飞船会变成橙色,但当该推力因超出速度限制而被丢弃时则不会。

Screenshot - Simple_UI.jpg

引言

好的,这是我的第一篇文章。希望您喜欢;我为此倾注了心血。非常欢迎评论,您可以指望我会阅读它们并回复所有问题、评论或疑虑。

我是在 2006 年 8 月参加游戏编程研讨会时开始对制导导弹着迷的。我提出了一种粗糙的目标引导方式,因为我不喜欢我的游戏中的敌人在玩家所在的位置射击,而不是在子弹到达玩家时玩家将要到达的位置射击。我的解决方案有点奏效,但它严格限于二维,并且通过使用循环产生了正确发射角度的粗略估计;我知道这种算法效率低下,但我有 72 小时的时间限制,所以我匆忙完成的东西必须凑合着用。

那之后我独自研究了这个问题。时间有限,因为我正在读高中四年级,但我很幸运能够将这个课题作为我的毕业设计,这是一个学生必须(希望如此)通过学习而有所收获的自选课题。我不知道如何解决这个复杂的数学问题,因此我能够腾出一些时间进行研究。

本项目总结了我的研究成果。我开发了一个系统,用于拦截具有位置、速度和加速度的目标(由具有给定位置和速度的射击者发射——射击者加速度不影响导弹),该导弹在给定时间段内具有给定加速度(可以将其视为燃料,预计燃料耗尽后没有加速度),给定初始或“炮口”速度,以及给定初始径向距离(就像导弹发射时出现在末端的发射器长度,具有上述初始速度)。此计算结果以布尔返回值形式表示指定导弹击中指定目标的能力,一个单位向量列表(一个二维双精度数组),其中第一个索引是拦截方向(最多可能有四种可能性!),按升序排列(最快拦截排在数组最前面),第二个索引(012)分别表示 XYZ,以及(可选)每个向量撞击目标所需的时间。我的研究成果可供公众免费使用,对于游戏编程,尤其是在开发优秀的太空射击游戏 AI 等方面,都非常有用。(如果您确实选择将我的制导系统 DLL 或我的项目的任何其他组件用于您的目的,请记住注明 Christopher Kampas 的功劳(请叫我 Jay)),事实上我非常鼓励这样做,因为这个项目的目的是让游戏开发人员的生活更轻松,当然不仅仅是我。)

背景

放松,虽然我将基本的微积分原理和四次公式融合在复杂的代数中,但您,作为开发人员,不期望对这些主题有任何了解,尽管如果您了解它们当然不会有坏处(概念上,理解极坐标绘图也不会有坏处)。我将在此处提供理解我的项目所需的基本数学基础;完成之后,我希望数学将完全去神秘化。本质上,我计算出击中目标所需的时间,然后简单地计算出经过该时间后目标将在哪里,并朝那个方向瞄准。

首先,如果我想确定相对于射手的拦截路径(忽略加速度,因为它不像速度和位置那样影响导弹的初始状态),通过从目标的相应值中减去射手的位置和速度,结果将是一个与我们原始场景具有相同拦截向量的场景,但是从原点向这些新的目标值发射。我们已经完全消除了问题中的射手参数。

接下来,从微积分中得出的两个方程帮助我们描述物体随时间变化的位置。首先,物体在给定时间 T 之后的速度等于加速度乘以 T 加上初始速度 (Vt = At + V0)。其次,物体在给定时间 T 之后的位置等于加速度乘以 T 的平方的一半,加上初始速度乘以 T,加上初始位置 (Pt = (1/2)At2 + V0t + P0)。具体为什么这些方程有效有点复杂(特别是第二个,它神秘的 1/2 似乎凭空出现……但我的老师详细解释给我听的方式,如果你想到三角形的面积,你就会走在正确的方向上)

最后,也是最难理解的部分是四次方程的使用。你们许多人可能知道二次方程,它指出当 0 = AX2 + BX + C 时,X = (-B ±(B2 - 4AC)) / 2A,这是通过“配方”得出的结论。那么,四次方程要复杂得多,并且大量使用了三次方程,从而产生了四个解。如果您想了解更多,可以 Google “四次方程”和/或查看我的制导系统 DLL 中的“rootsOf”函数,但它太庞大和复杂,无法在此处合理提供。然而,您需要知道的是它求解 X,其中 0 = AX4 + BX3 + CX2 + DX + E

Using the Code

首先,为了避免我的代码变得不必要的冗长和难以筛选,我的变量名虽然很短但仍然非常直观。我在我的制导系统中用三个字母来标识大多数变量。第一个字母表示我们正在谈论的对象(T 代表目标,S 代表射手,P 代表弹丸)。第二个字母表示我们感兴趣的向量(A 代表加速度,V 代表速度,P 代表位置)。最后,第三个字母表示我们想要知道的特定信息(XYZ 代表维度分量,或者 M 代表大小——对于不熟悉的人来说,可能更好地理解为长度,顺便说一下,它总是等于 √(X2 + Y2 + Z2)。因此,“tay”被理解为“targetAcclerationY”,但它使代码更具可读性,因为对“tay”的调用非常频繁。另一个例子是“pvm”,即“projectileVelocityMagnitude”。有一个特例,“rbt”(剩余燃烧时间,即剩余燃料),还有“rot”(容差半径,即目标半径加上导弹半径)出现在我的项目中的制导系统之外,对于确定擦边球碰撞是必要的,当导弹燃料耗尽时也必要,因为对拦截方法的调用将为所有弹丸向量大小提供 0,这会导致一个否则错误的响应,即目标未命中一微米,因为如果目标是一个无穷小的点,即容差半径为 0,则无法抵消双精度浮点数算术后台发生的微小舍入误差。

我的项目制导系统位于一个 DLL 中,其中包含静态类 Targeting,该类包含 CalculateAccelerationCalculateVelocity 方法(只需求解一个方程组,该方程组给定三个连续位置值,分别计算该物体当前的加速度和速度,每个维度使用一次。Targeting 还包含 Intercept 的两个重载,这样您就不必提供一个输出数组,如果您不关心二维向量数组中给定的每个向量需要多长时间才能撞击(数组中的顺序完全对应)。唯一的 private 方法是 rootsOf 方法,它求解一个四次方程以获取自变量(在我们的例子中是时间,在背景部分列为 X)。

算法的抽象视图

如需更深入的分析,请阅读下面代数解部分描述的实际底层数学。本节旨在以简单的 2D 场景抽象地传达概念,不讨论我的 DLL 中实际结果的计算细节。

首先,从射手和目标中减去射手的位置和速度

位置减法

Screenshot - animation1.gif

速度减法

Screenshot - animation2.gif

下一步是找到导弹能在同一时间与目标在同一位置的所有情况(现在从原点发射,目标相对位置和速度没有射手引起的漂移)。本质上,这些是目标沿其抛物线轨迹在给定时间与以原点为中心、半径为弹丸在该特定时间内所行进距离的球体相交的精确时间(下一次动画中分别的红色目标点和黑色圆圈);这样的时间最多可以有四个,最少可以有零个,或介于两者之间(原因在代数部分进行探讨),但在实践中,由于问题的性质,在绝大多数情况下,只会存在零个或两个这样的时间。

Screenshot - animation3.gif

最后计算发射单位向量(并按飞行时间从短到长排序)。这是通过获取上一步中计算的所有时间并确定目标在这些时间点的位置来完成的。通过这样做,导弹的制导系统知道目标在它可以通过直线飞行击中目标的每个时刻的位置,因此,为了计算发射单位向量,将这些坐标中的每一个都视为一个向量并进行归一化。现在调用者只需使用这些向量来适当地配置实际导弹对象的状态并将其引入其运行时环境(物理引擎等);这种环境配置的具体细节可以在代数部分的倒数第二段中找到。

Screenshot - image1.gif

请注意,第二阶段(后 rbt “燃料耗尽”阶段)的计算方式非常相似,它从第一阶段结束的地方开始,使用略微不同的弹丸与原点距离作为时间函数的方程。

至于那些所谓的“最近”接近,这些方程只是进行一些计算,以确定调整用于确定目标未来位置的时间值以进行射击,将导致目标偏离更多或偏离更少的精确时间点,无论这种调整是增加还是减少(也就是说,它是最好的时代,或者可以说是最坏的时代),并确定这些顶点是否足够接近。与两阶段的拦截计算一起使用,这四个相互关联的方程考虑了所有可能的情况,并且在同时使用时是完全防故障的。

Screenshot - animation4.gif

请注意,这不仅对确定那些几乎逃脱但由于自身过大而未逃脱的目标的擦边球碰撞很有用,而且还可用于消除当弹丸自身没有加速度时(即 pam = 0,如果导弹本身只是一个恒定速度的弹丸,或者更常见的是,因为导弹的剩余燃烧时间已达到 0 并且它正在请求轨迹更新)舍入误差的不利副作用。要更深入地理解这一点,请在我的 GUI 下载中尝试使用这些设置的模拟状态,并注意红/蓝拦截线将向 x 轴弯曲并似乎只是勉强接触它——理论上它在单个、无限小的点处接触;但是,由于使用双精度浮点数进行算术运算时发生的舍入误差,将导致该线要么刚刚越过它(这本身并不是坏事),要么刚刚未触及 x 轴并开始再次远离它而从未触及它(这是极其不可取的,因为制导系统会报告它无法拦截,而实际上它会拦截,只要目标不是无限小)。

代数解法详解

请注意,此处将使用上述命名约定。

想象一下:在消除了射手的参数(如背景部分第二段所述)并应用了确定经过给定时间后位置的方程 (Pt = (1/2) * Pam * t2 + Pvm * t + Ppm) 后,可以肯定地说,只要我有足够的剩余燃烧时间,导弹与原点的距离将由该方程给出;此时导弹将以哪个方向发射是未知的(并且在最后一步之前将一直是未知的),所以虽然我知道我将行进多远,但此时它可以是任何方向。这意味着(以及为什么极坐标绘图将有助于可视化这一点,很快就会有图表)我们可以在 2D 中绘制一个圆,或在 3D 中绘制一个球体等,这描述了经过给定时间后导弹可能在哪里,实际位置仅取决于它发射的方向。这是最重要的一点:我们有一个描述导弹与原点距离作为时间函数的方程。

接下来,我们可以使用相同的公式来描述目标在每个维度中与原点的距离(例如,Xt = (1/2) * Tax * t2 + Tvx * t + TpxYZ 的方程与其各自的 T_yT_z 变量相同)。我们可以将其与大小方程一起使用,得出 Tt =(Xt2 + Yt2 + Zt2)。请注意,这类似于毕达哥拉斯定理两次应用,如 M = √(√(X2 + Y2)2 + Z2),其中平方和平方根简单地抵消了。

因此,当 t 的值满足条件 Tt = Pt 时,我们找到了一个 t 值,该值可以在同一时间将导弹置于目标上的同一点(假设我以正确的方向发射),使得如果目标不采取规避行动,并且目标或导弹的加速度没有受到某种外部力的改变,导弹将在整个飞行过程中沿直线飞行;如果发生这种情况,导弹会像每次时间步一样重新调整自身,但这条直线可能会略微弯曲,或者拦截可能变得不可能(特别是通过使用原始力量逃逸的有效规避行动,即转离导弹并打开油门以超越导弹,假设目标有足够的原始力量来实现这一点)。然而,最终,如果加速度向量没有以任何方式改变,拦截是可能的,并且它将在导弹发射后经过时间 t 后发生(假设我们有足够的剩余燃烧时间,但我稍后会详细介绍这些方程)。现在是困难的部分,求解 t

当我写出我们的 TP 的时间函数时,我看到 t 的最高幂是二次方(即,我看到了时间平方,但例如没有像时间立方这样的东西),但是,如果我们想尝试使用二次公式,存在一个主要问题——在尝试在超过 1D 空间中进行拦截时,T 方程中会产生平方根(在 1D 中,平方根的平方可以抵消,因为该维度上的值也是整个向量的大小,但 1D 线上的拦截有点微不足道,你不觉得吗?)。消除平方根的方法是将两边平方。如果 Tt = Pt,那么 Tt2 = Pt2,证明这一点就像在 n * n = n * n 之后引用反射性质一样简单,在两边都除以 n 之后,它变为 n = n。我们已经成功消除了平方根,但现在我们必须解决应用于子方程的所有平方。

到目前为止,我们有:Xt2 + Yt2 + Zt2 = Pt2 对于满足直线拦截所需时间长度的 t 值将成立(因此也是最佳拦截,因为两点之间最快的路径是直线。因此,最快,即最小的 t 值,它必须是实数,大于或等于零,并且小于或等于剩余燃烧时间,才是最佳拦截,因为它是最快的直线,是速度最快的直线,如果你愿意的话)。

为了完成这个问题,必须在内部对每个子方程进行平方。幸运的是,由于所有方程基本相同,工作量减少了。稍后当我提到计算导弹在飞行过程中燃料耗尽时的拦截时,P 函数将略有不同,但在这里它也与 XYZ 函数非常相似。因为对函数应用平方非常相似,所以我只在此处求解 X,而不是通过复制粘贴工作三次并更改一些字母来浪费空间。

我们从这里开始

Xt2 = ((1/2) * Tax * t2 + Tvx * t + Tpx)2 

因此

(A + B + C)2 = A * A + A * B + A * C +
               B * A + B * B + B * C +
               C * A + C * B + C * C 

这类似于乘二项式的老式 FOIL 方法(首项,外项,内项,末项),它更为常见,但它是潜在数学真理的更广泛实现(这个使用三项式),并且为了我们的目的可以简化,因为我们只对三项式进行平方,所以我们可以简化为

(A + B + C)2 = A2 + B2 + C2 + 2 * (A * B + A * C + B * C)

因此,以标准多项式形式表示 t,所有同类项合并后,

Xt2 = (1/4) * Tax2 * t4 +
  Tax * Tvx * t3 +
  (Tax * Tpx + Tvx2) * t2 +
  2 * Tvx * Tpx * t +
  Tpx2

组合 XYZ 函数就像进一步组合同类项一样简单(第一项,即 t4 项变为:(1/4) * (Tax2 + Tay2 + Taz2) * t4))。

那么现在,这如何帮助我们求解 t 呢?通过从我们原始的 Tt2 = Pt2 两边减去 Pt2(从而得到 Tt2 - Pt2 = 0),当所有项在这些子方程中完全替换和简化后,结果是发现一个四次方程,即四次多项式。要实际执行这最后一步,从我们在最后两段中完成的 Tt2 方程中减去 Pt2 项,就像在上一段中为 XYZ 添加项一样简单。这是所有结果方程(我添加了一些括号,以使某些内容更清晰,这些内容对于运算顺序并非真正必要)

0 = ( (1/4) * (Tax2 + Tay2 + Taz2 - Pam2) ) * t4 +
    ( Tax * Tvx + Tay * Tvy + Taz * Tvz - Pam * Pvm ) * t3 +
    ( Tax * Tpx + Tvx2 + Tay * Tpy + Tvy2 + 
        Taz * Tpz + Tvz2 - Pam * Ppm - Pvm2 ) * t2 +
    ( 2 * ( Tvx * Tpx + Tvy * Tpy + Tvz * Tpz - Pvm * Ppm ) ) * t +
    ( Tpx2 + Tpy2 + Tpz2 - Ppm2 )

这可以解出 t。我做了一些研究,并编写了一个 rootsOf 函数,其中 t 的系数按标准多项式形式的顺序传入,并返回所有实数根。公平地说,它并不是一个真正“完整”的求根函数,因为它只告诉调用者实数根,但没有指示复数根(它们被完全省略了,即如果所有根都是复数,函数不返回任何根)。虽然这是真的,但如果有人因为能够在虚数时间拦截目标而说他们锁定了目标,这比出于我们的目的在负时间拦截更不现实,但负数在制导系统中的调用堆栈更高层被抛弃,以及其他不可接受的值(例如,用这个方程找到的在 rbt 之后的根)。

要找出 rbt 之后时间的根,唯一改变的是我们的 P 函数,它看起来像这样

P't = ( Pam * Rbt *+ Pvm ) * t + ( Ppm - (1/2) * Pam * Rbt2 )

平方后看起来像这样

P't2 = ( Pam2 * Rbt2 + 2 * Pam * Pvm * Rbt + Pvm2 ) * t2 +
  ( 2 * Pam * Ppm * (Pam * Rbt + Pvm) - Pam2 * Rbt3 - Pam * Pvm * Rbt2 ) * t +
  ( (1/4) * Pam2 * Rbt4 - Pam * Ppm * Rbt2 + Ppm2 )

请记住,从 T 函数中减去这些项后,如果所得的根都是实数且大于 rbt,则认为它们是有效的(严格来说,等于 rbt 的根也是有效的,但 P 函数可以很好地处理这些根,因此如果它们在使用 P 函数时出现,则无需保留它们。另请注意,大于 rbt 也意味着大于或等于零,因为在上下文中 rbt 不能为负数)。

最后,关于擦边球碰撞:给定一个四次多项式 Y = AX4 + BX3 + CX2 + DX + E,其瞬时斜率为零的 X 值由三次多项式 Y' = 4AX3 + 3BX2 + 2CX + D 的根给出。请注意,D 的隐含系数为一,D 项中 X 的隐含幂为零,这简化为 D,但也要注意,如果继续该模式,E 的系数为零,这就是 E 项完全消失的原因。

通过使用这个三次方程,我们可以利用我们的四次系数来计算最近接近。关于这一点,可能令人困惑的是它们不一定有意义,因为如果存在真正的拦截或真正的最近接近,它们通常是“最远”接近。然而,如果确实存在最近接近(例如,如果不存在真正的拦截,那么第一个和最后一个三次根是最近接近,或者中间根是最近接近,其中顺序由 X 的值决定),那么我们可以确定它是一个有效的擦边球碰撞,如果 Y' 的绝对值小于或等于容差半径(目标半径加上导弹半径)。接近是最近还是最远与制导系统无关,因为容差半径比较会消除不可接受的值,并且它在技术上是最近还是最远接近实际上无关紧要,因为如果接近足够近以构成碰撞,并且也比直接碰撞更快,那么瞄准擦边球碰撞是最佳选择。

一个通用的三次函数

Screenshot - image2.gif

一个通用的四次函数

Screenshot - image3.gif

一个三次函数,其根位于四次函数斜率为零的位置

Screenshot - image4.gif

所以,我们已经解出了所有的根,现在是最后一步。通过将这些 t 值代入 XYZ 函数,结果是目标相对于射手的 XYZ 坐标(射手的加速度被完全忽略,如很久以前提到的)。制导系统可以通过获取每个 (X, Y, Z) 坐标并除以所有分量并除以该特定坐标的各自大小来编译一个单位向量数组,同样由 M =(X2 + Y2 + Z2) 给出,即坐标 C 的单位向量由 (X, Y, Z) 给出,其中 X = Cx / Cm Y = Cy / CmZ = Cz / Cm

为了使用每个单位向量,导弹的初始状态设置如下(加速度、速度和位置),给定一个目标单位向量 U 和射手的速度和位置向量 SvSp(注意 PamPvmPpm 通过标量乘法相乘,而 SvSp 通过向量加法相加)

A = U * Pam
V = U * Pvm + Sv
P = U * Ppm + Sp

请注意,在导弹飞行过程中更新其轨迹时,它会告诉制导系统其当前速度和位置是“射手”参数,并且其初始速度为零,初始位置为零,因为此时必须仅凭导弹的加速度来调整飞行路径,即没有“射手”可以从导弹开始的地方为其提供初始速度或位置。

四次方程的由来及其重要性

1540年,洛多维科·费拉里发现了四次方程。这个精妙的公式于1545年首次在名为《大艺》的出版物中发表,同时发表的还有吉罗拉莫·卡尔达诺发现的三次方程,后者对于求解四次方程至关重要,以至于导致了五年的延迟。一个重要的问题出现了——什么是四次方程?如果一个方程中有五个定义的常数和一个变量,如果零等于第一个常数乘以变量的四次方,加上第二个常数乘以变量的三次方,加上第三个常数乘以变量的平方,加上第四个常数乘以变量,再加上第五个常数,那么它就是四次方程。这通常写为 0 = AX4 + BX3 + CX2 + DX + E。四次方程求解满足此条件的所有四个可能的 X 值,其中 A != 0。从技术上讲,总是存在四个解,但,在移除重复解之前,其中零、两个或四个将是实数,而 X 的其余解将是复数——包含实部加虚部的数,其中虚部前面是系数 i。这四个解在各种现实世界情况中都非常有用,因为在实践中,需要对平方项进行平方才能得出结论,从而将该项提高到四次方,这种情况出奇地常见。

这对于考虑到自身及其目标加速度、速度和位置的制导导弹来说,尤其具有洞察力。在代入、分配、合并同类项并系统地将所有内容移到方程的一侧,从而在另一侧留下零之后,会产生一个四次方程,这是因为加速度随时间改变位置表示为 pt = (1/2)at2,并且在得到四次表示的过程中,这被平方并表示为 pt2 = (1/4)a2t4,其中我们希望求解 t 而不是 XA 项展现在我们眼前。类似地,仅考虑速度和位置的制导导弹将通过使用二次方程产生结果,通常写为 0 = AX2 + BX + C,因为在将所有内容对齐为标准多项式形式的过程中,t 将被平方,但由于没有要平方的 t 平方项,因此结果形式中 t 的最高幂将为二次方,因此为 AX2。在一个更简单的层面上,仅考虑位置的制导导弹将产生更简单的解决方案。

这些结论表明,导弹可能能够根据位置、速度、加速度和加速度变化进行导航,就像加速度代表速度变化一样,尽管没有很好的描述加速度变化的词语。令人惊讶的是,这却是错误的。另一个问题出现了——是什么让加速度如此特殊?答案在于四次方程本身所产生的四次方。五次方程,或任何更高次多项式具有非零系数的方程,都没有一个公式,在给定系数的情况下,能够产生所讨论变量的所有可能值,即制导导弹情况下的时间。在数学界众所周知,“阿贝尔-鲁菲尼定理(也称为阿贝尔不可能性定理)指出,五次或更高次多项式方程没有一般的根式解”(维基百科)。有方法可以精确估算此类多项式的所有根,但没有办法像二次、三次和四次方程为二、三、四次多项式提供的那样,以优雅的等式形式使用系数来找到所有根。

关注点

我知道燃料耗尽时,弹丸质量会减少,应用 F = MA(牛顿第二运动定律)到这个问题中,我们发现我们产生了加速度变化。不幸的是,我可以生成更高次的多项式,但我无法解析地求解时间,因为四次公式是可以用这种方式求解的最高次多项式(上面部分的维基百科参考文献详细阐述了这一点),而且由于这种运动相对来说非常小,可以合理地忽略不计。这个制导系统适用于没有空气阻力或重力等力的情况,但再次强调,包含这些力会随着时间的推移导致相对较小的误差,因为导弹会在每个时间步不断更新其轨迹以考虑这些微小的调整。我仍在研究更广泛的问题解决方案,但目前我的研究成果已经足够大(并且功能也足够完善),所以我认为不妨分享一下。

历史

首先,我花了几小时做了一个粗略的例程来估算二维恒定速度,后来我开发了一个使用三角函数(主要是余弦定律,用二次方程求解一些未知数)的二维解析解。我能够将它转换为恒定速度的三维解,但在这里碰壁了。在改变思路,转向代数和微积分,并远离几何和三角函数之后,我得到了一个恒定加速度的三维解,它可以很容易地适用于任何维数,因为四次系数非常简单地是每个维度的特定小次方程结果的总和。想要一个 6D 解吗?11D 解怎么样?使用这种求解时间的方法,您可以在 5 分钟内轻松设置。

  • 2007年6月22日 -- 原始版本发布
  • 2007年6月27日 -- 文章和下载更新
  • 2007年7月3日 -- 文章完成,并添加了简单用户界面下载
  • 2007年7月10日 -- 下载 Simple_Guidance_System_UI.zip 更新
  • 2007年7月20日 -- 下载 Simple_Guidance_System_UI.zip 更新
  • 2007年8月7日 -- 下载 Simple_Guidence_System_UI.zip 更新
  • 2007年8月9日 -- 下载 Simple_Guidence_System_UI.zip 更新
  • 2007年8月15日 -- 修复了下载 Guided_Missile_Simulator.zip 中的一个错误,该错误导致某些有效的用户输入无法通过验证
© . All rights reserved.