接下来的4个教程详细介绍了传播包的一些基本用法,这些用法在库架构文档的传播部分中有描述。
根据调用应用程序的需求,传播器可以在初始时间和传播目标时间之间提供中间状态,或者仅提供最终状态。
当用户想要完全控制时间演化时,使用此方法。应用程序给出目标时间,但没有任何步骤处理程序。
让我们将EME2000惯性参考系定义为参考坐标系:
Frame inertialFrame = FramesFactory.getEME2000();
让我们设置一个初始状态:
TimeScale utc = TimeScalesFactory.getUTC();
AbsoluteDate initialDate = new AbsoluteDate(2004, 01, 01, 23, 30, 00.000, utc);
double mu = 3.986004415e+14;
double a = 24396159; // 半长轴,单位为米
double e = 0.72831215; // 偏心率
double i = FastMath.toRadians(7); // 倾角
double omega = FastMath.toRadians(180); // 近地点幅角
double raan = FastMath.toRadians(261); // 升交点赤经
double lM = 0; // 平近点角
初始轨道定义为KeplerianOrbit
。有关轨道表示的更多详细信息可以在库架构文档的轨道部分中找到。
Orbit initialOrbit = new KeplerianOrbit(a, e, i, omega, raan, lM, PositionAngleType.MEAN,
inertialFrame, initialDate, mu);
我们选择使用一个非常简单的KeplerianPropagator
来计算基本的开普勒运动。它可以是任何可用的传播器。
KeplerianPropagator kepler = new KeplerianPropagator(initialOrbit);
最后,定义了持续时间和步长的传播特性,并进行传播循环以便在每个步骤打印结果:
double duration = 600.;
AbsoluteDate finalDate = initialDate.shiftedBy(duration);
double stepT = 60.;
int cpt = 1;
for (AbsoluteDate extrapDate = initialDate;
extrapDate.compareTo(finalDate) <= 0;
extrapDate = extrapDate.shiftedBy(stepT)) {
SpacecraftState currentState = kepler.propagate(extrapDate);
System.out.format(Locale.US, "step %2d %s %s%n",
cpt++, currentState.getDate(), currentState.getOrbit());
}
打印的结果如下所示:
步骤 1 2004-01-01T23:30:00.000 开普勒参数: {a: 2.4396159E7; e: 0.72831215; i: 7.0; pa: 180.0; raan: 261.0; v: 0.0;}
步骤 2 2004-01-01T23:31:00.000 开普勒参数: {a: 2.4396159E7; e: 0.72831215; i: 7.0; pa: 180.0; raan: 261.0; v: 5.281383633573694;}
步骤 3 2004-01-01T23:32:00.000 开普勒参数: {a: 2.4396159E7; e: 0.72831215; i: 7.0; pa: 180.0; raan: 261.0; v: 10.525261309411585;}
步骤 4 2004-01-01T23:33:00.000 开普勒参数: {a: 2.4396159E7; e: 0.72831215; i: 7.0; pa: 180.0; raan: 261.0; v: 15.695876839823306;}
步骤 5 2004-01-01T23:34:00.000 开普勒参数: {a: 2.4396159E7; e: 0.72831215; i: 7.0; pa: 180.0; raan: 261.0; v: 20.76077035517381;}
步骤 6 2004-01-01T23:35:00.000 开普勒参数: {a: 2.4396159E7; e: 0.72831215; i: 7.0; pa: 180.0; raan: 261.0; v: 25.691961427063767;}
步骤 7 2004-01-01T23:36:00.000 开普勒参数: {a: 2.4396159E7; e: 0.72831215; i: 7.0; pa: 180.0; raan: 261.0; v: 30.466680460539763;}
步骤 8 2004-01-01T23:37:00.000 开普勒参数: {a: 2.4396159E7; e: 0.72831215; i: 7.0; pa: 180.0; raan: 261.0; v: 35.06763907945756;}
步骤 9 2004-01-01T23:38:00.000 开普勒参数: {a: 2.4396159E7; e: 0.72831215; i: 7.0; pa: 180.0; raan: 261.0; v: 39.48289615024968;}
步骤 10 2004-01-01T23:39:00.000 开普勒参数: {a: 2.4396159E7; e: 0.72831215; i: 7.0; pa: 180.0; raan: 261.0; v: 43.70541689946282;}
步骤 11 2004-01-01T23:40:00.000 开普勒参数: {a: 2.4396159E7; e: 0.72831215; i: 7.0; pa: 180.0; raan: 261.0; v: 47.732436294590705;}
此示例的完整代码可以在教程的源代码树中找到,文件名为src/main/java/org/orekit/tutorials/propagation/KeplerianPropagation.java
。
为了获取中间状态,用户需要注册一些自定义对象实现OrekitStepHandler
或OrekitFixedStephHandler
如上面的“仅最终状态”示例中所示,让我们定义一些初始状态:
// 惯性参考系
Frame inertialFrame = FramesFactory.getEME2000();
// 初始日期
TimeScale utc = TimeScalesFactory.getUTC();
AbsoluteDate initialDate = new AbsoluteDate(2004, 01, 01, 23, 30, 00.000,utc);
// 中心引力系数
double mu = 3.986004415e+14;
// 初始轨道
double a = 24396159; // 半长轴,单位为米
double e = 0.72831215; // 偏心率
double i = FastMath.toRadians(7); // 倾角
double omega = FastMath.toRadians(180); // 近地点幅角
double raan = FastMath.toRadians(261); // 升交点赤经
double lM = 0; // 平近点角
Orbit initialOrbit = new KeplerianOrbit(a, e, i, omega, raan, lM, PositionAngleType.MEAN,
inertialFrame, initialDate, mu);
// 初始状态定义
SpacecraftState initialState = new SpacecraftState(initialOrbit);
这里我们使用了一个更复杂的NumericalPropagator
,它基于底层的Hipparchus库提供的自适应步长积分器,但使用哪个积分器并不重要。
// 自适应步长积分器
// 最小步长为0.001,最大步长为1000
double minStep = 0.001;
double maxstep = 1000.0;
double positionTolerance = 10.0;
OrbitType propagationType = OrbitType.KEPLERIAN;
double[][] tolerances =
NumericalPropagator.tolerances(positionTolerance, initialOrbit, propagationType);
AdaptiveStepsizeIntegrator integrator =
new DormandPrince853Integrator(minStep, maxstep, tolerances[0], tolerances[1]);
我们设置了积分器,并强制其使用开普勒参数进行传播。
NumericalPropagator propagator = new NumericalPropagator(integrator);
propagator.setOrbitType(propagationType);
一个力模型,这里简化为单个扰动引力场,被考虑在内。有关力模型的更多细节可以在库架构文档的力模型部分找到。
NormalizedSphericalHarmonicsProvider provider =
GravityFieldFactory.getNormalizedProvider(10, 10);
ForceModel holmesFeatherstone =
new HolmesFeatherstoneAttractionModel(FramesFactory.getITRF(IERSConventions.IERS_2010,
true),
provider)
这个力模型简单地添加到了传播器中:
propagator.addForceModel(holmesFeatherstone);
然后,为传播器设置初始状态:
propagator.setInitialState(initialState);
传播器的配置通过一个固定步长的TutorialStepHandler
完成,该类实现了OrekitFixedStepHandler
接口,以便在循环中调用handleStep
方法。对于本教程,handleStep
方法只会在每个步长时打印当前状态。
propagator.getMultiplexer().add(60., new TutorialStepHandler());
最后,传播器只需从初始状态开始,传播一定的时间。
SpacecraftState finalState = propagator.propagate(new AbsoluteDate(initialDate, 630.));
显然,通过几行代码,主应用程序将定期输出的处理委托给传播器,通过变步长积分循环。
只需要从OrekitFixedStepHandler
接口派生出一些类,实现handleStep
方法,如下所示:
private static class TutorialStepHandler implements OrekitFixedStepHandler {
public void init(final SpacecraftState s0, final AbsoluteDate t, final double step) {
System.out.println(" 日期 a e" +
" i \u03c9 \u03a9" +
" \u03bd");
}
public void handleStep(SpacecraftState currentState) {
KeplerianOrbit o = (KeplerianOrbit) OrbitType.KEPLERIAN.convertType(currentState.getOrbit());
System.out.format(Locale.US, "%s %12.3f %10.8f %10.6f %10.6f %10.6f %10.6f%n",
currentState.getDate(),
o.getA(), o.getE(),
FastMath.toDegrees(o.getI()),
FastMath.toDegrees(o.getPerigeeArgument()),
FastMath.toDegrees(o.getRightAscensionOfAscendingNode()),
FastMath.toDegrees(o.getTrueAnomaly()));
}
public void finish(final SpacecraftState finalState) {
System.out.println("这是最后一步");
System.out.println();
}
}
打印的结果如下所示:
日期 a e i ω Ω ν
2004-01-01T23:30:00.000Z 24396159.000 0.72831215 7.000000 180.000000 261.000000 0.000000
2004-01-01T23:31:00.000Z 24395672.948 0.72830573 6.999927 180.010992 260.999966 5.270439
2004-01-01T23:32:00.000Z 24394149.110 0.72828580 6.999758 180.021885 260.999767 10.503710
2004-01-01T23:33:00.000Z 24391676.555 0.72825352 6.999506 180.032557 260.999281 15.664370
2004-01-01T23:34:00.000Z 24388396.501 0.72821073 6.999190 180.042889 260.998422 20.720220
2004-01-01T23:35:00.000Z 24384487.471 0.72815976 6.998827 180.052785 260.997139 25.643463
2004-01-01T23:36:00.000Z 24380142.510 0.72810308 6.998434 180.062182 260.995416 30.411433
2004-01-01T23:37:00.000Z 24375546.779 0.72804310 6.998029 180.071043 260.993268 35.006866
2004-01-01T23:38:00.000Z 24370861.668 0.72798191 6.997624 180.079354 260.990738 39.417786
2004-01-01T23:39:00.000Z 24366216.959 0.72792119 6.997234 180.087112 260.987893 43.637076
2004-01-01T23:40:00.000Z 24361709.735 0.72786221 6.996868 180.094320 260.984809 47.661865
这是最后一步
最终状态:
2004-01-01T23:40:30.000 24359529.816 0.72783366 6.996697 180.097720 260.983203 49.601407
这个示例的完整代码可以在库的源代码树中找到,文件位于 src/main/java/org/orekit/tutorials/propagation/NumericalPropagation.java
。
当用户需要在初始日期和结束日期之间的任意时间访问轨道状态时,可以使用第三种模式。
与上面的两个示例一样,首先定义一些初始状态:
// 惯性坐标系
Frame inertialFrame = FramesFactory.getEME2000();
// 初始日期
TimeScale utc = TimeScalesFactory.getUTC();
AbsoluteDate initialDate = new AbsoluteDate(2004, 01, 01, 23, 30, 00.000, utc);
// 中心引力系数
double mu = 3.986004415e+14;
// 初始轨道
double a = 24396159; // 半长轴,单位为米
double e = 0.72831215; // 偏心率
double i = FastMath.toRadians(7); // 倾角
double omega = FastMath.toRadians(180); // 近地点幅角
double raan = FastMath.toRadians(261); // 升交点赤经
double lM = 0; // 平近点角
Orbit initialOrbit = new KeplerianOrbit(a, e, i, omega, raan, lM, PositionAngleType.MEAN,
inertialFrame, initialDate, mu);
// 初始状态定义
SpacecraftState initialState = new SpacecraftState(initialOrbit);
这里使用了一个简单的NumericalPropagator
,没有考虑扰动,基于底层的Hipparchus库提供的经典固定步长龙格-库塔积分器。
double stepSize = 10;
AbstractIntegrator integrator = new ClassicalRungeKuttaIntegrator(stepSize);
NumericalPropagator propagator = new NumericalPropagator(integrator);
为该传播器设置初始状态:
propagator.setInitialState(initialState);
然后使用传播器的星历生成器:
final EphemerisGenerator generator = propagator.getEphemerisGenerator();
并对给定的持续时间进行传播。
SpacecraftState finalState = propagator.propagate(initialDate.shiftedBy(6000));
这个finalState
可以用于任何用途,例如打印如下所示:
数值传播:
最终日期:2004-01-02T01:10:00.000Z
等时参数:{a: 2.4396159E7;
ex: 0.11393312156755062; ey: 0.719345418868777;
hx: -0.009567941763699867; hy: -0.06040960680288257;
lv: 583.1250344407331;}
在传播过程中,中间状态存储在一个星历中,可以通过单个调用来恢复:
BoundedPropagator ephemeris = generator.getGeneratedEphemeris();
System.out.println(" 从 " + ephemeris.getMinDate() + " 到 " + ephemeris.getMaxDate() + " 定义的星历");
星历被定义为BoundedPropagator
,这意味着它只在传播的初始日期和最终日期之间有效。上面的代码给出了以下结果:
星历定义从2004-01-01T23:30:00.000Z到2004-01-02T01:10:00.000
在这些日期之间,星历可以像任何传播器一样使用,通过一次调用将轨道状态传播到任何中间日期:
SpacecraftState intermediateState = ephemeris.propagate(intermediateDate);
下面是将中间日期设置为开始日期之后3000秒和正好是最终日期的结果:
星历传播:
日期:2004-01-02T00:20:00.000Z
赤道参数:{a: 2.4396159E7;
ex: 0.11393312156755062; ey: 0.719345418868777;
hx: -0.009567941763699867; hy: -0.06040960680288257;
lv: 559.0092657655282;}
日期:2004-01-02T01:10:00.000Z
赤道参数:{a: 2.4396159E7;
ex: 0.11393312156755062; ey: 0.719345418868777;
hx: -0.009567941763699867; hy: -0.06040960680288257;
lv: 583.1250344407331;}
下面显示了当我们尝试使用超出星历范围的日期时(在这种情况下,中间日期设置为星历开始前1000秒),我们得到的错误消息:
星历范围外的日期:2004-01-01T23:13:20.000Z在[2004-01-01T23:30:00.000Z, 2004-01-02T01:10:00.000Z]之前1.0E3秒
此示例的完整代码可以在库的源代码树中的文件src/main/java/org/orekit/tutorials/propagation/EphemerisMode.java
中找到。
本教程旨在演示事件处理机制的强大和简单性。
我们需要在某个时间范围内检查卫星和地面站之间的可见性。
我们将使用并扩展预定义的ElevationDetector
来执行任务。
首先,让我们为卫星设置一个初始状态,该状态由某个惯性参考系中某个日期的位置和速度定义。
Vector3D position = new Vector3D(-6142438.668, 3492467.560, -25767.25680);
Vector3D velocity = new Vector3D(505.8479685, 942.7809215, 7435.922231);
PVCoordinates pvCoordinates = new PVCoordinates(position, velocity);
AbsoluteDate initialDate =
new AbsoluteDate(2004, 01, 01, 23, 30, 00.000, TimeScalesFactory.getUTC());
Frame inertialFrame = FramesFactory.getEME2000();
我们还需要设置中心引力系数,以将初始轨道定义为KeplerianOrbit
。
double mu = 3.986004415e+14;
Orbit initialOrbit =
new KeplerianOrbit(pvCoordinates, inertialFrame, initialDate, mu);
有关轨道表示的更多细节可以在库架构文档的轨道部分找到。
作为传播器,我们考虑使用KeplerianPropagator
来计算简单的开普勒运动。它可以更复杂,而不改变本教程的通用目的。
Propagator kepler = new KeplerianPropagator(initialOrbit);
然后,让我们通过其坐标将地面站定义为GeodeticPoint
:
double longitude = FastMath.toRadians(45.);
double latitude = FastMath.toRadians(25.);
double altitude = 0.;
GeodeticPoint station1 = new GeodeticPoint(latitude, longitude, altitude);
并将其与与某个地球参考系中的BodyShape
相关联的TopocentricFrame
关联起来。
Frame earthFrame = FramesFactory.getITRF(IERSConventions.IERS_2010, true);
BodyShape earth = new OneAxisEllipsoid(Constants.WGS84_EARTH_EQUATORIAL_RADIUS,
Constants.WGS84_EARTH_FLATTENING,
earthFrame);
TopocentricFrame sta1Frame = new TopocentricFrame(earth, station1, "station1");
有关BodyShape
和GeodeticPoint
的更多细节可以在库架构文档的天体部分找到。
有关TopocentricFrame
的更多细节可以在库架构文档的参考系部分找到。
EventDetector
被定义为具有恒定高程限制和专用处理程序的ElevationDetector
,在这种简单情况下,可以将其内联编写为实现EventHandler
接口的eventOccurred
方法的lambda函数:
double maxcheck = 60.0;
double threshold = 0.001;
double elevation = FastMath.toRadians(5.);
EventDetector sta1Visi =
new ElevationDetector(maxcheck, threshold, sta1Frame).
withConstantElevation(elevation).
withHandler((s, detector, increasing) -> {
System.out.println(" 在 " +
detector.getTopocentricFrame().getName() +
(increasing ? " 开始可见性 " : " 结束可见性 ") +
s.getDate().toStringWithoutUtcOffset(utc, 3));
return increasing ? Action.CONTINUE : Action.STOP;
});
将此EventDetector
添加到传播器中:
kepler.addEventDetector(sta1Visi);
传播器将从初始日期传播到第一次升起或按照VisibilityHandler
类中实现的行为进行固定持续时间的传播。
SpacecraftState finalState =
kepler.propagate(new AbsoluteDate(initialDate, 1500.));
System.out.println(" 最终状态 : " + finalState.getDate().durationFrom(initialDate));
打印的结果如下所示。我们可以看到传播在检测到设置后停止:
在 station1 上开始可见性 2004-01-01T23:31:52.098
在 station1 上结束可见性 2004-01-01T23:42:48.850
从初始日期到最终状态的持续时间(秒):768.850267132939
此示例的完整代码可以在教程的源代码树中的文件src/main/java/org/orekit/tutorials/propagation/VisibilityCheck.java
中找到。