1   package org.orekit.rugged.adjustment.util;
2   
3   import java.util.ArrayList;
4   import java.util.List;
5   
6   import org.hipparchus.geometry.euclidean.threed.Rotation;
7   import org.hipparchus.geometry.euclidean.threed.RotationConvention;
8   import org.hipparchus.geometry.euclidean.threed.RotationOrder;
9   import org.hipparchus.geometry.euclidean.threed.Vector3D;
10  import org.hipparchus.util.FastMath;
11  import org.orekit.attitudes.AttitudeProvider;
12  import org.orekit.attitudes.LofOffset;
13  import org.orekit.attitudes.NadirPointing;
14  import org.orekit.attitudes.TabulatedLofOffset;
15  import org.orekit.attitudes.YawCompensation;
16  import org.orekit.bodies.BodyShape;
17  import org.orekit.frames.Frame;
18  import org.orekit.frames.FramesFactory;
19  import org.orekit.frames.LOFType;
20  import org.orekit.orbits.CircularOrbit;
21  import org.orekit.orbits.Orbit;
22  import org.orekit.orbits.PositionAngleType;
23  import org.orekit.propagation.Propagator;
24  import org.orekit.propagation.analytical.KeplerianPropagator;
25  import org.orekit.time.AbsoluteDate;
26  import org.orekit.utils.AngularDerivativesFilter;
27  import org.orekit.utils.Constants;
28  import org.orekit.utils.TimeStampedAngularCoordinates;
29  import org.orekit.utils.TimeStampedPVCoordinates;
30  
31  /**
32   * Class to compute Pleiades orbit for refining Junit tests.
33   */
34  public class PleiadesOrbitModel {
35  
36      /** Flag to change Attitude Law (by default Nadir Pointing Yaw Compensation). */
37      private boolean userDefinedLOFTransform;
38  
39      /** User defined Roll law. */
40      private double[] lofTransformRollPoly;
41  
42      /** User defined Pitch law. */
43      private double[] lofTransformPitchPoly;
44  
45      /** User defined Yaw law. */
46      private double[] lofTransformYawPoly;
47  
48      /** Reference date. */
49      private AbsoluteDate refDate;
50  
51      /** Default constructor.
52       */
53      public PleiadesOrbitModel() {
54          userDefinedLOFTransform = false;
55      }
56  
57      /** Create a circular orbit.
58       */
59      public Orbit createOrbit(final double mu, final AbsoluteDate date) {
60          
61          // the following orbital parameters have been computed using
62          // Orekit tutorial about phasing, using the following configuration:
63          //
64          // orbit.date = 2012-01-01T00:00:00.000
65          // phasing.orbits.number = 143
66          // phasing.days.number = 10
67          // sun.synchronous.reference.latitude = 0
68          // sun.synchronous.reference.ascending = false
69          // sun.synchronous.mean.solar.time = 10:30:00
70          // gravity.field.degree = 12
71          // gravity.field.order = 12
72  
73          final Frame eme2000 = FramesFactory.getEME2000();
74          return new CircularOrbit(694000.0 + Constants.WGS84_EARTH_EQUATORIAL_RADIUS,
75                                   -4.029194321683225E-4,
76                                   0.0013530362644647786,
77                                   FastMath.toRadians(98.2), // Pleiades inclination 98.2 deg
78                                   FastMath.toRadians(-86.47 + 180),
79                                   FastMath.toRadians(135.9 + 0.3),
80                                   PositionAngleType.TRUE,
81                                   eme2000,
82                                   date,
83                                   mu);
84      }
85  
86      /** Set the Local Orbital Frame characteristics.
87       */
88      public void setLOFTransform(final double[] rollPoly, final double[] pitchPoly,
89                                  final double[] yawPoly, final AbsoluteDate date) {
90  
91          this.userDefinedLOFTransform = true;
92          lofTransformRollPoly = rollPoly.clone();
93          lofTransformPitchPoly = pitchPoly.clone();
94          lofTransformYawPoly = yawPoly.clone();
95          this.refDate = date;
96      }
97  
98      /** Recompute the polynom coefficients with shift.
99       */
100     private double getPoly(final double[] poly, final double shift) {
101         
102         double val = 0.0;
103         for (int coef = 0; coef < poly.length; coef++) {
104             val = val + poly[coef] * FastMath.pow(shift, coef);
105         }
106         return val;
107     }
108 
109     /** Get the offset.
110      */
111    private Rotation getOffset(final BodyShape earth, final Orbit orbit, final double shift) {
112         
113         final LOFType type = LOFType.VVLH;
114         final double roll = getPoly(lofTransformRollPoly, shift);
115         final double pitch = getPoly(lofTransformPitchPoly, shift);
116         final double yaw = getPoly(lofTransformYawPoly, shift);
117 
118         final LofOffset law = new LofOffset(orbit.getFrame(), type, RotationOrder.XYZ,
119                                       roll, pitch, yaw);
120         final Rotation offsetAtt = law.
121                                    getAttitude(orbit, orbit.getDate().shiftedBy(shift), orbit.getFrame()).
122                                    getRotation();
123         final NadirPointing nadirPointing = new NadirPointing(orbit.getFrame(), earth);
124         final Rotation nadirAtt = nadirPointing.
125                                   getAttitude(orbit, orbit.getDate().getDate().shiftedBy(shift), orbit.getFrame()).
126                                   getRotation();
127         final Rotation offsetProper = offsetAtt.compose(nadirAtt.revert(), RotationConvention.VECTOR_OPERATOR);
128 
129         return offsetProper;
130     }
131 
132    /** Create the attitude provider.
133     */
134     public AttitudeProvider createAttitudeProvider(final BodyShape earth, final Orbit orbit) {
135 
136         if (userDefinedLOFTransform) {
137             final LOFType type = LOFType.VVLH;
138 
139             final List<TimeStampedAngularCoordinates> list = new ArrayList<TimeStampedAngularCoordinates>();
140 
141             for (double shift = -10.0; shift < +10.0; shift += 1e-2) {
142                 list.add(new TimeStampedAngularCoordinates(refDate.shiftedBy(shift), 
143                                                            getOffset(earth, orbit, shift),
144                                                            Vector3D.ZERO,
145                                                            Vector3D.ZERO));
146             }
147 
148             final TabulatedLofOffset tabulated = new TabulatedLofOffset(orbit.getFrame(), type, list,
149                                                                         2, AngularDerivativesFilter.USE_R);
150 
151             return tabulated;
152         } else {
153             return new YawCompensation(orbit.getFrame(), new NadirPointing(orbit.getFrame(), earth));
154         }
155     }
156 
157    /** Generate the orbit.
158     */
159    public List<TimeStampedPVCoordinates> orbitToPV(final Orbit orbit, final BodyShape earth,
160                                                     final AbsoluteDate minDate, final AbsoluteDate maxDate,
161                                                     final double step) {
162         
163         final Propagator propagator = new KeplerianPropagator(orbit);
164 
165         propagator.setAttitudeProvider(createAttitudeProvider(earth, orbit));
166 
167         propagator.propagate(minDate);
168         final List<TimeStampedPVCoordinates> list = new ArrayList<TimeStampedPVCoordinates>();
169         propagator.getMultiplexer().add(step,
170                                  currentState -> list.add(new TimeStampedPVCoordinates(currentState.getDate(),
171                                                                                        currentState.getPVCoordinates().getPosition(),
172                                                                                        currentState.getPVCoordinates().getVelocity(),
173                                                                                        Vector3D.ZERO)));
174         propagator.propagate(maxDate);
175 
176         return list;
177     }
178 
179    /** Generate the attitude.
180     */
181    public List<TimeStampedAngularCoordinates> orbitToQ(final Orbit orbit, final BodyShape earth,
182                                                         final AbsoluteDate minDate, final AbsoluteDate maxDate,
183                                                         final double step) {
184         
185         final Propagator propagator = new KeplerianPropagator(orbit);
186         propagator.setAttitudeProvider(createAttitudeProvider(earth, orbit));
187         propagator.propagate(minDate);
188         final List<TimeStampedAngularCoordinates> list = new ArrayList<>();
189         propagator.getMultiplexer().add(step,
190                                         currentState -> list.add(new TimeStampedAngularCoordinates(currentState.getDate(),
191                                                                                                    currentState.getAttitude().getRotation(),
192                                                                                                    Vector3D.ZERO,
193                                                                                                    Vector3D.ZERO)));
194         propagator.propagate(maxDate);
195 
196         return list;
197     }
198 }