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

科学与工程通用框架 - 第六部分:人造卫星轨道确定

starIconstarIconstarIconstarIcon
emptyStarIcon
starIcon

4.88/5 (27投票s)

2006年9月19日

CPOL

19分钟阅读

viewsIcon

84270

downloadIcon

6739

一篇关于框架应用程序确定人造卫星轨道的文章

有用链接

Artificial satellite trajectory

1. 引言

许多工程问题不需要高级数学或物理知识。然而,它们可能非常复杂,因为它们包含许多不同的对象以及它们之间的链接。本文致力于解决其中一个问题。本文的所有代码都与 Visual C# 2010 Express 兼容。

2. 背景

事实上,卫星轨道的确定是对测量值的统计处理。正如几个世纪前的教育需要希腊语和拉丁语知识一样,任何轨道确定专家都应该了解一般线性方法和卡尔曼滤波。本文深入描述了一般线性方法的应用,并简要描述了卡尔曼滤波技术。

3. 外部库

任何高级软件都需要与第三方软件互操作。本文使用了两个额外的库。第一个计算地球引力。第二个计算地球大气层的参数。适配器模式用于软件互操作性。让我们演示一下这种模式的用法。以下代码包含计算地球引力的函数声明

/// <summary>
/// Calculation of gravity accelerations
/// </summary>
/// <param name="N0">Degree of Legendre polinomials</param>
/// <param name="NK">Number of harmonics</param>
/// <param name="X">X - coordinate</param>
/// <param name="Y">Y - coordinate</param>
/// <param name="Z">Z - coordinate</param>
/// <param name="FX">X - component of gravitational acceleration</param>
/// <param name="FY">Y - component of gravitational acceleration</param>
/// <param name="FZ">Z - component of gravitational acceleration</param>
private void Forces(int N0, int NK, double X, double Y, double Z, out double FX,
        out double FY, out double FZ)

此函数不为框架所知。但是框架包含 IObjectTransformer 接口。

/// <summary>
/// Transformer of objects
/// </summary>
public interface IObjectTransformer
{
    /// <summary>
    /// Input variables
    /// </summary>
    string[] Input
    {
        get;
    }

    /// <summary>
    /// Output variables
    /// </summary>
    string[] Output
    {
        get;
    }

    /// <summary>
    /// Gets type of i - th input variable
    /// </summary>
    /// <param name="i">Variable index</param>
    /// <returns>The type</returns>
    object GetInputType(int i);

    /// <summary>
    /// Gets type of i - th output variable
    /// </summary>
    /// <param name="i">Variable index</param>
    /// <returns>The type</returns>
    object GetOutputType(int i);

    /// <summary>
    /// Calculation
    /// </summary>
    /// <param name="input">Input</param>
    /// <param name="output">Output</param>
    void Calculate(object[] input, object[] output);
}

此接口是一个抽象转换操作。此接口的成员具有以下含义

成员名称 注释
1 输入 输入变量的名称
2 输出 输出变量的名称
3 GetInputType(int i) 第 i 个输入变量的类型
4 GetOutputType(int i) 第 i 个输出变量的类型
5 Calculate(object[] input, object[] output) 计算

以下代码片段展示了此接口的实现

/// <summary>
/// Gravity of Earth
/// </summary>
public class Gravity : IObjectTransformer, ICategoryObject, IPropertiesEditor,
    IObjectFactory
 {
    /// <summary>
    /// Inputs
    /// </summary>
    static private readonly string[] inps = new string[] { "x", "y", "z" };

    /// <summary>
    /// Outputs
    /// </summary>
    static private readonly string[] outs = new string[] { "Gx", "Gy", "Gz" };

    string[] IObjectTransformer.Input
    {
        get { return inps; }
    }

    string[] IObjectTransformer.Output
    {
        get { return outs; }
    }

    object IObjectTransformer.GetInputType(int i)
    {
        return ret;
    }

    object IObjectTransformer.GetOutputType(int i)
    {
        return ret;
    }

    /// <summary>
    /// Calculation
    /// </summary>
    /// <param name="input">Input</param>
    /// <param name="output">Output</param>
    void IObjectTransformer.Calculate(object[] input, object[] output)
    {
        // Input cast
        double x = (double)input[0];
        double y = (double)input[1];
        double z = (double)input[2];

        double fx, fy, fz;

        // Call of forces
        Forces(n0, nk, x, y, z, out fx, out fy, out fz);

        // filling of output
        output[0] = fx;
        output[1] = fy;
        output[2] = fz;
    }
}

让我们解释一下这段代码。输入变量分别命名为 "x"、"y" 和 "z"。这些名称用于互操作性。类似地,输出变量命名为 "Gx"、"Gy"、"Gz"。因此我们有三个输入和三个输出变量。所有这些变量都具有 "Double" 类型。框架使用的类型系统与 .NET 的不一致,因为框架应该区分长度不同的数组。ArrayReturnType 用于数组。然而对于 double 变量类型,使用 const Double ret = 0;Calculate 调用 Forces 函数。因此 Forces 函数通过 IObjectTransformer 接口的方法调用而隐式地对框架可见。现在让我们解释框架如何找到必要的对象。以下接口用于此目的

/// <summary>
/// The factory of category object
/// </summary>
public interface IObjectFactory
{
    /// <summary>
    /// Names of objects
    /// </summary>
    string[] Names
    {
        get;
    }

    /// <summary>
    /// Object by name
    /// </summary>
    /// <param name="name">The name</param>
    /// <returns>The object</returns>
    ICategoryObject this[string name]
    {
        get;
    }
}  

Names 属性返回库提供的对象的名称。ICategoryObject this[string name] 按名称返回对象。以下代码显示了此接口的实现

string[] IObjectFactory.Names
{
    get { return new string[] { "Gravity 36 * 36" }; }
}

ICategoryObject IObjectFactory.this[string name]
{
    get { return this; }
}   

用户界面中通过以下方式指示“重力 36 * 36”。首先,我们将设置外部对象。

如果我们打开其属性编辑器并选择库(Grav36.dll),则可访问对象的列表将显示在下面的 combobox

然后应选择必要的对象(“重力 36 * 36”)。完成此操作后,该对象将具有新的图标

以下代码表示查找对象工厂

/// <summary>
/// Gets factory from assembly
/// </summary>
/// <param name="ass">The assembly</param>
/// <returns>The factory</returns>
static public IObjectFactory GetFactory(Assembly ass)
{
    Type[] types = ass.GetTypes(); // Types of assembly
    foreach (Type type in types)
    {
        if (type.GetInterface("IObjectFactory") != null)
        {
            // Looking for singleton
            FieldInfo fi = type.GetField("Object");
            if (fi != null)
            {
                return fi.GetValue("Object") as IObjectFactory;
            }
            else
            {
                // Calling of default constructor
                return type.GetConstructor(new Type[] { }).Invoke(new object[] 
                { }) as IObjectFactory;
            }
        }
    }
    return null;
}  

此代码定义了实现 IObjectFactory 接口的程序集类型。如果此类型包含单例(命名为 "Object"),则使用此单例。否则使用对象的默认构造函数。

4. 容器

复杂的应用程序需要大量的对象方块和箭头。理解这样一幅图是非常困难的。但是,您可以合并一组对象方块和箭头。您还可以将方块集组合到容器中。这样,结果图将清晰易懂。轨道确定需要运动方程,而运动方程又需要重力模型和大气模型。

Artificial satellite motion model

在此图中,**重力**和**大气**使用动态链接库,如第3节所述。将这些组件合并到一个容器中很方便。要创建容器,用户应创建场景并选择主菜单的*工具/容器设计器*选项。选择*工具/容器设计器*选项后,我们得到

Properties

此表单的右侧允许我们通过勾选复选框来选择公共组件。左侧允许我们设置公共组件的几何位置。设置这些位置后,您可以将容器保存到 `*.cont` 文件中。在此示例中,公共组件是**大气**、**重力**和**运动方程**。然后,我们应该创建一个调色板按钮。为此,您应该将 `*.cont` 放到 `Application path/cont` 目录中,并创建按钮图标并将其放到应用程序路径中。然后,您应该创建或编辑 `Containers.xml` 文件。此文件包含有关工具栏额外选项卡、额外按钮及其图标以及容器文件名的信息。此文件的内容清晰明了,此处省略。

创建或编辑 Containers.xml 文件后,将出现新的选项卡和按钮,如下图所示

Picture with container

我们有一个额外的按钮,可以将新组件放到桌面上。

5. 运动模型

人造卫星的运动模型是一个描述其在格林尼治参考系中运动的常微分方程组:

Motion equations

其中,运动参数 分别是坐标和速度分量,角速度 是地球的角速度,角速度 是总外部加速度的分量。当前模型包含引力作用和气动力作用。这些加速度可以通过以下公式定义

Acceleration formulae

下表包含这些参数的含义:

Parameters

常微分方程组件用于上述方程。该组件没有丰富的符号系统,只使用小写变量。但是,该组件支持丰富的注释系统,如下所示:

Parameters

这些注释可以包含变量和物理参数之间的映射。方程的自变量(xyzuvw)在右侧部分被勾选。这些变量与

Parameters

该组件以下列方式表示微分方程:

Parameters

除了自变量,方程还包含其他参数。下表包含了这些参数的映射关系。

Parameters

其中一些参数是常量。其他参数需要导出。常量被勾选,而导出的参数未被勾选,如下所示:

Parameters

导出的参数与引力和大气模型有关。这些模型包含在外部库中。下图包含了运动模型的组件。

Motion model

**运动方程**组件被认为是上述常微分方程的组件。这些方程具有反馈。方程的右侧取决于引力。否则,引力取决于卫星的坐标。**向量**组件用作**运动方程**的反馈。

FeedBack

这张图有以下含义。**Vector** 组件的变量 *x*、*y*、*z*、*u*、*v*、*w* 分别赋给 **Motion equations** 的 *x*、*y*、*z*、*u*、*v*、*w* 变量。**Vector** 的输入和输出参数如下所示

Pareameters of Vector object

组件**重力**和**大气**是分别从外部库获取的对象,它们计算地球重力和地球大气。这两个对象都实现了 IObjectTransformer 接口。**G-变换**和**A-变换**对象是辅助对象,分别用于应用**重力**和**大气**对象。**G-变换**的属性如下所示

Pareameters of Vector object

上图具有以下含义。**G-变换**连接到**重力**对象。此对象对应于导出的 Gravity 类(Gravity 类的代码在此文本上方)。Gravity 类实现了 IObjectTransformer 接口。Gravity 的输入参数是标有“x”、“y”、“z”的坐标。因此,上面的组合框标有“x”、“y”、“z”标签。上图表示参数“x”、“y”、“z”分别分配给**Vector**组件的 Formula_1Formula_2Formula_3。否则,**Vector**的 Formula_1Formula_2Formula_3 分配给**Motion equations**的 xyz。但是**Motion equations**组件使用**G-变换**的参数

Parameters of Vector object

此图表示**运动方程**的参数 *a*、*b*、*c* 分配给**G-变换**的参数 *Gx*、*Gy*、*Gz*。因此,地球的 Gravity 函数被导出到**G-变换**。地球大气以类似方式导出。

6. 问题描述

下图说明了轨道确定的问题。

State of problem

我们有一颗人造地球卫星。有一组地面站进行测量。因此,我们有地面站和卫星之间距离和相对速度的测量值。处理这些测量值可以确定轨道。

6.1 输入数据

输入数据包含距离和相对速度的测量值。为此使用了特殊组件。这些组件如下所示

Measurements

**距离**组件的纵坐标是测量的距离,**速度**组件的纵坐标是测量的相对速度。这些组件的横坐标无关紧要。其他输入数据如下所示

All picture

输入参数的完整列表如下表所示

组件名称 注释
1 Distance 距离测量数组
2 速度 速度测量数组
3 距离时间 距离测量时间数组
4 速度时间 速度测量时间数组
5 距离 X 与距离测量对应的地面站的 X 坐标数组
6 距离 Y 与距离测量对应的地面站的 Y 坐标数组
7 距离 Z 与距离测量对应的地面站的 Z 坐标数组
8 速度 X 与速度测量对应的地面站的 X 坐标数组
9 速度 Y 与速度测量对应的地面站的 Y 坐标数组
10 速度 Z 与速度测量对应的地面站的 Z 坐标数组
11 距离 Sigma 距离测量标准差数组
12 速度 Sigma 速度测量标准差数组

让我们对这张表进行评论。我们有两个测量数组。第一个数组 _d_1_, _d_2_, ... 包含距离测量值。第二个数组 _V_1_, _V_2_ ... 包含速度测量值。上表的前两行对应这两个数组。测量值 _d_1_, _d_2_, ... 在不同时间执行。上表的第三行对应这些测量的时间数组。类似地,第四行对应 _V_1_, _V_2_ ... 测量的时间数组。一组地面站用于测量。假设 _d_i_ 是由坐标为 _X_i_, _Y_i_, _Z_i_ 的地面站获得的。表的第5、6、7行对应 _X_i_, _Y_i_, _Z_i_ 数组。类似地,第8-10行对应地面站的坐标和 _V_i_ 测量值。请注意,不同的测量值没有相同的精度。一般线性方法要求对这些测量值使用不同的权重。为此开发了一个新组件 Sigma。它使我们能够创建加权选择。在轨道确定的情况下,测量值具有不同的方差。因此我们遇到了 加权最小二乘 情况。因此需要测量值的方差。第11和12行分别包含 _d_i_ 和 _V_i_ 的方差数组。组件**距离选择**和**速度选择**是包含测量值及其方差的“加权选择”。**距离选择**的属性如下所示

Weighted selection

这张图有以下含义

  • 测量数组包含在**距离**组件的纵坐标中。
  • 方差数组包含在**距离 Sigma** 组件的纵坐标中。

**速度选择**组件以类似的方式构建。我使用了图 图 组件来存储选择。这样做是因为用户可以在没有数据库的情况下尝试此示例。实际上,此场景应该使用与数据库图 数据库图 的连接。

6.2 非线性回归

统计学中的**非线性回归**是拟合模型的问题。y = f(x,\theta) + \varepsilon

针对多维 x,y 数据,其中 fx非线性函数,带有回归参数 θ。

非线性回归操作与选择。该软件实现了两种处理选择的方法。第一种方法迭代加载选择,即逐步加载。第二种方法一次性加载选择。

使用迭代回归的非线性回归软件架构如下图所示

Architecture

让我们描述一下这个方案的组件。迭代器提供选择中的数据 _x_ 和 _y_。_y_ 是拟合方程的**左侧**。**变换**对应于非线性函数 _f_,并生成拟合模型的**左侧**。**处理器**协调所有动作并纠正**回归参数**。

一次性加载选择的软件架构如下图所示

Architecture

处理器将**计算参数**与**选择**进行比较,计算残差,然后修正**回归参数**。在这两个方案中,**迭代器**、**选择**等都不是具体组件。它们是实现**迭代器**、**选择**等接口的组件。例如,**相机**组件可以实现**选择**接口。在这里,我将简要介绍示例。更深入的描述可在该项目的文档中找到。第二个方案用于确定轨道。

6.3 配料

上图包含了非线性回归的一般要素。让我们考虑与轨道确定相关的要素。**选择**已在6.1中考虑。**回归参数**是卫星坐标和速度分量的初始值。这些参数包含在**运动方程**组件中。这些参数如下图所示

Regression parameters

如前所述,参数 _x_、_y_、_x_、_u_、_v_、_w_ 是坐标和速度分量。上图的顶部包含轨道确定之前这些参数的值。底部包含轨道确定之后的值。这些参数在轨道确定过程中会发生变化。变换阶段包含以下步骤

  • 卫星轨迹计算
  • 时间偏移计算
  • 距离和速度计算

**累加器**组件将轨迹参数作为实际函数进行计算。让我们解释一下什么是实际函数。函数有两种定义点。根据势能点函数 _f_(_t_) 是通过已知参数 _t_ 计算 _f_。实际点意味着函数 _f_ 是单个(实际)对象。实际函数可以通过在 _t_ 的不同值下计算 _f_(_t_) 的值从势能函数获得。**运动方程**组件执行运动参数的势能计算,而**累加器**对象将这些势能函数转换为实际函数。**累加器**的属性如下所示

Accumulator

根据这些属性,**累加器**计算 _f_(_t_0_)、_f_(_t_1_)、_f_(_t_2_)、...,其中 _t_0_ = 1770457504(开始),_t_i+1_ - _t_i_ = 10(步长)。参数值的数量等于 2500(步数)。因此,**累加器**存储 _f_(_t_0_)、_f_(_t_1_)、_f_(_t_2_),并且对于任何 _t_0_ < _t_ < _t_2500_。然后 _f_(_t_) 通过三次多项式插值获得。需要注意的是,距离和速度测量不是瞬时的,因为光速是有限的。地面站T1时刻发送信号,卫星T2时刻发送反射信号,然后地面站T3时刻接收信号。测量时间是T3。然而,距离测量并非T3时刻卫星和地面站之间的距离。它等于 (_d_1_ - _d_2_) / 2,其中 _d_1_ 是T1时刻地面站与T2时刻卫星之间的距离,类似地,_d_2_ 是T3时刻地面站与T2时刻卫星之间的距离。**差值**和**时间 + 偏移**组件使我们能够考虑这种情况。**差值**组件的属性如下图所示

Difference

此组件的输出由**时间 + 偏移**使用。**时间 + 偏移**的属性如下所示

Time + Shift

此组件计算卫星信号反射时间数组。组件**Delta**是辅助组件。它具有以下属性

Delta

**测量**组件计算距离和速度的测量值。此组件具有以下属性

Delta

这些参数与选择进行比较。**处理器**组件执行此类计算或(用另一个术语)回归。回归公式如下所示

y = f(x,\theta) + \varepsilon

**处理器**组件反映此公式。此组件的属性如下所示

Processor

上面窗口的左侧对应于回归公式的 _x_。在所考虑的情况下,_x_ 的分量是坐标和速度分量。下表包含向量 _x_ 的分量。

物理参数 标识符
1 X 运动方程/运动方程.x
2 Y 运动方程/运动方程.y
3 Z 运动方程/运动方程.z
4 Vx 运动方程/运动方程.u
5 Vy 运动方程/运动方程.v
6 Vz 运动方程/运动方程.w

上面窗口的中间部分包含回归公式的 _f_(_x_)。_f_(_x_) 向量包含两个子向量 _Formula_1_ 和 _Formula_2_,它们属于**测量**组件。这些子向量是距离和速度的计算值。上面窗口的右侧对应于回归公式的 _y_。向量 _y_ 包含两个选择,分别对应于距离和速度测量。点击 _Iterate_ 按钮启动非线性回归步骤。

7. 卡尔曼滤波

本节包含卡尔曼滤波技术,不涉及任何轨道确定。仅考虑通用理论和简单示例。

7.1 理论

卡尔曼滤波是一种以鲁道夫·E·卡尔曼命名的数学方法。其目的是利用随时间观察到的包含噪声(随机变化)和其他不准确性的测量值,并生成倾向于更接近测量值的真实值及其相关计算值的值。卡尔曼滤波理论不依赖于物理现象。因此,卡尔曼滤波可用于估计不同类型对象(机械、电气、气动等)的状态。此外,卡尔曼滤波理论不依赖于测量类型。任何类型的测量(惯性、电气、温度、光学、核)都是可接受的。因此,卡尔曼滤波是独立于物理背景的工程对象。我们拥有通用的工程对象,这个想法与通用工程软件的想法非常接近。卡尔曼滤波理论如何在没有任何物理背景的情况下存在?它基于抽象方程。其中一些方程如下所示

Kalman Filter Equations

其中 _x_k-1_ 和 _x_k_ 分别是 _k_-1 步和 _k_ 步的状态向量。_z_k_ 是测量向量。向量函数 _f_ 和 _h_ 分别称为转移函数和测量函数。向量 _w_k_ 和 _v_k_。以上所有概念都是抽象的。这些概念与任何特殊工程问题没有直接关系。卡尔曼滤波使用偏导数矩阵

PartialDerivationMatrix.gif

7.2 实施

卡尔曼滤波的实现包含以下矩阵公式集

Kalman Filter Matrix Formulae

Kalman Filter Matrix Formulae

Kalman Filter Matrix Formulae

Kalman Filter Matrix Formulae

Kalman Filter Matrix Formulae

这些公式的实现如下所示

Kalman filter

卡尔曼滤波使用向量和矩阵运算。为此开发了向量 向量 和矩阵 矩阵 组件。下面是卡尔曼滤波的典型用法示例

此图包含所有必要的卡尔曼滤波要素

  • 协方差矩阵
  • 增益派生
  • 与递归贝叶斯估计的关系

矩阵属性编辑器如下所示

Matrix

它将矩阵的元素与外部数据链接。矩阵操作由公式编辑器执行。正如第四部分所述,编辑器区分大小写。例如,公式 _ax_ 的含义可能不同。如果 _a_ 和 _x_ 是实数,则此公式表示普通乘积。如果 _a_ 和 _x_ 是矩阵,则我们有矩阵乘积。如果 _a_ 是矩阵而 _x_ 是向量,则 _ax_ 是矩阵-向量乘积等。在以下情况公式中

Formula

_a_ 和 _h_ 是矩阵,_y_ 和 _z_ 是向量。因此,通过使用向量和矩阵组件,我们可以构建卡尔曼滤波器的任何修改。

8. 人造地球卫星预报

除了计算,任何软件都需要生成文档。文档生成功能在预测问题中得到了展示。预测文档包含卫星在赤道交点时刻的运动参数。下图解释了预测问题

Forecast picture

卫星沿着其轨道运动。运动参数对应于它从南向北穿过赤道的时间。当卫星的 _Z_ 坐标等于 0 时,它穿过赤道。如果我们将坐标和时间作为 _Z_ 的函数,那么我们可以看到必要的参数是这些函数在 _Z_ = 0 时的值。下图表示此任务的解决方案。

Forecast algorithm

**延迟**组件的类型为 FunctionAccumulator。这种类型与 Simulink 的传输延迟非常相似。然而,FunctionAccumulator 更先进。**延迟**的属性如下所示

Delay

**延迟**组件连接到**数据**组件。它存储**数据**的最新输出值。_步数_ = 4 意味着**延迟**存储每个输出参数的最后 4 个值。数据的 _Formula_4_ 是卫星的 _Z_ 坐标。因此,**延迟**的所有参数都被视为 _Z_ 的函数。让我们考虑预测的所有组件。**卫星**组件是一个容器,其中包含卫星的**运动方程**。**数据**组件连接到**运动方程**,并将时间参数添加到运动参数中。**数据**的属性如下所示

Data.

**递归**组件类似于 Simulink 的内存组件。此组件计算 Z 坐标的时间延迟。**递归**元素的属性如下所示

Recursve

Condition 元素用于确定赤道穿越的时间。Condition 的属性如下所示:

Condition

此组件的参数含义包含在注释中。

Condition

最后,Output 组件包含预测参数的计算。它有以下公式:

Output Formulae

86400是每天的秒数。_time_ 函数将 double 变量转换为 DateTime。_b_ 是赤道交叉的条件。输入参数是作为函数Z的运动参数。参数的完整列表包含在以下注释中

Output

最后,Chart 组件具有以下属性:

Chart

这些属性具有以下含义。当条件变量为 true 时执行输出。在这种情况下,条件是 Condition 对象的 _Formula_1_。这是赤道交叉的条件。输出参数是 Output 对象的 _Formula_1_ - _Formula_7_。标签 _X_、_Y_、_Z_、_Vx_、_Vy_、_Vz_ 是 XML 文档中反映的标签。XML 文档如下所示

<Root>
  <Parameters>
    <Parameter Name="T" Value="Monday, June 28, 1999 11:17:05 PM.457" />
    <Parameter Name="X" Value="-6595.47050815637" />
    <Parameter Name="Y" Value="-2472.05799683873" />
    <Parameter Name="Z" Value="0" />
    <Parameter Name="Vx" Value="-0.541295154046453" />
    <Parameter Name="Vy" Value="1.46945520971716" />
    <Parameter Name="Vz" Value="7.45051367374592" />
  </Parameters>
  <Parameters>
    <Parameter Name="T" Value="Tuesday, June 29, 1999 12:55:08 AM.068" />
    <Parameter Name="X" Value="-7026.76544757067" />
    <Parameter Name="Y" Value="487.053173194772" />
    <Parameter Name="Z" Value="0" />
    <Parameter Name="Vx" Value="0.117122882887633" />
    <Parameter Name="Vy" Value="1.56173832654579" />
    <Parameter Name="Vz" Value="7.45055871464937" />
  </Parameters>
 <Root>

第一个参数为 DateTime 类型,其他参数为 double 类型。XML 文档反映了这种情况。XSLT (可扩展样式表语言转换) 用于文档生成。以下代码包含 XSLT 文件。

<xsl:stylesheet version="1.0" xmlns:xsl=http://www.w3.org/1999/XSL/Transform 
    xmlns:msxsl="urn:schemas-microsoft-com:xslt"
    xmlns:user="urn:my-scripts">
  <xsl:template match="/">
    <html>
      <body>
        <p>
          <h1>Forecast</h1>
        </p>
        <xsl:apply-templates />
      </body>
    </html>
  </xsl:template>
  <xsl:template match="Parameters">
    <p></p>
    <p>
      <table border="1">
        <xsl:apply-templates />
      </table>
    </p>
  </xsl:template>
  <xsl:template match="Parameter">
    <xsl:apply-templates />
    <tr>
      <td>
        <xsl:value-of select="@Name" />
      </td>
      <td>
        <xsl:value-of select="@Value" />
      </td>
    </tr>
  </xsl:template>
</xsl:stylesheet>

此 XSLT 代码提供了以下 HTML 文档。

预报

T 1999年6月28日星期一 晚上11:17:05.457
X -6595.47050815637
Y -2472.05799683873
Z 0
Vx -0.541295154046453
Vy 1.46945520971716
Vz 7.45051367374592

T 1999年6月29日星期二 凌晨12:55:08.068
X -7026.76544757067
Y 487.053173194772
Z 0
Vx 0.117122882887633
Vy 1.56173832654579
Vz 7.45055871464937

关注点

有一种观点认为,深入研究需要特定的专业。然而,艾萨克·牛顿爵士是一位伟大的科学家,也是一位铸币局局长。事实上,从事抽象代数(第五部分)并不妨碍解决日常工程问题。

© . All rights reserved.