/* 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 java.util.ArrayList;
import java.util.List;
import org.hipparchus.geometry.euclidean.threed.Rotation;
import org.hipparchus.geometry.euclidean.threed.RotationConvention;
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.CelestialBodyFactory;
import org.orekit.bodies.OneAxisEllipsoid;
import org.orekit.errors.OrekitException;
import org.orekit.frames.Frame;
import org.orekit.frames.FramesFactory;
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.CartesianDerivativesFilter;
import org.orekit.utils.IERSConventions;
import org.orekit.utils.PVCoordinates;
import org.orekit.utils.PVCoordinatesProvider;
import org.orekit.utils.TimeStampedPVCoordinates;
public class YawSteeringTest {
// Computation date
private AbsoluteDate date;
// Reference frame = ITRF
private Frame itrf;
// Satellite position
CircularOrbit circOrbit;
// Earth shape
OneAxisEllipsoid earthShape;
@Test
public void testTarget() throws OrekitException {
// Attitude laws
// **************
// Target pointing attitude provider without yaw compensation
NadirPointing nadirLaw = new NadirPointing(circOrbit.getFrame(), earthShape);
// Target pointing attitude provider with yaw compensation
YawSteering yawCompensLaw =
new YawSteering(circOrbit.getFrame(), nadirLaw, CelestialBodyFactory.getSun(), Vector3D.MINUS_I);
// Check observed ground point
// *****************************
TimeStampedPVCoordinates noYawObserved = nadirLaw.getTargetPV(circOrbit, date, itrf);
// with yaw compensation
TimeStampedPVCoordinates yawObserved = yawCompensLaw.getTargetPV(circOrbit, date, itrf);
// Check difference
PVCoordinates observedDiff = new PVCoordinates(yawObserved, noYawObserved);
Assert.assertEquals(0.0, observedDiff.getPosition().getNorm(), Utils.epsilonTest);
Assert.assertEquals(0.0, observedDiff.getVelocity().getNorm(), Utils.epsilonTest);
Assert.assertEquals(0.0, observedDiff.getAcceleration().getNorm(), Utils.epsilonTest);
Assert.assertSame(nadirLaw, yawCompensLaw.getUnderlyingAttitudeProvider());
}
@Test
public void testSunAligned() throws OrekitException {
// Attitude laws
// **************
// Target pointing attitude provider over satellite nadir at date, without yaw compensation
NadirPointing nadirLaw = new NadirPointing(circOrbit.getFrame(), earthShape);
// Target pointing attitude provider with yaw compensation
PVCoordinatesProvider sun = CelestialBodyFactory.getSun();
YawSteering yawCompensLaw = new YawSteering(circOrbit.getFrame(), nadirLaw, sun, Vector3D.MINUS_I);
// Get sun direction in satellite frame
Rotation rotYaw = yawCompensLaw.getAttitude(circOrbit, date, circOrbit.getFrame()).getRotation();
Vector3D sunEME2000 = sun.getPVCoordinates(date, FramesFactory.getEME2000()).getPosition();
Vector3D sunSat = rotYaw.applyTo(sunEME2000);
// Check sun is in (X,Z) plane
Assert.assertEquals(0.0, FastMath.sin(sunSat.getAlpha()), 1.0e-7);
}
@Test
public void testCompensAxis() throws OrekitException {
// Attitude laws
// **************
// Target pointing attitude provider over satellite nadir at date, without yaw compensation
NadirPointing nadirLaw = new NadirPointing(circOrbit.getFrame(), earthShape);
// Target pointing attitude provider with yaw compensation
YawSteering yawCompensLaw =
new YawSteering(circOrbit.getFrame(), nadirLaw, CelestialBodyFactory.getSun(), Vector3D.MINUS_I);
// Get attitude rotations from non yaw compensated / yaw compensated laws
Rotation rotNoYaw = nadirLaw.getAttitude(circOrbit, date, circOrbit.getFrame()).getRotation();
Rotation rotYaw = yawCompensLaw.getAttitude(circOrbit, date, circOrbit.getFrame()).getRotation();
// Compose rotations composition
Rotation compoRot = rotYaw.compose(rotNoYaw.revert(), RotationConvention.VECTOR_OPERATOR);
Vector3D yawAxis = compoRot.getAxis(RotationConvention.VECTOR_OPERATOR);
// Check axis
Assert.assertEquals(0., yawAxis.getX(), Utils.epsilonTest);
Assert.assertEquals(0., yawAxis.getY(), Utils.epsilonTest);
Assert.assertEquals(1., yawAxis.getZ(), Utils.epsilonTest);
}
/** Test the derivatives of the sliding target
*/
@Test
public void testSlidingDerivatives() throws OrekitException {
GroundPointing law = new YawSteering(circOrbit.getFrame(),
new NadirPointing(circOrbit.getFrame(), earthShape),
CelestialBodyFactory.getSun(),
Vector3D.MINUS_I);
List<TimeStampedPVCoordinates> sample = new ArrayList<TimeStampedPVCoordinates>();
for (double dt = -0.1; dt < 0.1; dt += 0.05) {
Orbit o = circOrbit.shiftedBy(dt);
sample.add(law.getTargetPV(o, o.getDate(), o.getFrame()));
}
TimeStampedPVCoordinates reference =
TimeStampedPVCoordinates.interpolate(circOrbit.getDate(),
CartesianDerivativesFilter.USE_P, sample);
TimeStampedPVCoordinates target =
law.getTargetPV(circOrbit, circOrbit.getDate(), circOrbit.getFrame());
Assert.assertEquals(0.0,
Vector3D.distance(reference.getPosition(), target.getPosition()),
1.0e-15 * reference.getPosition().getNorm());
Assert.assertEquals(0.0,
Vector3D.distance(reference.getVelocity(), target.getVelocity()),
4.0e-11 * reference.getVelocity().getNorm());
Assert.assertEquals(0.0,
Vector3D.distance(reference.getAcceleration(), target.getAcceleration()),
8.0e-6 * reference.getAcceleration().getNorm());
}
@Test
public void testSpin() throws OrekitException {
NadirPointing nadirLaw = new NadirPointing(circOrbit.getFrame(), earthShape);
// Target pointing attitude provider with yaw compensation
AttitudeProvider law = new YawSteering(circOrbit.getFrame(), nadirLaw, CelestialBodyFactory.getSun(), Vector3D.MINUS_I);
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.shiftedBy(-300.0),
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-9 * 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-9 * evolutionAnglePlus);
Vector3D spin0 = s0.getAttitude().getSpin();
Vector3D reference = AngularCoordinates.estimateRate(sMinus.getAttitude().getRotation(),
sPlus.getAttitude().getRotation(),
2 * h);
Assert.assertTrue(spin0.getNorm() > 1.0e-3);
Assert.assertEquals(0.0, spin0.subtract(reference).getNorm(), 5.0e-13);
}
@Before
public void setUp() {
try {
Utils.setDataRoot("regular-data");
// Computation date
date = new AbsoluteDate(new DateComponents(1970, 04, 07),
TimeComponents.H00,
TimeScalesFactory.getUTC());
// Body mu
final double mu = 3.9860047e14;
// Reference frame = ITRF
itrf = FramesFactory.getITRF(IERSConventions.IERS_2010, true);
// Satellite position
circOrbit =
new CircularOrbit(7178000.0, 0.5e-4, -0.5e-4, FastMath.toRadians(50.), FastMath.toRadians(270.),
FastMath.toRadians(5.300), PositionAngle.MEAN,
FramesFactory.getEME2000(), date, mu);
// Elliptic earth shape */
earthShape =
new OneAxisEllipsoid(6378136.460, 1 / 298.257222101, itrf);
} catch (OrekitException oe) {
Assert.fail(oe.getMessage());
}
}
@After
public void tearDown() {
date = null;
itrf = null;
circOrbit = null;
earthShape = null;
}
}