/* Copyright 2002-2017 CS Systèmes d'Information
* Licensed to CS Systèmes d'Information (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.attitudes;
import org.hipparchus.geometry.euclidean.threed.Rotation;
import org.hipparchus.geometry.euclidean.threed.RotationConvention;
import org.hipparchus.geometry.euclidean.threed.RotationOrder;
import org.hipparchus.geometry.euclidean.threed.Vector3D;
import org.hipparchus.util.FastMath;
import org.junit.After;
import org.junit.Assert;
import org.junit.Before;
import org.junit.Test;
import org.orekit.Utils;
import org.orekit.bodies.GeodeticPoint;
import org.orekit.bodies.OneAxisEllipsoid;
import org.orekit.errors.OrekitException;
import org.orekit.frames.Frame;
import org.orekit.frames.FramesFactory;
import org.orekit.frames.LOFType;
import org.orekit.orbits.CircularOrbit;
import org.orekit.orbits.KeplerianOrbit;
import org.orekit.orbits.Orbit;
import org.orekit.orbits.PositionAngle;
import org.orekit.propagation.Propagator;
import org.orekit.propagation.SpacecraftState;
import org.orekit.propagation.analytical.KeplerianPropagator;
import org.orekit.time.AbsoluteDate;
import org.orekit.time.DateComponents;
import org.orekit.time.TimeComponents;
import org.orekit.time.TimeScalesFactory;
import org.orekit.utils.AngularCoordinates;
import org.orekit.utils.IERSConventions;
import org.orekit.utils.PVCoordinates;
public class LofOffsetTest {
// Computation date
private AbsoluteDate date;
// Body mu
private double mu;
// Reference frame = ITRF
private Frame itrf;
// Earth shape
OneAxisEllipsoid earthSpheric;
// Satellite position
CircularOrbit orbit;
PVCoordinates pvSatEME2000;
/** Test is the lof offset is the one expected
*/
@Test
public void testZero() throws OrekitException {
// Satellite position
// Lof aligned attitude provider
final LofOffset lofAlignedLaw = new LofOffset(orbit.getFrame(), LOFType.VVLH);
final Rotation lofOffsetRot = lofAlignedLaw.getAttitude(orbit, date, orbit.getFrame()).getRotation();
// Check that
final Vector3D momentumEME2000 = pvSatEME2000.getMomentum();
final Vector3D momentumLof = lofOffsetRot.applyTo(momentumEME2000);
final double cosinus = FastMath.cos(Vector3D.dotProduct(momentumLof, Vector3D.PLUS_K));
Assert.assertEquals(1., cosinus, Utils.epsilonAngle);
}
/** Test if the lof offset is the one expected
*/
@Test
public void testOffset() throws OrekitException {
// Satellite position
final CircularOrbit circ =
new CircularOrbit(7178000.0, 0.5e-4, -0.5e-4, FastMath.toRadians(0.), FastMath.toRadians(270.),
FastMath.toRadians(5.300), PositionAngle.MEAN,
FramesFactory.getEME2000(), date, mu);
// Create target pointing attitude provider
// ************************************
// Elliptic earth shape
final OneAxisEllipsoid earthShape = new OneAxisEllipsoid(6378136.460, 1 / 298.257222101, itrf);
final GeodeticPoint geoTargetITRF = new GeodeticPoint(FastMath.toRadians(43.36), FastMath.toRadians(1.26), 600.);
// Attitude law definition from geodetic point target
final TargetPointing targetLaw = new TargetPointing(circ.getFrame(), geoTargetITRF, earthShape);
final Rotation targetRot = targetLaw.getAttitude(circ, date, circ.getFrame()).getRotation();
// Create lof aligned attitude provider
// *******************************
final LofOffset lofAlignedLaw = new LofOffset(orbit.getFrame(), LOFType.VVLH);
final Rotation lofAlignedRot = lofAlignedLaw.getAttitude(circ, date, circ.getFrame()).getRotation();
// Get rotation from LOF to target pointing attitude
Rotation rollPitchYaw = targetRot.compose(lofAlignedRot.revert(), RotationConvention.VECTOR_OPERATOR).revert();
final double[] angles = rollPitchYaw.getAngles(RotationOrder.ZYX, RotationConvention.VECTOR_OPERATOR);
final double yaw = angles[0];
final double pitch = angles[1];
final double roll = angles[2];
// Create lof offset attitude provider with computed roll, pitch, yaw
// **************************************************************
final LofOffset lofOffsetLaw = new LofOffset(orbit.getFrame(), LOFType.VVLH, RotationOrder.ZYX, yaw, pitch, roll);
final Rotation lofOffsetRot = lofOffsetLaw.getAttitude(circ, date, circ.getFrame()).getRotation();
// Compose rotations : target pointing attitudes
final double angleCompo = targetRot.composeInverse(lofOffsetRot, RotationConvention.VECTOR_OPERATOR).getAngle();
Assert.assertEquals(0., angleCompo, Utils.epsilonAngle);
}
/** Test is the target pointed is the one expected
*/
@Test
public void testTarget()
throws OrekitException {
// Create target point and target pointing law towards that point
final GeodeticPoint targetDef = new GeodeticPoint(FastMath.toRadians(5.), FastMath.toRadians(-40.), 0.);
final TargetPointing targetLaw = new TargetPointing(orbit.getFrame(), targetDef, earthSpheric);
// Get roll, pitch, yaw angles corresponding to this pointing law
final LofOffset lofAlignedLaw = new LofOffset(orbit.getFrame(), LOFType.VVLH);
final Rotation lofAlignedRot = lofAlignedLaw.getAttitude(orbit, date, orbit.getFrame()).getRotation();
final Attitude targetAttitude = targetLaw.getAttitude(orbit, date, orbit.getFrame());
final Rotation rollPitchYaw = targetAttitude.getRotation().compose(lofAlignedRot.revert(), RotationConvention.VECTOR_OPERATOR).revert();
final double[] angles = rollPitchYaw.getAngles(RotationOrder.ZYX, RotationConvention.VECTOR_OPERATOR);
final double yaw = angles[0];
final double pitch = angles[1];
final double roll = angles[2];
// Create a lof offset law from those values
final LofOffset lofOffsetLaw = new LofOffset(orbit.getFrame(), LOFType.VVLH, RotationOrder.ZYX, yaw, pitch, roll);
final LofOffsetPointing lofOffsetPtLaw = new LofOffsetPointing(orbit.getFrame(), earthSpheric, lofOffsetLaw, Vector3D.PLUS_K);
// Check target pointed by this law : shall be the same as defined
final Vector3D pTargetRes =
lofOffsetPtLaw.getTargetPV(orbit, date, earthSpheric.getBodyFrame()).getPosition();
final GeodeticPoint targetRes = earthSpheric.transform(pTargetRes, earthSpheric.getBodyFrame(), date);
Assert.assertEquals(targetDef.getLongitude(), targetRes.getLongitude(), Utils.epsilonAngle);
Assert.assertEquals(targetDef.getLongitude(), targetRes.getLongitude(), Utils.epsilonAngle);
}
@Test
public void testSpin() throws OrekitException {
final AttitudeProvider law = new LofOffset(orbit.getFrame(), LOFType.VVLH, RotationOrder.XYX, 0.1, 0.2, 0.3);
AbsoluteDate date = new AbsoluteDate(new DateComponents(1970, 01, 01),
new TimeComponents(3, 25, 45.6789),
TimeScalesFactory.getUTC());
KeplerianOrbit orbit =
new KeplerianOrbit(7178000.0, 1.e-4, FastMath.toRadians(50.),
FastMath.toRadians(10.), FastMath.toRadians(20.),
FastMath.toRadians(30.), PositionAngle.MEAN,
FramesFactory.getEME2000(), date, 3.986004415e14);
Propagator propagator = new KeplerianPropagator(orbit, law);
double h = 0.01;
SpacecraftState sMinus = propagator.propagate(date.shiftedBy(-h));
SpacecraftState s0 = propagator.propagate(date);
SpacecraftState sPlus = propagator.propagate(date.shiftedBy(h));
// check spin is consistent with attitude evolution
double errorAngleMinus = Rotation.distance(sMinus.shiftedBy(h).getAttitude().getRotation(),
s0.getAttitude().getRotation());
double evolutionAngleMinus = Rotation.distance(sMinus.getAttitude().getRotation(),
s0.getAttitude().getRotation());
Assert.assertEquals(0.0, errorAngleMinus, 1.0e-6 * evolutionAngleMinus);
double errorAnglePlus = Rotation.distance(s0.getAttitude().getRotation(),
sPlus.shiftedBy(-h).getAttitude().getRotation());
double evolutionAnglePlus = Rotation.distance(s0.getAttitude().getRotation(),
sPlus.getAttitude().getRotation());
Assert.assertEquals(0.0, errorAnglePlus, 1.0e-6 * evolutionAnglePlus);
Vector3D spin0 = s0.getAttitude().getSpin();
Vector3D reference = AngularCoordinates.estimateRate(sMinus.getAttitude().getRotation(),
sPlus.getAttitude().getRotation(),
2 * h);
Assert.assertEquals(0.0, spin0.subtract(reference).getNorm(), 1.0e-10);
}
@Test
public void testAnglesSign() throws OrekitException {
AbsoluteDate date = new AbsoluteDate(new DateComponents(1970, 01, 01),
new TimeComponents(3, 25, 45.6789),
TimeScalesFactory.getUTC());
KeplerianOrbit orbit =
new KeplerianOrbit(7178000.0, 1.e-8, FastMath.toRadians(50.),
FastMath.toRadians(10.), FastMath.toRadians(20.),
FastMath.toRadians(0.), PositionAngle.MEAN,
FramesFactory.getEME2000(), date, 3.986004415e14);
double alpha = 0.1;
double cos = FastMath.cos(alpha);
double sin = FastMath.sin(alpha);
// Roll
Attitude attitude = new LofOffset(orbit.getFrame(), LOFType.VVLH, RotationOrder.XYZ, alpha, 0.0, 0.0).getAttitude(orbit, date, orbit.getFrame());
checkSatVector(orbit, attitude, Vector3D.PLUS_I, 1.0, 0.0, 0.0, 1.0e-8);
checkSatVector(orbit, attitude, Vector3D.PLUS_J, 0.0, cos, sin, 1.0e-8);
checkSatVector(orbit, attitude, Vector3D.PLUS_K, 0.0, -sin, cos, 1.0e-8);
// Pitch
attitude = new LofOffset(orbit.getFrame(), LOFType.VVLH, RotationOrder.XYZ, 0.0, alpha, 0.0).getAttitude(orbit, date, orbit.getFrame());
checkSatVector(orbit, attitude, Vector3D.PLUS_I, cos, 0.0, -sin, 1.0e-8);
checkSatVector(orbit, attitude, Vector3D.PLUS_J, 0.0, 1.0, 0.0, 1.0e-8);
checkSatVector(orbit, attitude, Vector3D.PLUS_K, sin, 0.0, cos, 1.0e-8);
// Yaw
attitude = new LofOffset(orbit.getFrame(), LOFType.VVLH, RotationOrder.XYZ, 0.0, 0.0, alpha).getAttitude(orbit, date, orbit.getFrame());
checkSatVector(orbit, attitude, Vector3D.PLUS_I, cos, sin, 0.0, 1.0e-8);
checkSatVector(orbit, attitude, Vector3D.PLUS_J, -sin, cos, 0.0, 1.0e-8);
checkSatVector(orbit, attitude, Vector3D.PLUS_K, 0.0, 0.0, 1.0, 1.0e-8);
}
@Test
public void testRetrieveAngles() throws OrekitException {
AbsoluteDate date = new AbsoluteDate(new DateComponents(1970, 01, 01),
new TimeComponents(3, 25, 45.6789),
TimeScalesFactory.getUTC());
KeplerianOrbit orbit =
new KeplerianOrbit(7178000.0, 1.e-4, FastMath.toRadians(50.),
FastMath.toRadians(10.), FastMath.toRadians(20.),
FastMath.toRadians(30.), PositionAngle.MEAN,
FramesFactory.getEME2000(), date, 3.986004415e14);
RotationOrder order = RotationOrder.ZXY;
double alpha1 = 0.123;
double alpha2 = 0.456;
double alpha3 = 0.789;
LofOffset law = new LofOffset(orbit.getFrame(), LOFType.VVLH, order, alpha1, alpha2, alpha3);
Rotation offsetAtt = law.getAttitude(orbit, date, orbit.getFrame()).getRotation();
Rotation alignedAtt = new LofOffset(orbit.getFrame(), LOFType.VVLH).getAttitude(orbit, date, orbit.getFrame()).getRotation();
Rotation offsetProper = offsetAtt.compose(alignedAtt.revert(), RotationConvention.VECTOR_OPERATOR);
double[] anglesV = offsetProper.revert().getAngles(order, RotationConvention.VECTOR_OPERATOR);
Assert.assertEquals(alpha1, anglesV[0], 1.0e-11);
Assert.assertEquals(alpha2, anglesV[1], 1.0e-11);
Assert.assertEquals(alpha3, anglesV[2], 1.0e-11);
double[] anglesF = offsetProper.getAngles(order, RotationConvention.FRAME_TRANSFORM);
Assert.assertEquals(alpha1, anglesF[0], 1.0e-11);
Assert.assertEquals(alpha2, anglesF[1], 1.0e-11);
Assert.assertEquals(alpha3, anglesF[2], 1.0e-11);
}
private void checkSatVector(Orbit o, Attitude a, Vector3D satVector,
double expectedX, double expectedY, double expectedZ,
double threshold) {
Vector3D zLof = o.getPVCoordinates().getPosition().normalize().negate();
Vector3D yLof = o.getPVCoordinates().getMomentum().normalize().negate();
Vector3D xLof = Vector3D.crossProduct(yLof, zLof);
Assert.assertTrue(Vector3D.dotProduct(xLof, o.getPVCoordinates().getVelocity()) > 0);
Vector3D v = a.getRotation().applyInverseTo(satVector);
Assert.assertEquals(expectedX, Vector3D.dotProduct(v, xLof), 1.0e-8);
Assert.assertEquals(expectedY, Vector3D.dotProduct(v, yLof), 1.0e-8);
Assert.assertEquals(expectedZ, Vector3D.dotProduct(v, zLof), 1.0e-8);
}
@Before
public void setUp() {
try {
Utils.setDataRoot("regular-data");
// Computation date
date = new AbsoluteDate(new DateComponents(2008, 04, 07),
TimeComponents.H00,
TimeScalesFactory.getUTC());
// Body mu
mu = 3.9860047e14;
// Reference frame = ITRF
itrf = FramesFactory.getITRF(IERSConventions.IERS_2010, true);
// Elliptic earth shape
earthSpheric =
new OneAxisEllipsoid(6378136.460, 0., itrf);
// Satellite position
orbit =
new CircularOrbit(7178000.0, 0.5e-8, -0.5e-8, FastMath.toRadians(50.), FastMath.toRadians(150.),
FastMath.toRadians(5.300), PositionAngle.MEAN,
FramesFactory.getEME2000(), date, mu);
pvSatEME2000 = orbit.getPVCoordinates();
} catch (OrekitException oe) {
Assert.fail(oe.getMessage());
}
}
@After
public void tearDown() {
date = null;
itrf = null;
earthSpheric = null;
}
}