Commit 9853acdf authored by Luc Maisonobe's avatar Luc Maisonobe

Merge branch 'issue-7' into 'master'

Issue 7

See merge request !12
parents d912fb2a 6496fa60
Pipeline #694 passed with stages
in 2 minutes and 25 seconds
......@@ -27,7 +27,7 @@
<orekit-tutorials.build-helper-maven-plugin.version>3.2.0</orekit-tutorials.build-helper-maven-plugin.version>
<orekit-tutorials.maven-gpg-plugin.version>1.6</orekit-tutorials.maven-gpg-plugin.version>
<orekit-tutorials.maven-install-plugin.version>3.0.0-M1</orekit-tutorials.maven-install-plugin.version>
<orekit-tutorials.orekit.version>10.2</orekit-tutorials.orekit.version>
<orekit-tutorials.orekit.version>10.3-SNAPSHOT</orekit-tutorials.orekit.version>
<orekit-tutorials.hipparchus.version>1.7</orekit-tutorials.hipparchus.version>
<orekit-tutorials.jackson.version>2.9.9</orekit-tutorials.jackson.version>
<orekit-tutorials.compiler.source>1.8</orekit-tutorials.compiler.source>
......
......@@ -20,6 +20,15 @@
<title>Orekit Tutorials Changes</title>
</properties>
<body>
<release version="10.3" date="TBC"
description="TBC.">
<action dev="luc" type="add" issue="7">
Added tutorial for constant thrust maneuvers.
</action>
<action dev="luc" type="add" issue="7">
Added tutorial for impulsive maneuvers.
</action>
</release>
<release version="10.2" date="2020-07-16"
description="Version 10.2 is the second release of the Orekit Tutorials.
The version number is 10.2 to follow Orekit version number.
......
/* Copyright 2002-2020 CS GROUP
* Licensed to CS GROUP (CS) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* CS licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.orekit.tutorials.maneuvers;
import java.io.File;
import java.util.Locale;
import org.hipparchus.geometry.euclidean.threed.Rotation;
import org.hipparchus.geometry.euclidean.threed.Vector3D;
import org.hipparchus.ode.nonstiff.AdaptiveStepsizeIntegrator;
import org.hipparchus.ode.nonstiff.DormandPrince853Integrator;
import org.hipparchus.util.FastMath;
import org.orekit.attitudes.AttitudeProvider;
import org.orekit.attitudes.InertialProvider;
import org.orekit.attitudes.LofOffset;
import org.orekit.data.DataContext;
import org.orekit.data.DataProvidersManager;
import org.orekit.data.DirectoryCrawler;
import org.orekit.errors.OrekitException;
import org.orekit.forces.maneuvers.Maneuver;
import org.orekit.forces.maneuvers.propulsion.BasicConstantThrustPropulsionModel;
import org.orekit.forces.maneuvers.propulsion.PropulsionModel;
import org.orekit.forces.maneuvers.trigger.DateBasedManeuverTriggers;
import org.orekit.forces.maneuvers.trigger.ManeuverTriggers;
import org.orekit.frames.Frame;
import org.orekit.frames.FramesFactory;
import org.orekit.frames.LOFType;
import org.orekit.orbits.KeplerianOrbit;
import org.orekit.orbits.Orbit;
import org.orekit.orbits.OrbitType;
import org.orekit.orbits.PositionAngle;
import org.orekit.propagation.SpacecraftState;
import org.orekit.propagation.numerical.NumericalPropagator;
import org.orekit.time.AbsoluteDate;
import org.orekit.time.DateComponents;
import org.orekit.time.TimeComponents;
import org.orekit.time.TimeScalesFactory;
import org.orekit.utils.Constants;
/**
* Orekit tutorial for an apogee maneuver.
*
* @author Luc Maisonobe
*/
public class ApogeeManeuver {
/** Private constructor for utility class. */
private ApogeeManeuver() {
// empty
}
/**
* Program entry point.
* @param args program arguments (unused here)
*/
public static void main(final String[] args) {
try {
// configure Orekit
final File home = new File(System.getProperty("user.home"));
final File orekitData = new File(home, "orekit-data");
if (!orekitData.exists()) {
System.err.format(Locale.US, "Failed to find %s folder%n",
orekitData.getAbsolutePath());
System.err.format(Locale.US, "You need to download %s from %s, unzip it in %s and rename it 'orekit-data' for this tutorial to work%n",
"orekit-data-master.zip", "https://gitlab.orekit.org/orekit/orekit-data/-/archive/master/orekit-data-master.zip",
home.getAbsolutePath());
System.exit(1);
}
final DataProvidersManager manager = DataContext.getDefault().getDataProvidersManager();
manager.addProvider(new DirectoryCrawler(orekitData));
// set up initial GTO orbit
final Frame eme2000 = FramesFactory.getEME2000();
final AbsoluteDate date = new AbsoluteDate(new DateComponents(2004, 01, 01),
new TimeComponents(23, 30, 00.000),
TimeScalesFactory.getUTC());
final Orbit orbit =
new KeplerianOrbit(24396159, 0.72831215, FastMath.toRadians(7),
FastMath.toRadians(180), FastMath.toRadians(261),
FastMath.toRadians(0), PositionAngle.TRUE,
eme2000, date,
Constants.EIGEN5C_EARTH_MU);
final SpacecraftState initialState = new SpacecraftState(orbit, 2500.0);
// prepare numerical propagator
final OrbitType orbitType = OrbitType.EQUINOCTIAL;
final double[][] tol = NumericalPropagator.tolerances(1.0, orbit, orbitType);
final AdaptiveStepsizeIntegrator integrator =
new DormandPrince853Integrator(0.001, 1000, tol[0], tol[1]);
integrator.setInitialStepSize(60);
final NumericalPropagator propagator = new NumericalPropagator(integrator);
propagator.setInitialState(initialState);
propagator.setAttitudeProvider(new LofOffset(eme2000, LOFType.VNC));
// set up an attitude law dedicated to the maneuver
// where the +X axis (direction of acceleration of the thruster)
// points towards a specific direction
final Vector3D direction = new Vector3D(FastMath.toRadians(-7.4978),
FastMath.toRadians(351));
final AttitudeProvider attitudeOverride =
new InertialProvider(new Rotation(direction, Vector3D.PLUS_I),
eme2000);
// maneuver will start at a known date and stop after a known duration
final AbsoluteDate firingDate = new AbsoluteDate(new DateComponents(2004, 1, 2),
new TimeComponents(4, 15, 34.080),
TimeScalesFactory.getUTC());
final double duration = 3653.99;
final ManeuverTriggers triggers = new DateBasedManeuverTriggers(firingDate, duration);
// maneuver has constant thrust
final double thrust = 420;
final double isp = 318;
final PropulsionModel propulsionModel =
new BasicConstantThrustPropulsionModel(thrust, isp,
Vector3D.PLUS_I,
"apogee-engine");
// build maneuver and add it to the propagator as a new force model
propagator.addForceModel(new Maneuver(attitudeOverride, triggers, propulsionModel));
// progress monitoring
propagator.setMasterMode(120.0, (state, isLast) ->
System.out.format(Locale.US, "%s a = %12.3f m, e = %11.9f, m = %8.3f kg%n",
state.getDate(), state.getA(), state.getE(), state.getMass())
);
// propagate orbit, including maneuver
propagator.propagate(firingDate.shiftedBy(-900), firingDate.shiftedBy(duration + 900));
System.exit(0);
} catch (OrekitException e) {
System.err.println(e.getLocalizedMessage());
System.exit(1);
}
}
}
/* Copyright 2002-2020 CS GROUP
* Licensed to CS GROUP (CS) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* CS licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.orekit.tutorials.maneuvers;
import java.io.File;
import java.util.Locale;
import org.hipparchus.geometry.euclidean.threed.Vector3D;
import org.hipparchus.util.FastMath;
import org.orekit.attitudes.AttitudeProvider;
import org.orekit.attitudes.LofOffset;
import org.orekit.data.DataContext;
import org.orekit.data.DataProvidersManager;
import org.orekit.data.DirectoryCrawler;
import org.orekit.errors.OrekitException;
import org.orekit.forces.maneuvers.ImpulseManeuver;
import org.orekit.frames.Frame;
import org.orekit.frames.FramesFactory;
import org.orekit.frames.LOFType;
import org.orekit.orbits.KeplerianOrbit;
import org.orekit.orbits.Orbit;
import org.orekit.orbits.PositionAngle;
import org.orekit.propagation.analytical.KeplerianPropagator;
import org.orekit.propagation.events.EnablingPredicate;
import org.orekit.propagation.events.EventDetector;
import org.orekit.propagation.events.EventEnablingPredicateFilter;
import org.orekit.propagation.events.NodeDetector;
import org.orekit.propagation.events.handlers.StopOnIncreasing;
import org.orekit.time.AbsoluteDate;
import org.orekit.time.DateComponents;
import org.orekit.time.TimeComponents;
import org.orekit.time.TimeScalesFactory;
import org.orekit.utils.Constants;
/**
* Orekit tutorial for simple impulsive maneuver.
*
* <p>This tutorial shows a basic usage for performing
* an impulsive inclination maneuver at node.</p>
* @author Luc Maisonobe
*/
public class ImpulseAtNode {
/** Private constructor for utility class. */
private ImpulseAtNode() {
// empty
}
/**
* Program entry point.
* @param args program arguments (unused here)
*/
public static void main(final String[] args) {
try {
// configure Orekit
final File home = new File(System.getProperty("user.home"));
final File orekitData = new File(home, "orekit-data");
if (!orekitData.exists()) {
System.err.format(Locale.US, "Failed to find %s folder%n",
orekitData.getAbsolutePath());
System.err.format(Locale.US, "You need to download %s from %s, unzip it in %s and rename it 'orekit-data' for this tutorial to work%n",
"orekit-data-master.zip", "https://gitlab.orekit.org/orekit/orekit-data/-/archive/master/orekit-data-master.zip",
home.getAbsolutePath());
System.exit(1);
}
final DataProvidersManager manager = DataContext.getDefault().getDataProvidersManager();
manager.addProvider(new DirectoryCrawler(orekitData));
// set up an initial orbit, with 50 degrees inclination
final Frame eme2000 = FramesFactory.getEME2000();
final Orbit initialOrbit =
new KeplerianOrbit(8000000.0, 0.01,
FastMath.toRadians(50.0), // ← this is initial inclination
FastMath.toRadians(140.0),
FastMath.toRadians(12.0),
FastMath.toRadians(-60.0), PositionAngle.MEAN,
eme2000,
new AbsoluteDate(new DateComponents(2008, 6, 23),
new TimeComponents(14, 0, 0),
TimeScalesFactory.getUTC()),
Constants.EIGEN5C_EARTH_MU);
// the maneuver will be defined in spacecraft frame
// we need to ensure the Z axis is aligned with orbital momentum
// so we select an attitude aligned with LVLH Local Orbital frame
final AttitudeProvider attitudeProvider = new LofOffset(eme2000, LOFType.LVLH);
// we want to perform a series of 3 inclination reduction maneuvers,
// as they modify only inclination, they must occur at node
// but not all nodes are suitable, we want ascending nodes, with a ΔV along -Z
// the maneuvers are triggered when Action.STOP events occur (and are filtered out)
final NodeDetector ascendingNodeStopper =
new NodeDetector(FramesFactory.getEME2000()).
withMaxCheck(300.0).
withThreshold(1.0e-6).
withHandler(new StopOnIncreasing<>());
// we allow only maneuvers on the first 3 orbits
final AbsoluteDate lastAllowedDate =
initialOrbit.getDate().shiftedBy(3 * initialOrbit.getKeplerianPeriod());
final EnablingPredicate<EventDetector> predicate =
(state, detector, g) -> state.getDate().isBefore(lastAllowedDate);
final EventDetector trigger =
new EventEnablingPredicateFilter<>(ascendingNodeStopper, predicate);
// create the maneuver, using ascending node detector as a trigger
final ImpulseManeuver<EventDetector> maneuver =
new ImpulseManeuver<>(trigger,
new Vector3D(0.0, 0.0, -122.25), // ← 122.25 m/s along -Z
350.0);
// wrap-up everything in a propagator
// note that ImpulseManeuver is a event detector, not a force model!
// this allows it to be used for all propagators, including analytical ones
// like the Keplerian propagator used here
final KeplerianPropagator propagator = new KeplerianPropagator(initialOrbit, attitudeProvider);
propagator.addEventDetector(maneuver);
// progress monitoring: we should see inclination remain constant as we
// cross descending nodes (i.e. switch from Northern to Southern
// hemisphere), and change as we cross the first three ascending nodes
propagator.setMasterMode(900.0, (state, isLast) -> {
final Vector3D pos = state.getPVCoordinates(eme2000).getPosition();
System.out.format(Locale.US, "%s %s hemisphere inclination = %5.3f%n",
state.getDate(),
pos.getZ() > 0 ? "Northern" : "Southern",
FastMath.toDegrees(state.getOrbit().getI()));
});
// run simulation
propagator.propagate(initialOrbit.getDate().shiftedBy(5 * initialOrbit.getKeplerianPeriod()));
System.exit(0);
} catch (OrekitException e) {
System.err.println(e.getLocalizedMessage());
System.exit(1);
}
}
}
<!--- Copyright 2002-2020 CS GROUP
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
-->
# Maneuvers
The next tutorials detail some elementary usages of the maneuvers.
Both simple impulsive maneuvers and more complex continuous thrust
maneuvers are presented.
## Impulsive maneuvers
Impulsive maneuvers are very simple discrete changes to the velocity
of a spacecraft. They are mainly used in two cases:
- for station-keeping, as they remain realistic models given the small
size of the required maneuvers
- for initialization of optimization or search algorithm that will
internally use more realistic models for large maneuvers
This tutorial shows how to implement a series of maneuvers to change
progressively the inclination of an orbit.
Let's set up an initial state as:
final Frame eme2000 = FramesFactory.getEME2000();
final Orbit initialOrbit =
new KeplerianOrbit(8000000.0, 0.01,
FastMath.toRadians(50.0), // ← this is initial inclination
FastMath.toRadians(140.0),
FastMath.toRadians(12.0),
FastMath.toRadians(-60.0), PositionAngle.MEAN,
eme2000,
new AbsoluteDate(new DateComponents(2008, 6, 23),
new TimeComponents(14, 0, 0),
TimeScalesFactory.getUTC()),
Constants.EIGEN5C_EARTH_MU);
The maneuver will be defined in spacecraft frame. We need to ensure the Z axis is
aligned with orbital momentum, so we select an attitude aligned with LVLH
Local Orbital frame
final AttitudeProvider attitudeProvider = new LofOffset(eme2000, LOFType.LVLH);
We want to perform a series of 3 inclination reduction maneuvers. As they modify
only inclination, they must occur at node, but not all nodes are suitable, we want
ascending nodes, with a ΔV along -Z. The maneuvers are triggered when `Action.STOP`
events occur (and are filtered out)
final NodeDetector ascendingNodeStopper =
new NodeDetector(FramesFactory.getEME2000()).
withMaxCheck(300.0).
withThreshold(1.0e-6).
withHandler(new StopOnIncreasing<>());
We allow only maneuvers on the first 3 orbits
final AbsoluteDate lastAllowedDate =
initialOrbit.getDate().shiftedBy(3 * initialOrbit.getKeplerianPeriod());
final EnablingPredicate<EventDetector> predicate =
(state, detector, g) -> state.getDate().isBefore(lastAllowedDate);
final EventDetector trigger =
new EventEnablingPredicateFilter<>(ascendingNodeStopper, predicate);
Create the maneuver, using ascending node detector as a trigger
final ImpulseManeuver<EventDetector> maneuver =
new ImpulseManeuver<>(trigger,
new Vector3D(0.0, 0.0, -122.25), // ← 122.25 m/s along -Z
350.0);
Wrap-up everything in a propagator. Note that ImpulseManeuver is a event detector,
not a force model! This allows it to be used for all propagators, including
analytical ones like the Keplerian propagator used here
final KeplerianPropagator propagator = new KeplerianPropagator(initialOrbit, attitudeProvider);
propagator.addEventDetector(maneuver);
Progress monitoring
propagator.setMasterMode(900.0, (state, isLast) -> {
final Vector3D pos = state.getPVCoordinates(eme2000).getPosition();
System.out.format(Locale.US, "%s %s hemisphere inclination = %5.3f%n",
state.getDate(),
pos.getZ() > 0 ? "Northern" : "Southern",
FastMath.toDegrees(state.getOrbit().getI()));
});
Run simulation
propagator.propagate(initialOrbit.getDate().shiftedBy(5 * initialOrbit.getKeplerianPeriod()));
The printed result is shown below. We see that inclination remains constant as
we cross descending nodes (i.e. switch from Northern to Southern hemisphere),
and changes as we cross the first three ascending nodes
2008-06-23T14:00:00.000 Northern hemisphere inclination = 50.000
2008-06-23T14:15:00.000 Northern hemisphere inclination = 50.000
2008-06-23T14:30:00.000 Northern hemisphere inclination = 50.000
2008-06-23T14:45:00.000 Southern hemisphere inclination = 50.000
2008-06-23T15:00:00.000 Southern hemisphere inclination = 50.000
2008-06-23T15:15:00.000 Southern hemisphere inclination = 50.000
2008-06-23T15:30:00.000 Southern hemisphere inclination = 50.000
2008-06-23T15:45:00.000 Northern hemisphere inclination = 49.000
2008-06-23T16:00:00.000 Northern hemisphere inclination = 49.000
2008-06-23T16:15:00.000 Northern hemisphere inclination = 49.000
2008-06-23T16:30:00.000 Northern hemisphere inclination = 49.000
2008-06-23T16:45:00.000 Southern hemisphere inclination = 49.000
2008-06-23T17:00:00.000 Southern hemisphere inclination = 49.000
2008-06-23T17:15:00.000 Southern hemisphere inclination = 49.000
2008-06-23T17:30:00.000 Southern hemisphere inclination = 49.000
2008-06-23T17:45:00.000 Northern hemisphere inclination = 48.001
2008-06-23T18:00:00.000 Northern hemisphere inclination = 48.001
2008-06-23T18:15:00.000 Northern hemisphere inclination = 48.001
2008-06-23T18:30:00.000 Northern hemisphere inclination = 48.001
2008-06-23T18:45:00.000 Southern hemisphere inclination = 48.001
2008-06-23T19:00:00.000 Southern hemisphere inclination = 48.001
2008-06-23T19:15:00.000 Southern hemisphere inclination = 48.001
2008-06-23T19:30:00.000 Southern hemisphere inclination = 48.001
2008-06-23T19:45:00.000 Northern hemisphere inclination = 47.001
2008-06-23T20:00:00.000 Northern hemisphere inclination = 47.001
2008-06-23T20:15:00.000 Northern hemisphere inclination = 47.001
2008-06-23T20:30:00.000 Southern hemisphere inclination = 47.001
2008-06-23T20:45:00.000 Southern hemisphere inclination = 47.001
2008-06-23T21:00:00.000 Southern hemisphere inclination = 47.001
2008-06-23T21:15:00.000 Southern hemisphere inclination = 47.001
2008-06-23T21:30:00.000 Northern hemisphere inclination = 47.001
2008-06-23T21:45:00.000 Northern hemisphere inclination = 47.001
2008-06-23T22:00:00.000 Northern hemisphere inclination = 47.001
2008-06-23T22:15:00.000 Northern hemisphere inclination = 47.001
2008-06-23T22:30:00.000 Southern hemisphere inclination = 47.001
2008-06-23T22:45:00.000 Southern hemisphere inclination = 47.001
2008-06-23T23:00:00.000 Southern hemisphere inclination = 47.001
2008-06-23T23:15:00.000 Southern hemisphere inclination = 47.001
2008-06-23T23:30:00.000 Northern hemisphere inclination = 47.001
2008-06-23T23:45:00.000 Northern hemisphere inclination = 47.001
The complete code for this example can be found in the source tree of the tutorials,
in file `src/main/java/org/orekit/tutorials/maneuvers/ImpulseAtNode.java`.
## Continuous maneuvers
Continuous maneuvers are realistic models that take into account
maneuver duration, attitude change during maneuver and mass depletion.
They can only be used with integration-based propagators.
This tutorial shows how to implement an apogee maneuver, using either
the attitude set up at propagator level itself or overriding it
for only the maneuver acceleration direction computation. We use
only date-based triggers and constant thrust propulsion system, but
it is possible to use different ones. As an example, we could
replace the `BasicConstantThrustPropulsionModel` with `ScaledConstantThrustPropulsionModel`
and to take into account some calibration factors (or estimate these
factors if instead of using this model in a simulation we use it in
an orbit determination and configure these scaling factors as estimated).
We could also replace the date-based triggers by event-based
triggers, which can model multi-burn maneuvers.
Let's set up an initial state with a GTO orbit and a 2500kg spacecraft:
final Frame eme2000 = FramesFactory.getEME2000();
final AbsoluteDate date = new AbsoluteDate(new DateComponents(2004, 01, 01),
new TimeComponents(23, 30, 00.000),
TimeScalesFactory.getUTC());
final Orbit orbit =
new KeplerianOrbit(24396159, 0.72831215, FastMath.toRadians(7),
FastMath.toRadians(180), FastMath.toRadians(261),
FastMath.toRadians(0), PositionAngle.TRUE,
eme2000, date,
Constants.EIGEN5C_EARTH_MU);
final SpacecraftState initialState = new SpacecraftState(orbit, 2500.0);
Prepare propagator, using an adaptive stepsize integrator. The propagator
will use an attitude mode aligned with VNC, i.e. its X axis is always
along orbital velocity
final OrbitType orbitType = OrbitType.EQUINOCTIAL;
final double[][] tol = NumericalPropagator.tolerances(1.0, orbit, orbitType);
final AdaptiveStepsizeIntegrator integrator =
new DormandPrince853Integrator(0.001, 1000, tol[0], tol[1]);
integrator.setInitialStepSize(60);
final NumericalPropagator propagator = new NumericalPropagator(integrator);
propagator.setInitialState(initialState);
propagator.setAttitudeProvider(new LofOffset(eme2000, LOFType.VNC));
At first, we want to compute the maneuver as an inertial one, so we cannot
rely on the attitude mode configured above, we need an attitude overriding
law with the X axis pointing towards a specific direction
final Vector3D direction = new Vector3D(FastMath.toRadians(-7.4978),
FastMath.toRadians(351));
final AttitudeProvider attitudeOverride =
new InertialProvider(new Rotation(direction, Vector3D.PLUS_I),
eme2000);
Maneuver will start at a known date and stop after a known duration
final AbsoluteDate firingDate = new AbsoluteDate(new DateComponents(2004, 1, 2),
new TimeComponents(4, 15, 34.080),
TimeScalesFactory.getUTC());
final double duration = 3653.99;
final ManeuverTriggers triggers = new DateBasedManeuverTriggers(firingDate, duration);
Maneuver has constant thrust
final double thrust = 420;
final double isp = 318;
final PropulsionModel propulsionModel =
new BasicConstantThrustPropulsionModel(thrust, isp,
Vector3D.PLUS_I,
"apogee-engine");
Build maneuver and add it to the propagator as a new force model
propagator.addForceModel(new Maneuver(attitudeOverride, triggers, propulsionModel));
Progress monitoring
propagator.setMasterMode(120.0, (state, isLast) ->
System.out.format(Locale.US, "%s a = %12.3f m, e = %11.9f, m = %8.3f kg%n",
state.getDate(), state.getA(), state.getE(), state.getMass())
);
Propagate orbit, including maneuver
propagator.propagate(fireDate.shiftedBy(-900), fireDate.shiftedBy(duration + 900));
The printed result is shown below. We see that semi-major axis, eccentricity
and inclination are constant before the maneuver, they change continuously
during the maneuver, and become constant again after maneuver
2004-01-02T04:00:34.080 a = 24396159.000 m, e = 0.728312150, m = 2500.000 kg
2004-01-02T04:02:34.080 a = 24396159.000 m, e = 0.728312150, m = 2500.000 kg
2004-01-02T04:04:34.080 a = 24396159.000 m, e = 0.728312150, m = 2500.000 kg
2004-01-02T04:06:34.080 a = 24396159.000 m, e = 0.728312150, m = 2500.000 kg
2004-01-02T04:08:34.080 a = 24396159.000 m, e = 0.728312150, m = 2500.000 kg
2004-01-02T04:10:34.080 a = 24396159.000 m, e = 0.728312150, m = 2500.000 kg
2004-01-02T04:12:34.080 a = 24396159.000 m, e = 0.728312150, m = 2500.000 kg
2004-01-02T04:14:34.080 a = 24396159.000 m, e = 0.728312150, m = 2500.000 kg
2004-01-02T04:16:34.080 a = 24442112.400 m, e = 0.725043403, m = 2491.919 kg
2004-01-02T04:18:34.080 a = 24536037.252 m, e = 0.718404119, m = 2475.758 kg
2004-01-02T04:20:34.080 a = 24632720.409 m, e = 0.711627339, m = 2459.596 kg
2004-01-02T04:22:34.080 a = 24732246.157 m, e = 0.704710905, m = 2443.435 kg
2004-01-02T04:24:34.080 a = 24834702.625 m, e = 0.697652633, m = 2427.273 kg
2004-01-02T04:26:34.080 a = 24940182.000 m, e = 0.690450311, m = 2411.112 kg
2004-01-02T04:28:34.080 a = 25048780.751 m, e = 0.683101699, m = 2394.950 kg
2004-01-02T04:30:34.080 a = 25160599.875 m, e = 0.675604529, m = 2378.788 kg
2004-01-02T04:32:34.080 a = 25275745.160 m, e = 0.667956507, m = 2362.627 kg