1   /* Copyright 2002-2024 CS GROUP
2    * Licensed to CS GROUP (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.estimation.measurements.gnss;
18  
19  import java.util.Arrays;
20  
21  import org.hipparchus.analysis.differentiation.Gradient;
22  import org.orekit.estimation.measurements.EstimatedMeasurement;
23  import org.orekit.estimation.measurements.EstimatedMeasurementBase;
24  import org.orekit.estimation.measurements.GroundReceiverCommonParametersWithDerivatives;
25  import org.orekit.estimation.measurements.GroundReceiverCommonParametersWithoutDerivatives;
26  import org.orekit.estimation.measurements.GroundReceiverMeasurement;
27  import org.orekit.estimation.measurements.GroundStation;
28  import org.orekit.estimation.measurements.ObservableSatellite;
29  import org.orekit.propagation.SpacecraftState;
30  import org.orekit.time.AbsoluteDate;
31  import org.orekit.utils.Constants;
32  import org.orekit.utils.ParameterDriver;
33  import org.orekit.utils.TimeSpanMap.Span;
34  import org.orekit.utils.TimeStampedPVCoordinates;
35  
36  /** Class modeling a phase measurement from a ground station.
37   * <p>
38   * The measurement is considered to be a signal emitted from
39   * a spacecraft and received on a ground station.
40   * Its value is the number of cycles between emission and
41   * reception. The motion of both the station and the
42   * spacecraft during the signal flight time are taken into
43   * account. The date of the measurement corresponds to the
44   * reception on ground of the emitted signal.
45   * </p>
46   * @author Thierry Ceolin
47   * @author Luc Maisonobe
48   * @author Maxime Journot
49   * @since 9.2
50   */
51  public class Phase extends GroundReceiverMeasurement<Phase> {
52  
53      /** Type of the measurement. */
54      public static final String MEASUREMENT_TYPE = "Phase";
55  
56      /** Name for ambiguity driver.
57       * @deprecated as of 12.1 not used anymore
58       */
59      @Deprecated
60      public static final String AMBIGUITY_NAME = "ambiguity";
61  
62      /** Driver for ambiguity. */
63      private final AmbiguityDriver ambiguityDriver;
64  
65      /** Wavelength of the phase observed value [m]. */
66      private final double wavelength;
67  
68      /** Simple constructor.
69       * @param station ground station from which measurement is performed
70       * @param date date of the measurement
71       * @param phase observed value (cycles)
72       * @param wavelength phase observed value wavelength (m)
73       * @param sigma theoretical standard deviation
74       * @param baseWeight base weight
75       * @param satellite satellite related to this measurement
76       * @since 9.3
77       * @deprecated as of 12.1, replaced by {@link #Phase(GroundStation,
78       * AbsoluteDate, double, double, double, double, ObservableSatellite,
79       * AmbiguityCache)}
80       */
81      @Deprecated
82      public Phase(final GroundStation station, final AbsoluteDate date,
83                   final double phase, final double wavelength, final double sigma,
84                   final double baseWeight, final ObservableSatellite satellite) {
85          this(station, date, phase, wavelength, sigma, baseWeight, satellite,
86               AmbiguityCache.DEFAULT_CACHE);
87      }
88  
89      /** Simple constructor.
90       * @param station ground station from which measurement is performed
91       * @param date date of the measurement
92       * @param phase observed value (cycles)
93       * @param wavelength phase observed value wavelength (m)
94       * @param sigma theoretical standard deviation
95       * @param baseWeight base weight
96       * @param satellite satellite related to this measurement
97       * @param cache from which ambiguity drive should come
98       * @since 12.1
99       */
100     public Phase(final GroundStation station, final AbsoluteDate date,
101                  final double phase, final double wavelength, final double sigma,
102                  final double baseWeight, final ObservableSatellite satellite,
103                  final AmbiguityCache cache) {
104         super(station, false, date, phase, sigma, baseWeight, satellite);
105         ambiguityDriver = cache.getAmbiguity(satellite.getName(),
106                                              station.getBaseFrame().getName(),
107                                              wavelength);
108         addParameterDriver(ambiguityDriver);
109         this.wavelength = wavelength;
110     }
111 
112     /** Get the wavelength.
113      * @return wavelength (m)
114      */
115     public double getWavelength() {
116         return wavelength;
117     }
118 
119     /** Get the driver for phase ambiguity.
120      * @return the driver for phase ambiguity
121      * @since 10.3
122      */
123     public AmbiguityDriver getAmbiguityDriver() {
124         return ambiguityDriver;
125     }
126 
127     /** {@inheritDoc} */
128     @Override
129     protected EstimatedMeasurementBase<Phase> theoreticalEvaluationWithoutDerivatives(final int iteration,
130                                                                                       final int evaluation,
131                                                                                       final SpacecraftState[] states) {
132 
133         final GroundReceiverCommonParametersWithoutDerivatives common = computeCommonParametersWithout(states[0]);
134 
135         // prepare the evaluation
136         final EstimatedMeasurementBase<Phase> estimated =
137                         new EstimatedMeasurementBase<>(this, iteration, evaluation,
138                                                        new SpacecraftState[] {
139                                                            common.getTransitState()
140                                                        }, new TimeStampedPVCoordinates[] {
141                                                            common.getTransitPV(),
142                                                            common.getStationDownlink()
143                                                        });
144 
145         // Clock offsets
146         final ObservableSatellite satellite = getSatellites().get(0);
147         final double              dts       = satellite.getClockOffsetDriver().getValue(common.getState().getDate());
148         final double              dtg       = getStation().getClockOffsetDriver().getValue(getDate());
149 
150         // Phase value
151         final double cOverLambda = Constants.SPEED_OF_LIGHT / wavelength;
152         final double ambiguity   = ambiguityDriver.getValue(common.getState().getDate());
153         final double phase       = (common.getTauD() + dtg - dts) * cOverLambda + ambiguity;
154 
155         estimated.setEstimatedValue(phase);
156 
157         return estimated;
158 
159     }
160 
161     /** {@inheritDoc} */
162     @Override
163     protected EstimatedMeasurement<Phase> theoreticalEvaluation(final int iteration,
164                                                                 final int evaluation,
165                                                                 final SpacecraftState[] states) {
166 
167         final SpacecraftState state = states[0];
168 
169         // Phase derivatives are computed with respect to spacecraft state in inertial frame
170         // and station parameters
171         // ----------------------
172         //
173         // Parameters:
174         //  - 0..2 - Position of the spacecraft in inertial frame
175         //  - 3..5 - Velocity of the spacecraft in inertial frame
176         //  - 6..n - station parameters (ambiguity, clock offset, station offsets, pole, prime meridian...)
177         final GroundReceiverCommonParametersWithDerivatives common = computeCommonParametersWithDerivatives(state);
178         final int nbParams = common.getTauD().getFreeParameters();
179 
180         // prepare the evaluation
181         final EstimatedMeasurement<Phase> estimated =
182                         new EstimatedMeasurement<>(this, iteration, evaluation,
183                                                    new SpacecraftState[] {
184                                                        common.getTransitState()
185                                                    }, new TimeStampedPVCoordinates[] {
186                                                        common.getTransitPV().toTimeStampedPVCoordinates(),
187                                                        common.getStationDownlink().toTimeStampedPVCoordinates()
188                                                    });
189 
190         // Clock offsets
191         final ObservableSatellite satellite = getSatellites().get(0);
192         final Gradient            dts       = satellite.getClockOffsetDriver().getValue(nbParams, common.getIndices(), state.getDate());
193         final Gradient            dtg       = getStation().getClockOffsetDriver().getValue(nbParams, common.getIndices(), getDate());
194 
195         // Phase value
196         final double   cOverLambda = Constants.SPEED_OF_LIGHT / wavelength;
197         final Gradient ambiguity   = ambiguityDriver.getValue(nbParams, common.getIndices(), state.getDate());
198         final Gradient phase       = common.getTauD().add(dtg).subtract(dts).multiply(cOverLambda).add(ambiguity);
199 
200         estimated.setEstimatedValue(phase.getValue());
201 
202         // Phase first order derivatives with respect to state
203         final double[] derivatives = phase.getGradient();
204         estimated.setStateDerivatives(0, Arrays.copyOfRange(derivatives, 0, 6));
205 
206         // Set first order derivatives with respect to parameters
207         for (final ParameterDriver driver : getParametersDrivers()) {
208             for (Span<String> span = driver.getNamesSpanMap().getFirstSpan(); span != null; span = span.next()) {
209 
210                 final Integer index = common.getIndices().get(span.getData());
211                 if (index != null) {
212                     estimated.setParameterDerivatives(driver, span.getStart(), derivatives[index]);
213                 }
214             }
215         }
216 
217         return estimated;
218 
219     }
220 
221 }