本教程强调了姿态包的特定用法,该用法在库架构文档的姿态部分中有描述。
AttitudesSequence
在传播某个SpacecraftState
时,可以在事件发生时轻松切换姿态法。
让我们设置一个初始状态:
初始轨道在这里被定义为一个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
。