Commit e1017f3f authored by Luc Maisonobe's avatar Luc Maisonobe
Browse files

Moved tutorials to a separate sister project.

parent 18511b08
......@@ -33,7 +33,7 @@ __Note:__ Our official repository is
## Documentation
Project overview, architecture and development, detailed features list,
tutorials, Javadoc and a lot of other information is available on the
Javadoc and a lot of other information is available on the
[Maven site](https://www.orekit.org/site-orekit-development/).
## Getting help
......
......@@ -21,6 +21,9 @@
</properties>
<body>
<release version="10.1" date="TBD" description="TBD">
<action dev="luc" type="update">
Moved tutorials to a separate sister project.
</action>
<action dev="bryan" type="fix" issue="612">
Fixed DSST orbit determination tutorial.
</action>
......
......@@ -110,22 +110,12 @@ The simplest way to use Orekit with Eclipse is to follow these steps:
automatically selected. Click finish
The Orekit library should be configured automatically, including the dependency
to the underlying mathematical library. Note however that the tutorials
that are present in the source distribution are not automatically added by
this process (because the tutorials correspond to extra code and as such they
are not referenced in the pom.xml file).
to the underlying mathematical library.
Now you have an orekit-x.y project in you workspace, and you can create your
own application projects that will depend on the Orekit project.
You can also check everything works correctly by running the junit tests.
If you want to go further and run the tutorials, you should update the
project configuration to add them. In the Eclipse Package Explorer tab,
right-click on the orekit-x.y project and select from the conext menu
the entry "Build Path -> Configure Build Path...". Then in the wizard that
should appear, select the "Source" tab in the right pane, click the button
"Add Folder...", open the "tutorials" folder, select the two sub-folders
"java" and "resource" and click "OK". Now the projects should display the
tutorials. Note that since 9.0, you need to have an "orekit-data" folder
in your home directory in order to run the tutorials.
If you want to go further and run the tutorials, you need to check the
sister project [Orekit tutorials](https://gitlab.orekit.org/orekit/orekit-tutorials).
<!--- Copyright 2002-2019 CS Systèmes d'Information
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.
-->
# Attitude
This tutorial emphasizes a specific usage of the attitude package
described in the [attitudes section](../architecture/attitudes.html) of
the library architecture documentation.
## Attitudes Sequence
`AttitudesSequence` enables easy switching between attitude laws on
event occurrences when propagating some `SpacecraftState`.
Let's set up an initial state as:
* a date in UTC time scale
* an orbit defined by the position and the velocity of the spacecraft in
the EME2000 inertial frame and an associated central attraction coefficient
chosen among many physical constants available in Orekit.
The initial orbit is here defined as a `KeplerianOrbit`.
AbsoluteDate initialDate = new AbsoluteDate(2004, 01, 01, 23, 30, 00.000, TimeScalesFactory.getUTC());
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);
More details on the orbit representation can be found
in the [orbits section](../architecture/orbits.html)
of the library architecture documentation.
We will put all switching events in a set.
final SortedSet<String> output = new TreeSet<String>();
Let's define a couple of `AttitudeProvider`, built upon `LofOffset` laws for instance.
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);
Let's also define some `EventDetector`. For this tutorial's requirements,
two `EclipseDetector`, each one using a customized implementation of `EventHandler`
with a dedicated `eventOccurred` method: `dayNightEvent`, to detect the day to night
transition, `nightDayEvent`, to detect the night to day transition:
PVCoordinatesProvider sun = CelestialBodyFactory.getSun();
PVCoordinatesProvider earth = CelestialBodyFactory.getEarth();
EventDetector dayNightEvent = new EclipseDetector(sun, 696000000., earth, Constants.WGS84_EARTH_EQUATORIAL_RADIUS).
withHandler(new ContinueOnEvent<EclipseDetector>());
EventDetector nightDayEvent = new EclipseDetector(sun, 696000000., earth, Constants.WGS84_EARTH_EQUATORIAL_RADIUS).
withHandler(new ContinueOnEvent<EclipseDetector>());
More details on event detectors and event handlers can be found in the
[propagation section](../architecture/propagation.html)
of the library architecture documentation.
An `AttitudesSequence` is then defined, for the sake of this tutorial,
by adding two switching conditions acting as a simple loop:
* the first one enables the transition from `dayObservationLaw` to `nightRestingLaw`
when a decreasing `dayNightEvent` occurs,
* the second one enables the transition from `nightRestingLaw` to `dayObservationLaw`
when an increasing `nightDayEvent` occurs.
As the two conditions reverse each other effect, the combined `AttitudesSequence`
acts as a loop. We also define a handler to monitor attitude switches:
AttitudesSequence attitudesSequence = new AttitudesSequence();
AttitudesSequence.SwitchHandler switchHandler =
new AttitudesSequence.SwitchHandler() {
public void switchOccurred(AttitudeProvider preceding, AttitudeProvider following,
SpacecraftState s) {
if (preceding == dayObservationLaw) {
output.add(s.getDate() + ": switching to night law");
} else {
output.add(s.getDate() + ": switching to day law");
}
}
};
attitudesSequence.addSwitchingCondition(dayObservationLaw, dayNightEvent,
false, true, 10.0,
AngularDerivativesFilter.USE_R, nightRestingLaw, switchHandler);
attitudesSequence.addSwitchingCondition(nightRestingLaw, nightDayEvent,
true, false, 10.0,
AngularDerivativesFilter.USE_R, dayObservationLaw, switchHandler);
An `AttitudesSequence` needs at least one switching condition to be meaningful,
but there is no upper limit.
An active `AttitudeProvider` may have several switch events and next law settings,
leading to different activation patterns depending on which event is triggered first.
Don't forget to set the current active law according to the current state:
if (dayNightEvent.g(new SpacecraftState(initialOrbit)) >= 0) {
// initial position is in daytime
attitudesSequence.resetActiveProvider(dayObservationLaw);
} else {
// initial position is in nighttime
attitudesSequence.resetActiveProvider(nightRestingLaw);
}
Now, let's choose some propagator to compute the spacecraft motion. We will use
an `EcksteinHechlerPropagator` based on the analytical Eckstein-Hechler model.
The propagator is built upon the initialOrbit, the attitudeSequence and
physical constants for the potential.
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);
The `attitudeSequence` must register all the switching events before propagation.
attitudesSequence.registerSwitchEvents(propagator);
The propagator operating mode is set to master mode with fixed step.
The implementation of the interface `OrekitFixedStepHandler` aims to define
the `handleStep` method called within the loop. For the purpose of this
tutorial, the `handleStep` method will print at the current date two angles,
the first one indicates if the spacecraft is eclipsed while the second informs
about the current attitude law.
propagator.setMasterMode(180., new OrekitFixedStepHandler() {
public void handleStep(SpacecraftState currentState, boolean isLast) {
DecimalFormatSymbols angleDegree = new DecimalFormatSymbols(Locale.US);
angleDegree.setDecimalSeparator('\u00b0');
DecimalFormat ad = new DecimalFormat(" 00.000;-00.000", angleDegree);
// the g function is the eclipse indicator, its an angle between Sun and Earth limb,
// positive when Sun is outside of Earth limb, negative when Sun is hidden by Earth limb
final double eclipseAngle = dayNightEvent.g(currentState);
// the Earth position in spacecraft frame should be along spacecraft Z axis
// during nigthtime and away from it during daytime due to roll and pitch offsets
final Vector3D earth = currentState.toTransform().transformPosition(Vector3D.ZERO);
final double pointingOffset = Vector3D.angle(earth, Vector3D.PLUS_K);
output.add(currentState.getDate() +
" " + ad.format(FastMath.toDegrees(eclipseAngle) +
" " + ad.format(FastMath.toDegrees(pointingOffset)));
}
});
More details on propagation modes can be found in the
[propagation section](../architecture/propagation.html)
of the library architecture documentation.
Finally, the propagator is just asked to propagate for a given duration, and we print
the results:
SpacecraftState finalState = propagator.propagate(initialDate.shiftedBy(12600.));
for (final String line : output) {
System.out.println(line);
}
Note that we use an intermediate `SortedSet` to first gather both the switching events
and the step outputs instead of just letting the event handler and step handler directly
print their results. The rationale is that as events handlers could truncate a step (if
their `eventOccurred` method returned `Action.STOP`), the library design is to always
call `eventOccurred` on the event handler first, and then to call `handleStep` on the
step handler afterwards, with the `isLast` boolean set up correctly if the event handler
decided to stop propagation. A side effect is that if both methods print something, then
the switch from the end of the step would be printed first and the step itself printed
afterwards, which would lead to out of order output. The `SortedSet` ensures the various
lines will be sorted in lexicographic order, which is chronological order here, despite
they will be generated slightly out of order near events occurrences.
As the propagation goes along, events occur switching from one attitude law to another.
The printed results are shown below:
2004-01-01T23:30:00.000 -11°649 00°000
2004-01-01T23:33:00.000 -17°804 00°000
2004-01-01T23:36:00.000 -22°458 00°000
2004-01-01T23:39:00.000 -25°045 00°000
2004-01-01T23:42:00.000 -25°140 00°000
2004-01-01T23:45:00.000 -22°726 00°000
2004-01-01T23:48:00.000 -18°207 00°000
2004-01-01T23:51:00.000 -12°146 00°000
2004-01-01T23:54:00.000 -05°042 00°000
2004-01-01T23:55:57.968: switching to day law
2004-01-01T23:57:00.000 02°741 43°958
2004-01-02T00:00:00.000 10°946 43°958
2004-01-02T00:03:00.000 19°390 43°958
2004-01-02T00:06:00.000 27°931 43°958
2004-01-02T00:09:00.000 36°441 43°958
2004-01-02T00:12:00.000 44°787 43°958
2004-01-02T00:15:00.000 52°808 43°958
2004-01-02T00:18:00.000 60°286 43°958
2004-01-02T00:21:00.000 66°913 43°958
2004-01-02T00:24:00.000 72°251 43°958
2004-01-02T00:27:00.000 75°751 43°958
2004-01-02T00:30:00.000 76°896 43°958
2004-01-02T00:33:00.000 75°480 43°958
2004-01-02T00:36:00.000 71°756 43°958
2004-01-02T00:39:00.000 66°259 43°958
2004-01-02T00:42:00.000 59°533 43°958
2004-01-02T00:45:00.000 51°999 43°958
2004-01-02T00:48:00.000 43°955 43°958
2004-01-02T00:51:00.000 35°608 43°958
2004-01-02T00:54:00.000 27°112 43°958
2004-01-02T00:57:00.000 18°596 43°958
2004-01-02T01:00:00.000 10°184 43°958
2004-01-02T01:03:00.000 02°022 43°958
2004-01-02T01:03:45.919: switching to night law
2004-01-02T01:06:00.000 -05°706 00°000
2004-01-02T01:09:00.000 -12°733 00°000
2004-01-02T01:12:00.000 -18°680 00°000
2004-01-02T01:15:00.000 -23°037 00°000
2004-01-02T01:18:00.000 -25°240 00°000
2004-01-02T01:21:00.000 -24°914 00°000
2004-01-02T01:24:00.000 -22°122 00°000
2004-01-02T01:27:00.000 -17°313 00°000
2004-01-02T01:30:00.000 -11°051 00°000
2004-01-02T01:33:00.000 -03°814 00°000
2004-01-02T01:34:28.690: switching to day law
2004-01-02T01:36:00.000 04°052 43°958
2004-01-02T01:39:00.000 12°308 43°958
2004-01-02T01:42:00.000 20°777 43°958
2004-01-02T01:45:00.000 29°322 43°958
2004-01-02T01:48:00.000 37°815 43°958
2004-01-02T01:51:00.000 46°121 43°958
2004-01-02T01:54:00.000 54°070 43°958
2004-01-02T01:57:00.000 61°434 43°958
2004-01-02T02:00:00.000 67°885 43°958
2004-01-02T02:03:00.000 72°963 43°958
2004-01-02T02:06:00.000 76°111 43°958
2004-01-02T02:09:00.000 76°841 43°958
2004-01-02T02:12:00.000 75°020 43°958
2004-01-02T02:15:00.000 70°968 43°958
2004-01-02T02:18:00.000 65°236 43°958
2004-01-02T02:21:00.000 58°353 43°958
2004-01-02T02:24:00.000 50°719 43°958
2004-01-02T02:27:00.000 42°613 43°958
2004-01-02T02:30:00.000 34°231 43°958
2004-01-02T02:33:00.000 25°723 43°958
2004-01-02T02:36:00.000 17°215 43°958
2004-01-02T02:39:00.000 08°834 43°958
2004-01-02T02:42:00.000 00°727 43°958
2004-01-02T02:42:16.591: switching to night law
2004-01-02T02:45:00.000 -06°907 00°000
2004-01-02T02:48:00.000 -13°788 00°000
2004-01-02T02:51:00.000 -19°515 00°000
2004-01-02T02:54:00.000 -23°558 00°000
2004-01-02T02:57:00.000 -25°366 00°000
2004-01-02T03:00:00.000 -24°622 00°000
Propagation ended at 2004-01-02T03:00:00.000
The complete code for this example can be found in the source tree of the library,
in file `src/tutorials/fr/cs/examples/attitude/EarthObservation.java`.
<!--- Copyright 2002-2019 CS Systèmes d'Information
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.
-->
# Frames
## Basic use
### The problem to be solved
We want to compute the Doppler effect of a satellite with respect to
a ground station.
### A simple solution
On the one hand, we define the Local Orbital Frame (LOF) related to the satellite.
Let's first define some initial state for the satellite with:
* an inertial frame
* a date in some time scale
* a central attraction coefficient
* an orbit defined by the position and the velocity of the satellite in the inertial frame at the date.
The initial orbit is just set as a `CartesianOrbit`.
More details on the orbit representation can be found
in the [orbits section](../architecture/orbits.html)
of the library architecture documentation.
Frame inertialFrame = FramesFactory.getEME2000();
TimeScale utc = TimeScalesFactory.getUTC();
AbsoluteDate initialDate =
new AbsoluteDate(2008, 10, 01, 0, 0, 00.000, utc);
double mu = 3.986004415e+14;
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);
Orbit initialOrbit =
new CartesianOrbit(pvCoordinates, inertialFrame, initialDate, mu);
As a propagator, we consider a simple `KeplerianPropagator` that will propagate orbit in the inertial
frame in which the initial orbit was defined (here EME2000).
Propagator kepler = new KeplerianPropagator(initialOrbit);
On the other hand, let's define the ground station by its coordinates as a `GeodeticPoint`
in its own `TopocentricFrame` related to a `BodyShape` in some terrestrial frame.
double longitude = FastMath.toRadians(45.);
double latitude = FastMath.toRadians(25.);
double altitude = 0.;
GeodeticPoint station = new GeodeticPoint(latitude, longitude, altitude);
Frame earthFrame = FramesFactory.getITRF(IERSConventions.IERS_2010, true);
BodyShape earth = new OneAxisEllipsoid(Constants.WGS84_EARTH_EQUATORIAL_RADIUS,
Constants.WGS84_EARTH_FLATTENING,
earthFrame);
TopocentricFrame staF = new TopocentricFrame(earth, station, "station");
More details on `BodyShape` and `GeodeticPoint` can be found
in the [bodies section](../architecture/bodies.html)
of the library architecture documentation.
More details on `TopocentricFrame` can be found
in the [frames section](../architecture/frames.html)
of the library architecture documentation.
Finally, we can get the Doppler measurement in a simple propagation loop
AbsoluteDate extrapDate = initialDate;
AbsoluteDate finalDate = new AbsoluteDate(initialDate, 6000, utc);
while (extrapDate.compareTo(finalDate) <= 0) {
// We can simply get the position and velocity of spacecraft in station frame at any time
PVCoordinates pvInert = kepler.propagate(extrapDate).getPVCoordinates();
PVCoordinates pvStation = inertialFrame.getTransformTo(staF, extrapDate).transformPVCoordinates(pvInert);
// And then calculate the doppler signal
double doppler = Vector3D.dotProduct(pvStation.getPosition(), pvStation.getVelocity()) / pvStation.getPosition().getNorm();
System.out.format(Locale.US, "%s %9.3f%n", extrapDate, doppler);
extrapDate = extrapDate.shiftedBy(600);
}
Here are the results displayed by this program:
time doppler (m/s)
2008-10-01T00:00:00.000 -2925.114
2008-10-01T00:10:00.000 -3069.084
2008-10-01T00:20:00.000 -1331.910
2008-10-01T00:30:00.000 1664.611
2008-10-01T00:40:00.000 3143.549
2008-10-01T00:50:00.000 2832.906
2008-10-01T01:00:00.000 1556.662
2008-10-01T01:10:00.000 -140.889
2008-10-01T01:20:00.000 -1860.637
2008-10-01T01:30:00.000 -3195.728
2008-10-01T01:40:00.000 -3538.053
### Source code
The complete code for this example can be found in the source tree of the library,
in file `src/tutorials/fr/cs/examples/frames/Frames1.java`.
## Advanced use
### The problem to be solved
The problem is related to the one exposed in the _User defined frames_ subsection of the
[frames section](../architecture/frames.html) of the library architecture documentation.
It can be summarized by the following schema.
![frames 2 tutorial](../images/frames2-tutorial.png)
For a given satellite, GPS measurements for position and velocity,
expressed in the ITRF frame, are available at any moment.
The GPS antenna is fixed with some offset with respect to the satellite reference frame.
The attitude of the satellite reference frame with respect to some moving frame related
to the satellite center of gravity (CoG) is known at any moment.
We want to compute for some instant the position and velocity of the CoG
in the EME2000 inertial frame.
### A smart solution
A possible solution provided by OREKIT is detailed above.
The CoG frame has its origin at the satellite center of gravity and is aligned with EME2000.
It is linked to its parent EME2000 frame by an a priori unknown transform which depends
on the current position and velocity. This transform is what we want to compute.
We first build the frame. We use the identity transform as a simple dummy value, the
real value which is time-dependent will be recomputed when time is reset:
Frame cogFrame = new UpdatableFrame(FramesFactory.getEME2000(), Transform.IDENTITY, "LOF", false);
The satellite frame, with origin also at the CoG, depends on attitude. For the sake of this
tutorial, we consider a simple inertial attitude here:
Transform cogToSat = new Transform(new Rotation(0.6, 0.48, 0, 0.64, false));
Frame satFrame = new Frame(cogFrame, cogToSat, "sat", false);
Finally, the GPS antenna frame is always defined from the satellite
frame by 2 transforms: a translation and a rotation. Let's set some values:
Transform translateGPS = new Transform(new Vector3D(0, 0, 1));
Transform rotateGPS = new Transform(date,
new Rotation(new Vector3D(0, 1, 3),
FastMath.toRadians(10),
RotationConvention.VECTOR_OPERATOR));
Frame gpsFrame = new Frame(satFrame,
new Transform(date, translateGPS, rotateGPS),
"GPS", false);
Let's consider some measurement date in UTC time scale:
TimeScale utc = TimeScalesFactory.getUTC();
AbsoluteDate date = new AbsoluteDate(2008, 10, 01, 12, 00, 00.000, utc);
Then let's get some satellite position and velocity in ITRF
as measured by GPS antenna at this moment:
Vector3D position = new Vector3D(-6142438.668, 3492467.560, -25767.25680);
Vector3D velocity = new Vector3D(505.8479685, 942.7809215, 7435.922231);
The transform from GPS frame to ITRF frame at this moment is defined by
a translation and a rotation. The translation is directly provided by the
GPS measurement above. The rotation is extracted from the existing tree, where
we know all rotations are already up to date, even if one translation is still
unknown. We combine the extracted rotation and the measured translation by
applying the rotation first because the position/velocity vector are given in
ITRF frame not in GPS antenna frame:
Transform measuredTranslation = new Transform(date, position, velocity);
Transform formerTransform =
gpsFrame.getTransformTo(FramesFactory.getITRF(IERSConventions.IERS_2010, true), date);
Transform preservedRotation =
new Transform(date,
formerTransform.getRotation(),
formerTransform.getRotationRate());
Transform gpsToItrf =
new Transform(date, preservedRotation, measuredTranslation);
So we can now update the transform from EME2000 to CoG frame.
The `updateTransform` method automatically locates the frames
in the global tree, combines all transforms and updates the single
transform between CoG itself and its parent EME2000 frame.
cogFrame.updateTransform(gpsFrame, FramesFactory.getITRF(IERSConventions.IERS_2010, true), gpsToItrf, date);
The frame tree is now in sync. We can compute all position and velocity
pairs we want:
PVCoordinates origin = PVCoordinates.ZERO;
Transform cogToItrf = cogFrame.getTransformTo(FramesFactory.getITRF(IERSConventions.IERS_2010, true), date);
PVCoordinates satItrf = cogToItrf.transformPVCoordinates(origin);
Transform cogToEme2000 = cogFrame.getTransformTo(FramesFactory.getEME2000(), date);
PVCoordinates satEME2000 = cogToEme2000.transformPVCoordinates(origin);
As a result, we can compare the GPS measurements to the computed values:
GPS antenna position in ITRF: -6142438.668 3492467.560 -25767.257
GPS antenna velocity in ITRF: 505.8479685 942.7809215 7435.9222310
Satellite position in ITRF: -6142439.167 3492468.238 -25766.717
Satellite velocity in ITRF: 505.8480179 942.7809579 7435.9222310
Satellite position in EME2000: 6675017.356 -2317478.625 -31517.554
Satellite velocity in EME2000: -150.5212983 -532.0401635 7436.0739037
### Source code
The complete code for this example can be found in the source tree of the library,
in file `src/tutorials/fr/cs/examples/frames/Frames2.java`.
## Direct use of transforms : coordinates with respect to spacecraft frame
### The problem to be solved
Let's consider a spacecraft which attitude is guided by a yaw steering law,
we want to plot some of the effects of such a law on the spacecraft motion.
### An immediate solution
There was once a `SpacecraftFrame` in Orekit, but it could not be used in
master propagation mode and has been deprecated as of 6.0, so we won't use it.
First, an initial orbit for the spacecraft is defined as follows:
Frame eme2000 = FramesFactory.getEME2000();
AbsoluteDate initialDate = new AbsoluteDate(2003, 4, 7, 10, 55, 21.575,
TimeScalesFactory.getUTC());
double mu = 3.986004415e+14;
Orbit orbit = new CircularOrbit(7178000.0, 0.5e-4, -0.5e-4,
FastMath.toRadians(50.),
FastMath.toRadians(220.),
FastMath.toRadians(5.300),
PositionAngle.MEAN,
eme2000, initialDate, mu);
More details on the orbit representation can be found in the
[orbits section](../architecture/orbits.html) of the library architecture
documentation.
Then the attitude law for the spacecraft is constructed:
* we first define a nadir pointing law towards the Earth under the spacecraft,
* then a yaw steering law is added
The yaw steering law wraps the nadir point law in order to give maximal lighting
to the solar arrays, which rotation axis is Y in spacecraft frame:
Frame earthFrame = FramesFactory.getITRF(IERSConventions.IERS_2010, true);
BodyShape earth = new OneAxisEllipsoid(Constants.WGS84_EARTH_EQUATORIAL_RADIUS,
Constants.WGS84_EARTH_FLATTENING,
earthFrame);
NadirPointing nadirLaw = new NadirPointing(eme2000, earth);
final PVCoordinatesProvider sun = CelestialBodyFactory.getSun();
YawSteering yawSteeringLaw = new YawSteering(eme2000, nadirLaw, sun, Vector3D.MINUS_I);
More details on the attitude representation can be found in the
[attitudes section](../architecture/attitudes.html) of the library architecture
documentation.
As a propagator, we consider an analytic `EcksteinHechlerPropagator`.
Propagator propagator =
new EcksteinHechlerPropagator(orbit, yawSteeringLaw,
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);
More details on `Propagator` can be found in the
[propagation section](../architecture/propagation.html) of the library
architecture documentation.
Then, we associate a step handler with the propagator which directly computes
the desired data in spacecraft frame using the current spacecraft state
propagator.setMasterMode(10, new OrekitFixedStepHandler() {
public void init(SpacecraftState s0, AbsoluteDate t)
// write file header
}
public void handleStep(SpacecraftState currentState, boolean isLast) {
Transform inertToSpacecraft = currentState.toTransform();
Vector3D sunInert = sun.getPVCoordinates(currentState.getDate(), currentState.getFrame()).getPosition();
Vector3D sunSat = inertToSpacecraft.transformPosition(sunInert);
Vector3D spin = inertToSpacecraft.getRotationRate();
// write data to file
}
}