姿态

本教程强调了姿态包的特定用法,该用法在库架构文档的姿态部分中有描述。

姿态序列

AttitudesSequence 在传播某个SpacecraftState时,可以在事件发生时轻松切换姿态法。

让我们设置一个初始状态:

  • 一个在UTC时间尺度上的日期
  • 由航天器在EME2000惯性参考系中的位置和速度以及在Orekit中可用的许多物理常数中选择的相关中心引力系数定义的轨道。

初始轨道在这里被定义为一个KeplerianOrbit。 TimeScale utc = TimeScalesFactory.getUTC(); AbsoluteDate initialDate = new AbsoluteDate(2004, 01, 01, 23, 30, 00.000, utc); Vector3D position = new Vector3D(-6142438.668, 3492467.560, -25767.25680); Vector3D velocity = new Vector3D(505.8479685, 942.7809215, 7435.922231); Orbit initialOrbit = new KeplerianOrbit(new PVCoordinates(position, velocity), FramesFactory.getEME2000(), initialDate, Constants.EIGEN5C_EARTH_MU);

有关轨道表示的更多详细信息可以在库架构文档的轨道部分找到。

我们将所有切换事件放在一个集合中。

final SortedSet<String> output = new TreeSet<>();

让我们定义一对AttitudeProvider,例如基于LofOffset法则。

final AttitudeProvider dayObservationLaw = new LofOffset(initialOrbit.getFrame(), LOFType.VVLH,
                                                         RotationOrder.XYZ, FastMath.toRadians(20), FastMath.toRadians(40), 0);
final AttitudeProvider nightRestingLaw   = new LofOffset(initialOrbit.getFrame(), LOFType.VVLH);

我们还定义了一些EventDetector。根据本教程的要求,有两个EclipseDetector,每个都使用一个定制的EventHandler实现和一个专用的eventOccurred方法:dayNightEvent用于检测白天到夜晚的过渡,nightDayEvent用于检测夜晚到白天的过渡:

PVCoordinatesProvider sun   = CelestialBodyFactory.getSun();
PVCoordinatesProvider earth = new OneAxisEllipsoid(Constants.WGS84_EARTH_EQUATORIAL_RADIUS,
                                                   0.0,
                                                   FramesFactory.getITRF(IERSConventions.IERS_2010, true));
EventDetector dayNightEvent = new EclipseDetector(sun, 696000000., earth).
                              withHandler(new ContinueOnEvent());
EventDetector nightDayEvent = new EclipseDetector(sun, 696000000., earth).
                              withHandler(new ContinueOnEvent());

有关事件检测器和事件处理器的更多详细信息可以在库架构文档的传播部分找到。

为了本教程的目的,我们定义了一个AttitudesSequence,通过添加两个作为简单循环的切换条件来定义:

  • 第一个条件是在发生递减的dayNightEvent时,从dayObservationLaw切换到nightRestingLaw
  • 第二个条件是在发生递增的nightDayEvent时,从nightRestingLaw切换到dayObservationLaw

由于这两个条件相互抵消,组合的AttitudesSequence就像一个循环。我们还定义了一个处理程序来监视姿态切换:

AttitudesSequence attitudesSequence = new AttitudesSequence();
AttitudesSequence.SwitchHandler switchHandler =
            (preceding, following, s) -> {
                if (preceding == dayObservationLaw) {
                    output.add(s.getDate().toStringWithoutUtcOffset(utc, 3) + ": 切换到夜间定律");
                } else {
                    output.add(s.getDate().toStringWithoutUtcOffset(utc, 3) + ": 切换到白天定律");
                }
            };
attitudesSequence.addSwitchingCondition(dayObservationLaw, nightRestingLaw, dayNightEvent,
                                        false, true, 10.0,
                                        AngularDerivativesFilter.USE_R, switchHandler);
attitudesSequence.addSwitchingCondition(nightRestingLaw, dayObservationLaw, nightDayEvent,
                                        true, false, 10.0,
                                        AngularDerivativesFilter.USE_R, switchHandler);

一个AttitudesSequence至少需要一个切换条件才有意义,但没有上限。

一个活动的AttitudeProvider可以有多个切换事件和下一个定律设置,根据触发的事件不同,会导致不同的激活模式。

不要忘记根据初始状态设置初始活动定律:

if (dayNightEvent.g(new SpacecraftState(initialOrbit)) >= 0) {
    // 初始位置在白天
    attitudesSequence.resetActiveProvider(dayObservationLaw);
} else {
    // 初始位置在夜间
    attitudesSequence.resetActiveProvider(nightRestingLaw);
}

现在,让我们选择一些用于计算航天器运动的传播器。我们将使用基于解析Eckstein-Hechler模型的EcksteinHechlerPropagator。传播器基于初始轨道、姿态序列和潜力的物理常数构建。

Propagator propagator = new EcksteinHechlerPropagator(initialOrbit, attitudesSequence,
                                                      Constants.EIGEN5C_EARTH_EQUATORIAL_RADIUS,
                                                      Constants.EIGEN5C_EARTH_MU, Constants.EIGEN5C_EARTH_C20,
                                                      Constants.EIGEN5C_EARTH_C30, Constants.EIGEN5C_EARTH_C40,
                                                      Constants.EIGEN5C_EARTH_C50, Constants.EIGEN5C_EARTH_C60);

attitudeSequence必须在传播之前注册所有的切换事件。

attitudesSequence.registerSwitchEvents(propagator);

传播器的操作模式通过固定步长处理器完成。接口OrekitFixedStepHandler的实现旨在定义循环中调用的handleStep方法。在本教程中,handleStep方法将在当前日期打印两个角度,第一个角度指示航天器是否被遮挡,第二个角度提供当前的姿态法。

propagator.getMultiplexer().add(180.0, (currentState, isLast) -> {
        DecimalFormatSymbols angleDegree = new DecimalFormatSymbols(Locale.US);
        angleDegree.setDecimalSeparator('\u00b0');
        DecimalFormat ad = new DecimalFormat(" 00.000;-00.000", angleDegree);

        // 航天器坐标系中的地球位置应该沿着航天器的Z轴,在夜间时远离它,在白天时由于滚动和俯仰偏移而靠近它
        final Vector3D earthDir = currentState.toTransform().transformPosition(Vector3D.ZERO);
        final double pointingOffset = Vector3D.angle(earthDir, Vector3D.PLUS_K);

        // g函数是日食指示器,它是太阳和地球边缘之间的角度,
        // 当太阳在地球边缘之外时为正,当太阳被地球边缘遮挡时为负
        final double eclipseAngle = dayNightEvent.g(currentState);

        output.add(currentState.getDate().toStringWithoutUtcOffset(utc, 3) +
                   " " + ad.format(FastMath.toDegrees(eclipseAngle) +
                   " " + ad.format(FastMath.toDegrees(pointingOffset)));
    }
});

有关步骤管理的更多详细信息,请参阅库架构文档中的传播部分

最后,只需要求传播器在给定的持续时间内传播,并打印结果:

SpacecraftState finalState = propagator.propagate(initialDate.shiftedBy(12600.));
for (final String line : output) {
    System.out.println(line);
}

请注意,我们使用一个中间的SortedSet来首先收集切换事件和步骤输出,而不是直接让事件处理器和步骤处理器直接打印结果。这样做的原因是,由于事件处理器可能会截断步骤(如果它们的eventOccurred方法返回Action.STOP),库的设计总是先调用事件处理器的eventOccurred方法,然后再调用步骤处理器的handleStep方法,如果事件处理器决定停止传播,则正确设置isLast布尔值。一个副作用是,如果两个方法都打印一些内容,那么步骤结束时的切换将首先被打印,然后才是步骤本身,这将导致输出顺序错误。SortedSet确保各行将按字典顺序排序,这里是按时间顺序排序,尽管它们在事件发生附近稍微有些无序生成。

随着传播的进行,事件会从一个姿态控制法切换到另一个。

打印的结果如下所示:

2004-01-01T23:30:00.000 -11°630  00°000
2004-01-01T23:33:00.000 -17°804  00°000
2004-01-01T23:36:00.000 -22°432  00°000
2004-01-01T23:39:00.000 -24°945  00°000
2004-01-01T23:42:00.000 -24°937  00°000
2004-01-01T23:45:00.000 -22°425  00°000
2004-01-01T23:48:00.000 -17°843  00°000
2004-01-01T23:51:00.000 -11°764  00°000
2004-01-01T23:54:00.000 -04°681  00°000
2004-01-01T23:55:50.363: 切换到白天法则
2004-01-01T23:57:00.000  03°050  43°958
2004-01-02T00:00:00.000  11°186  43°958
2004-01-02T00:03:00.000  19°556  43°958
2004-01-02T00:06:00.000  28°028  43°958
2004-01-02T00:09:00.000  36°484  43°958
2004-01-02T00:12:00.000  44°797  43°958
2004-01-02T00:15:00.000  52°808  43°958
2004-01-02T00:18:00.000  60°296  43°958
2004-01-02T00:21:00.000  66°944  43°958
2004-01-02T00:24:00.000  72°308  43°958
2004-01-02T00:27:00.000  75°830  43°958
2004-01-02T00:30:00.000  76°995  43°958
2004-01-02T00:33:00.000  75°605  43°958
2004-01-02T00:36:00.000  71°918  43°958
2004-01-02T00:39:00.000  66°468  43°958
2004-01-02T00:42:00.000  59°792  43°958
2004-01-02T00:45:00.000  52°301  43°958
2004-01-02T00:48:00.000  44°283  43°958
2004-01-02T00:51:00.000  35°938  43°958
2004-01-02T00:54:00.000  27°420  43°958
2004-01-02T00:57:00.000  18°858  43°958
2004-01-02T01:00:00.000  10°383  43°958
2004-01-02T01:03:00.000  02°148  43°958
2004-01-02T01:03:48.386: 切换到夜间法则
2004-01-02T01:06:00.000 -05°646  00°000
2004-01-02T01:09:00.000 -12°720  00°000
2004-01-02T01:12:00.000 -18°680  00°000
2004-01-02T01:15:00.000 -23°002  00°000
2004-01-02T01:18:00.000 -25°124  00°000
2004-01-02T01:21:00.000 -24°693  00°000
2004-01-02T01:24:00.000 -21°807  00°000
2004-01-02T01:27:00.000 -16°943  00°000
2004-01-02T01:30:00.000 -10°670  00°000
2004-01-02T01:33:00.000 -03°460  00°000
2004-01-02T01:34:21.084: 切换到白天法则
2004-01-02T01:36:00.000  04°351  43°958
2004-01-02T01:39:00.000  12°536  43°958
2004-01-02T01:42:00.000  20°931  43°958
2004-01-02T01:45:00.000  29°408  43°958
2004-01-02T01:48:00.000  37°851  43°958
2004-01-02T01:51:00.000  46°127  43°958
2004-01-02T01:54:00.000  54°070  43°958
2004-01-02T01:57:00.000  61°447  43°958
2004-01-02T02:00:00.000  67°920  43°958
2004-01-02T02:03:00.000  73°024  43°958
2004-01-02T02:06:00.000  76°194  43°958
2004-01-02T02:09:00.000  76°944  43°958
2004-01-02T02:12:00.000  75°151  43°958
2004-01-02T02:15:00.000  71°137  43°958
2004-01-02T02:18:00.000  65°454  43°958
2004-01-02T02:21:00.000  58°620  43°958
2004-01-02T02:24:00.000  51°026  

这个示例的完整代码可以在教程的源代码树中找到,文件名为 src/main/java/org/orekit/tutorials/attitude/EarthObservation.java