1   /* Copyright 2002-2019 CS Systèmes d'Information
2    * Licensed to CS Systèmes d'Information (CS) under one or more
3    * contributor license agreements.  See the NOTICE file distributed with
4    * this work for additional information regarding copyright ownership.
5    * CS licenses this file to You under the Apache License, Version 2.0
6    * (the "License"); you may not use this file except in compliance with
7    * the License.  You may obtain a copy of the License at
8    *
9    *   http://www.apache.org/licenses/LICENSE-2.0
10   *
11   * Unless required by applicable law or agreed to in writing, software
12   * distributed under the License is distributed on an "AS IS" BASIS,
13   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14   * See the License for the specific language governing permissions and
15   * limitations under the License.
16   */
17  package org.orekit.gnss.attitude;
18  
19  import java.util.HashMap;
20  import java.util.Map;
21  import java.util.SortedSet;
22  import java.util.TreeSet;
23  
24  import org.hipparchus.Field;
25  import org.hipparchus.RealFieldElement;
26  import org.orekit.attitudes.Attitude;
27  import org.orekit.attitudes.FieldAttitude;
28  import org.orekit.frames.Frame;
29  import org.orekit.time.AbsoluteDate;
30  import org.orekit.time.ChronologicalComparator;
31  import org.orekit.time.FieldAbsoluteDate;
32  import org.orekit.time.TimeStamped;
33  import org.orekit.utils.ExtendedPVCoordinatesProvider;
34  import org.orekit.utils.FieldPVCoordinatesProvider;
35  import org.orekit.utils.PVCoordinatesProvider;
36  import org.orekit.utils.TimeStampedAngularCoordinates;
37  import org.orekit.utils.TimeStampedFieldAngularCoordinates;
38  
39  /**
40   * Base class for attitude providers for navigation satellites.
41   *
42   * @author Luc Maisonobe
43   * @since 9.2
44   */
45  public abstract class AbstractGNSSAttitudeProvider implements GNSSAttitudeProvider {
46  
47      /** Serializable UID. */
48      private static final long serialVersionUID = 20171114L;
49  
50      /** Start of validity for this provider. */
51      private final AbsoluteDate validityStart;
52  
53      /** End of validity for this provider. */
54      private final AbsoluteDate validityEnd;
55  
56      /** Provider for Sun position. */
57      private final ExtendedPVCoordinatesProvider sun;
58  
59      /** Inertial frame where velocity are computed. */
60      private final Frame inertialFrame;
61  
62      /** Turns already encountered. */
63      private final SortedSet<TimeStamped> turns;
64  
65      /** Turns already encountered. */
66      private final transient Map<Field<? extends RealFieldElement<?>>, SortedSet<TimeStamped>> fieldTurns;
67  
68      /** Simple constructor.
69       * @param validityStart start of validity for this provider
70       * @param validityEnd end of validity for this provider
71       * @param sun provider for Sun position
72       * @param inertialFrame inertial frame where velocity are computed
73       */
74      protected AbstractGNSSAttitudeProvider(final AbsoluteDate validityStart,
75                                             final AbsoluteDate validityEnd,
76                                             final ExtendedPVCoordinatesProvider sun,
77                                             final Frame inertialFrame) {
78          this.validityStart = validityStart;
79          this.validityEnd   = validityEnd;
80          this.sun           = sun;
81          this.inertialFrame = inertialFrame;
82          this.turns         = new TreeSet<>(new ChronologicalComparator());
83          this.fieldTurns    = new HashMap<>();
84      }
85  
86      /** {@inheritDoc} */
87      @Override
88      public AbsoluteDate validityStart() {
89          return validityStart;
90      }
91  
92      /** {@inheritDoc} */
93      @Override
94      public AbsoluteDate validityEnd() {
95          return validityEnd;
96      }
97  
98      /** {@inheritDoc} */
99      @Override
100     public Attitude getAttitude(final PVCoordinatesProvider pvProv,
101                                 final AbsoluteDate date,
102                                 final Frame frame) {
103 
104         // compute yaw correction
105         final TurnSpan                      turnSpan  = getTurnSpan(date);
106         final GNSSAttitudeContextAttitudeContext">GNSSAttitudeContext           context   = new GNSSAttitudeContext(date, sun, pvProv, inertialFrame, turnSpan);
107         final TimeStampedAngularCoordinates corrected = correctedYaw(context);
108         if (turnSpan == null && context.getTurnSpan() != null) {
109             // we have encountered a new turn, store it
110             turns.add(context.getTurnSpan());
111         }
112 
113         return new Attitude(inertialFrame, corrected).withReferenceFrame(frame);
114 
115     }
116 
117     /** {@inheritDoc} */
118     @Override
119     public <T extends RealFieldElement<T>> FieldAttitude<T> getAttitude(final FieldPVCoordinatesProvider<T> pvProv,
120                                                                         final FieldAbsoluteDate<T> date,
121                                                                         final Frame frame) {
122 
123         // compute yaw correction
124         final FieldTurnSpan<T>                      turnSpan  = getTurnSpan(date);
125         final GNSSFieldAttitudeContext<T>           context   = new GNSSFieldAttitudeContext<>(date, sun, pvProv, inertialFrame, turnSpan);
126         final TimeStampedFieldAngularCoordinates<T> corrected = correctedYaw(context);
127         if (turnSpan == null && context.getTurnSpan() != null) {
128             // we have encountered a new turn, store it
129             fieldTurns.get(date.getField()).add(context.getTurnSpan());
130         }
131 
132         return new FieldAttitude<>(inertialFrame, corrected).withReferenceFrame(frame);
133 
134     }
135 
136     /** Get the turn span covering a date.
137      * @param date date to check
138      * @return turn span covering the date, or null if no span covers this date
139      */
140     private TurnSpan getTurnSpan(final AbsoluteDate date) {
141 
142         // as the reference date of the turn span is the end + margin date,
143         // the span to consider can only be the first span that is after date
144         final SortedSet<TimeStamped> after = turns.tailSet(date);
145         if (!after.isEmpty()) {
146             final TurnSpan="../../../../org/orekit/gnss/attitude/TurnSpan.html#TurnSpan">TurnSpan ts = (TurnSpan) after.first();
147             if (ts.inTurnTimeRange(date)) {
148                 return ts;
149             }
150         }
151 
152         // no turn covers the date
153         return null;
154 
155     }
156 
157     /** Get the turn span covering a date.
158      * @param date date to check
159      * @param <T> type of the field elements
160      * @return turn span covering the date, or null if no span covers this date
161      */
162     private <T extends RealFieldElement<T>> FieldTurnSpan<T> getTurnSpan(final FieldAbsoluteDate<T> date) {
163 
164         SortedSet<TimeStamped> sortedSet = fieldTurns.get(date.getField());
165         if (sortedSet == null) {
166             // this is the first time we manage such a field, prepare a sorted set for it
167             sortedSet = new TreeSet<>(new ChronologicalComparator());
168             fieldTurns.put(date.getField(), sortedSet);
169         }
170 
171         // as the reference date of the turn span is the end + margin date,
172         // the span to consider can only be the first span that is after date
173         final AbsoluteDate dateDouble = date.toAbsoluteDate();
174         final SortedSet<TimeStamped> after = sortedSet.tailSet(dateDouble);
175         if (!after.isEmpty()) {
176             @SuppressWarnings("unchecked")
177             final FieldTurnSpan<T> ts = (FieldTurnSpan<T>) after.first();
178             if (ts.inTurnTimeRange(dateDouble)) {
179                 return ts;
180             }
181         }
182 
183         // no turn covers the date
184         return null;
185 
186     }
187 
188     /** Select the
189     /** Compute GNSS attitude with midnight/noon yaw turn correction.
190      * @param context context data for attitude computation
191      * @return corrected yaw, using inertial frame as the reference
192      */
193     protected abstract TimeStampedAngularCoordinates correctedYaw(GNSSAttitudeContext context);
194 
195     /** Compute GNSS attitude with midnight/noon yaw turn correction.
196      * @param context context data for attitude computation
197      * @param <T> type of the field elements
198      * @return corrected yaw, using inertial frame as the reference
199      */
200     protected abstract <T extends RealFieldElement<T>> TimeStampedFieldAngularCoordinates<T>
201         correctedYaw(GNSSFieldAttitudeContext<T> context);
202 
203 }