/* 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.Line; 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.GeodeticPoint; import org.orekit.bodies.OneAxisEllipsoid; import org.orekit.errors.OrekitException; import org.orekit.errors.OrekitMessages; import org.orekit.frames.Frame; import org.orekit.frames.FramesFactory; import org.orekit.frames.Transform; 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.Constants; import org.orekit.utils.IERSConventions; import org.orekit.utils.PVCoordinates; public class TargetPointingTest { // Computation date private AbsoluteDate date; // Body mu private double mu; // Reference frame = ITRF private Frame itrf; // Transform from EME2000 to ITRF private Transform eme2000ToItrf; /** Test if both constructors are equivalent */ @Test public void testConstructors() throws OrekitException { // Satellite position // ******************** CircularOrbit circ = 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); // Attitude laws // *************** // Elliptic earth shape OneAxisEllipsoid earthShape = new OneAxisEllipsoid(6378136.460, 1 / 298.257222101, itrf); // Target definition as a geodetic point AND as a position/velocity vector GeodeticPoint geoTargetITRF = new GeodeticPoint(FastMath.toRadians(43.36), FastMath.toRadians(1.26), 600.); Vector3D pTargetITRF = earthShape.transform(geoTargetITRF); // Attitude law definition from geodetic point target TargetPointing geoTargetAttitudeLaw = new TargetPointing(circ.getFrame(), geoTargetITRF, earthShape); // Attitude law definition from position/velocity target TargetPointing pvTargetAttitudeLaw = new TargetPointing(circ.getFrame(), itrf, pTargetITRF); // Check that both attitude are the same // Get satellite rotation for target pointing law Rotation rotPv = pvTargetAttitudeLaw.getAttitude(circ, date, circ.getFrame()).getRotation(); // Get satellite rotation for nadir pointing law Rotation rotGeo = geoTargetAttitudeLaw.getAttitude(circ, date, circ.getFrame()).getRotation(); // Rotations composition Rotation rotCompo = rotGeo.composeInverse(rotPv, RotationConvention.VECTOR_OPERATOR); double angle = rotCompo.getAngle(); Assert.assertEquals(angle, 0.0, Utils.epsilonAngle); } /** Test if geodetic constructor works */ @Test public void testGeodeticConstructor() throws OrekitException { // Satellite position // ******************** CircularOrbit circ = 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); // Attitude law // ************** // Elliptic earth shape OneAxisEllipsoid earthShape = new OneAxisEllipsoid(6378136.460, 1 / 298.257222101, itrf); // Target definition as a geodetic point GeodeticPoint geoTargetITRF = new GeodeticPoint(FastMath.toRadians(43.36), FastMath.toRadians(1.26), 600.); // Attitude law definition TargetPointing geoTargetAttitudeLaw = new TargetPointing(circ.getFrame(), geoTargetITRF, earthShape); // Check that observed ground point is the same as defined target Vector3D pObservedEME2000 = geoTargetAttitudeLaw.getTargetPV(circ, date, FramesFactory.getEME2000()).getPosition(); GeodeticPoint geoObserved = earthShape.transform(pObservedEME2000, FramesFactory.getEME2000(), date); Assert.assertEquals(geoObserved.getLongitude(), geoTargetITRF.getLongitude(), Utils.epsilonAngle); Assert.assertEquals(geoObserved.getLatitude(), geoTargetITRF.getLatitude(), Utils.epsilonAngle); Assert.assertEquals(geoObserved.getAltitude(), geoTargetITRF.getAltitude(), 1.1e-8); } @Test public void testIssue115() throws OrekitException { // Satellite position // ******************** CircularOrbit circ = 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); // Attitude law // ************** // Elliptic earth shape OneAxisEllipsoid earthShape = new OneAxisEllipsoid(6378136.460, 1 / 298.257222101, itrf); // Target definition as a geodetic point GeodeticPoint geoTargetITRF = new GeodeticPoint(FastMath.toRadians(43.36), FastMath.toRadians(1.26), 600.); // Attitude law definition TargetPointing geoTargetAttitudeLaw = new TargetPointing(circ.getFrame(), geoTargetITRF, earthShape); // Check that observed ground point is the same as defined target Frame cirf = FramesFactory.getCIRF(IERSConventions.IERS_2010, true); Attitude att1 = geoTargetAttitudeLaw.getAttitude(circ, date, cirf); Attitude att2 = geoTargetAttitudeLaw.getAttitude(circ, date, itrf); Attitude att3 = att2.withReferenceFrame(cirf); Assert.assertEquals(0.0, Rotation.distance(att3.getRotation(), att1.getRotation()), 1.0e-15); } @Test public void testWrongFrame() { try { // in the following line, the frames have been intentionnally reversed new TargetPointing(itrf, FramesFactory.getEME2000(), new Vector3D(Constants.WGS84_EARTH_EQUATORIAL_RADIUS, 0, 0)); Assert.fail("an exception should have been thrown"); } catch (OrekitException oe) { Assert.assertEquals(OrekitMessages.NON_PSEUDO_INERTIAL_FRAME, oe.getSpecifier()); Assert.assertEquals(itrf.getName(), oe.getParts()[0]); } } /** Test with nadir target : Check that when the target is the same as nadir target at date, * satellite attitude is the same as nadir attitude at the same date, but different at a different date. */ @Test public void testNadirTarget() throws OrekitException { // Elliptic earth shape OneAxisEllipsoid earthShape = new OneAxisEllipsoid(6378136.460, 1 / 298.257222101, itrf); // Satellite on any position CircularOrbit circOrbit = new CircularOrbit(7178000.0, 1.e-5, 0., FastMath.toRadians(50.), 0., FastMath.toRadians(90.), PositionAngle.TRUE, FramesFactory.getEME2000(), date, mu); // Target attitude provider with target under satellite nadir // ******************************************************* // Definition of nadir target // Create nadir pointing attitude provider NadirPointing nadirAttitudeLaw = new NadirPointing(circOrbit.getFrame(), earthShape); // Check nadir target Vector3D pNadirTarget = nadirAttitudeLaw.getTargetPV(circOrbit, date, itrf).getPosition(); GeodeticPoint geoNadirTarget = earthShape.transform(pNadirTarget, itrf, date); // Create target attitude provider TargetPointing targetAttitudeLaw = new TargetPointing(circOrbit.getFrame(), geoNadirTarget, earthShape); // 1/ Test that attitudes are the same at date // ********************************************* // i.e the composition of inverse earth pointing rotation // with nadir pointing rotation shall be identity. // Get satellite rotation from target pointing law at date Rotation rotTarget = targetAttitudeLaw.getAttitude(circOrbit, date, circOrbit.getFrame()).getRotation(); // Get satellite rotation from nadir pointing law at date Rotation rotNadir = nadirAttitudeLaw.getAttitude(circOrbit, date, circOrbit.getFrame()).getRotation(); // Compose attitude rotations Rotation rotCompo = rotTarget.composeInverse(rotNadir, RotationConvention.VECTOR_OPERATOR); double angle = rotCompo.getAngle(); Assert.assertEquals(angle, 0.0, Utils.epsilonAngle); // 2/ Test that attitudes are different at a different date // ********************************************************** // Extrapolation one minute later KeplerianPropagator extrapolator = new KeplerianPropagator(circOrbit); double delta_t = 60.0; // extrapolation duration in seconds AbsoluteDate extrapDate = date.shiftedBy(delta_t); Orbit extrapOrbit = extrapolator.propagate(extrapDate).getOrbit(); // Get satellite rotation from target pointing law at date + 1min Rotation extrapRotTarget = targetAttitudeLaw.getAttitude(extrapOrbit, extrapDate, extrapOrbit.getFrame()).getRotation(); // Get satellite rotation from nadir pointing law at date Rotation extrapRotNadir = nadirAttitudeLaw.getAttitude(extrapOrbit, extrapDate, extrapOrbit.getFrame()).getRotation(); // Compose attitude rotations Rotation extrapRotCompo = extrapRotTarget.composeInverse(extrapRotNadir, RotationConvention.VECTOR_OPERATOR); double extrapAngle = extrapRotCompo.getAngle(); Assert.assertEquals(extrapAngle, FastMath.toRadians(24.684793905118823), Utils.epsilonAngle); } /** Test if defined target belongs to the direction pointed by the satellite */ @Test public void testTargetInPointingDirection() throws OrekitException { // Create computation date AbsoluteDate date = new AbsoluteDate(new DateComponents(2008, 04, 07), TimeComponents.H00, TimeScalesFactory.getUTC()); // Reference frame = ITRF Frame itrf = FramesFactory.getITRF(IERSConventions.IERS_2010, true); // Elliptic earth shape OneAxisEllipsoid earthShape = new OneAxisEllipsoid(6378136.460, 1 / 298.257222101, itrf); // Create target pointing attitude provider GeodeticPoint geoTarget = new GeodeticPoint(FastMath.toRadians(43.36), FastMath.toRadians(1.26), 600.); TargetPointing targetAttitudeLaw = new TargetPointing(FramesFactory.getEME2000(), geoTarget, earthShape); // Satellite position // ******************** // Create satellite position as circular parameters CircularOrbit circ = 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); // Transform satellite position to position/velocity parameters in EME2000 frame PVCoordinates pvSatEME2000 = circ.getPVCoordinates(); // Pointing direction // ******************** // Get satellite attitude rotation, i.e rotation from EME2000 frame to satellite frame Rotation rotSatEME2000 = targetAttitudeLaw.getAttitude(circ, date, circ.getFrame()).getRotation(); // Transform Z axis from satellite frame to EME2000 Vector3D zSatEME2000 = rotSatEME2000.applyInverseTo(Vector3D.PLUS_K); // Line containing satellite point and following pointing direction Vector3D p = eme2000ToItrf.transformPosition(pvSatEME2000.getPosition()); Line pointingLine = new Line(p, p.add(Constants.WGS84_EARTH_EQUATORIAL_RADIUS, eme2000ToItrf.transformVector(zSatEME2000)), 1.0e-10); // Check that the line contains earth center double distance = pointingLine.distance(earthShape.transform(geoTarget)); Assert.assertEquals(0, distance, 1.e-7); } /** Test the difference between pointing over two longitudes separated by 5° */ @Test public void testSlewedTarget() throws OrekitException { // Spheric earth shape OneAxisEllipsoid earthShape = new OneAxisEllipsoid(6378136.460, 0., itrf); // Satellite position // ******************** // Create satellite position as circular parameters CircularOrbit circ = new CircularOrbit(42164000.0, 0.5e-8, -0.5e-8, 0., 0., FastMath.toRadians(5.300), PositionAngle.MEAN, FramesFactory.getEME2000(), date, mu); // Create nadir pointing attitude provider // ********************************** NadirPointing nadirAttitudeLaw = new NadirPointing(circ.getFrame(), earthShape); // Get observed ground point from nadir pointing law Vector3D pNadirObservedEME2000 = nadirAttitudeLaw.getTargetPV(circ, date, FramesFactory.getEME2000()).getPosition(); Vector3D pNadirObservedITRF = eme2000ToItrf.transformPosition(pNadirObservedEME2000); GeodeticPoint geoNadirObserved = earthShape.transform(pNadirObservedITRF, itrf, date); // Create target pointing attitude provider with target equal to nadir target // ********************************************************************* TargetPointing targetLawRef = new TargetPointing(circ.getFrame(), itrf, pNadirObservedITRF); // Get attitude rotation in EME2000 Rotation rotSatRefEME2000 = targetLawRef.getAttitude(circ, date, circ.getFrame()).getRotation(); // Create target pointing attitude provider with target 5° from nadir target // ******************************************************************** GeodeticPoint geoTarget = new GeodeticPoint(geoNadirObserved.getLatitude(), geoNadirObserved.getLongitude() - FastMath.toRadians(5), geoNadirObserved.getAltitude()); Vector3D pTargetITRF = earthShape.transform(geoTarget); TargetPointing targetLaw = new TargetPointing(circ.getFrame(), itrf, pTargetITRF); // Get attitude rotation Rotation rotSatEME2000 = targetLaw.getAttitude(circ, date, circ.getFrame()).getRotation(); // Compute difference between both attitude providers // ********************************************* // Difference between attitudes // expected double tanDeltaExpected = (6378136.460/(42164000.0-6378136.460))*FastMath.tan(FastMath.toRadians(5)); double deltaExpected = FastMath.atan(tanDeltaExpected); // real double deltaReal = Rotation.distance(rotSatEME2000, rotSatRefEME2000); Assert.assertEquals(deltaReal, deltaExpected, 1.e-4); } @Test public void testSpin() throws OrekitException { Frame itrf = FramesFactory.getITRF(IERSConventions.IERS_2010, true); // Elliptic earth shape OneAxisEllipsoid earthShape = new OneAxisEllipsoid(6378136.460, 1 / 298.257222101, itrf); // Create target pointing attitude provider GeodeticPoint geoTarget = new GeodeticPoint(FastMath.toRadians(43.36), FastMath.toRadians(1.26), 600.); AttitudeProvider law = new TargetPointing(FramesFactory.getEME2000(), geoTarget, earthShape); 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-5 * 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-5 * 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.1e-10); } @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); // Transform from EME2000 to ITRF eme2000ToItrf = FramesFactory.getEME2000().getTransformTo(itrf, date); } catch (OrekitException oe) { Assert.fail(oe.getMessage()); } } @After public void tearDown() { date = null; itrf = null; eme2000ToItrf = null; } }