1   /* Copyright 2002-2026 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 org.hipparchus.analysis.differentiation.Gradient;
20  import org.orekit.estimation.measurements.EstimatedMeasurement;
21  import org.orekit.estimation.measurements.EstimatedMeasurementBase;
22  import org.orekit.estimation.measurements.MeasurementQuality;
23  import org.orekit.estimation.measurements.ObservableSatellite;
24  import org.orekit.estimation.measurements.Observer;
25  import org.orekit.propagation.SpacecraftState;
26  import org.orekit.signal.SignalTravelTimeModel;
27  import org.orekit.time.AbsoluteDate;
28  import org.orekit.utils.Constants;
29  import org.orekit.utils.TimeStampedPVCoordinates;
30  
31  /** One-way GNSS phase measurement.
32   * <p>
33   * This class can be used in precise orbit determination applications
34   * for modeling a phase measurement between a GNSS emitter
35   * and a LEO satellite (receiver).
36   * <p>
37   * The one-way GNSS phase measurement assumes knowledge of the orbit and
38   * the clock offset of the emitting GNSS satellite. For instance, it is
39   * possible to use a SP3 file or a GNSS navigation message to recover
40   * the satellite's orbit and clock.
41   * <p>
42   * This class is very similar to {@link InterSatellitesPhase} measurement
43   * class. However, using the one-way GNSS phase measurement, the orbit and clock
44   * of the emitting GNSS satellite are <b>NOT</b> estimated simultaneously with
45   * LEO satellite coordinates.
46   *
47   * @author Bryan Cazabonne
48   * @since 10.3
49   */
50  public class OneWayGNSSPhase extends AbstractOneWayGNSS<OneWayGNSSPhase> {
51  
52      /** Type of the measurement. */
53      public static final String MEASUREMENT_TYPE = "OneWayGNSSPhase";
54  
55      /** Driver for ambiguity. */
56      private final AmbiguityDriver ambiguityDriver;
57  
58      /** Wavelength of the phase observed value [m]. */
59      private final double wavelength;
60  
61      /** Simple constructor.
62       * @param observer object that sends signal
63       * @param date date of the measurement
64       * @param phase observed value, in cycles
65       * @param wavelength phase observed value wavelength, in meters
66       * @param sigma theoretical standard deviation
67       * @param baseWeight base weight
68       * @param local satellite which receives the signal and perform the measurement
69       * @param cache from which ambiguity drive should come
70       * @since 12.1
71       */
72      public OneWayGNSSPhase(final Observer observer,
73                             final AbsoluteDate date,
74                             final double phase, final double wavelength, final double sigma,
75                             final double baseWeight, final ObservableSatellite local,
76                             final AmbiguityCache cache) {
77          this(observer, date, phase, wavelength, new MeasurementQuality(sigma, baseWeight), new SignalTravelTimeModel(),
78                  local, cache);
79      }
80  
81      /** Simple constructor.
82       * @param observer object that sends signal
83       * @param date date of the measurement
84       * @param phase observed value, in cycles
85       * @param wavelength phase observed value wavelength, in meters
86       * @param measurementQuality measurement quality data as used in orbit determination
87       * @param signalTravelTimeModel signal model
88       * @param local satellite which receives the signal and perform the measurement
89       * @param cache from which ambiguity drive should come
90       * @since 14.0
91       */
92      public OneWayGNSSPhase(final Observer observer, final AbsoluteDate date,
93                             final double phase, final double wavelength, final MeasurementQuality measurementQuality,
94                             final SignalTravelTimeModel signalTravelTimeModel, final ObservableSatellite local,
95                             final AmbiguityCache cache) {
96          // Call super constructor
97          super(observer, date, phase, measurementQuality, signalTravelTimeModel, local);
98  
99          // Initialize phase ambiguity driver
100         ambiguityDriver = cache.getAmbiguity(observer.getName(), local.getName(), wavelength);
101 
102         // Add ambiguity parameter to measurement
103         addParameterDriver(ambiguityDriver);
104 
105         // Initialise fields
106         this.wavelength = wavelength;
107     }
108 
109     /** Get the wavelength.
110      * @return wavelength (m)
111      */
112     public double getWavelength() {
113         return wavelength;
114     }
115 
116     /** Get the driver for phase ambiguity.
117      * @return the driver for phase ambiguity
118      */
119     public AmbiguityDriver getAmbiguityDriver() {
120         return ambiguityDriver;
121     }
122 
123     /** {@inheritDoc} */
124     @Override
125     protected EstimatedMeasurementBase<OneWayGNSSPhase> theoreticalEvaluationWithoutDerivatives(final int iteration,
126                                                                                                 final int evaluation,
127                                                                                                 final SpacecraftState[] states) {
128 
129         final CommonParametersWithoutDerivatives common =
130             computeLocalParametersWithout(states, getSatellites().getFirst(), getDate());
131 
132         // prepare the evaluation
133         final EstimatedMeasurementBase<OneWayGNSSPhase> estimatedPhase =
134                         new EstimatedMeasurementBase<>(this, iteration, evaluation,
135                                                        new SpacecraftState[] {
136                                                            common.getState()
137                                                        }, new TimeStampedPVCoordinates[] {
138                                                            common.getRemotePV(),
139                                                            common.getTransitPV()
140                                                        });
141 
142         // Phase value
143         final double   cOverLambda = Constants.SPEED_OF_LIGHT / wavelength;
144         final double   ambiguity   = ambiguityDriver.getValue(common.getState().getDate());
145         final double   phase       = (common.getTauD() + common.getLocalOffset().getBias() -
146                                       common.getRemoteOffset().getBias()) * cOverLambda + ambiguity;
147 
148         // Set value of the estimated measurement
149         estimatedPhase.setEstimatedValue(phase);
150 
151         // Return the estimated measurement
152         return estimatedPhase;
153 
154     }
155 
156     /** {@inheritDoc} */
157     @Override
158     protected EstimatedMeasurement<OneWayGNSSPhase> theoreticalEvaluation(final int iteration,
159                                                                           final int evaluation,
160                                                                           final SpacecraftState[] states) {
161 
162         final CommonParametersWithDerivatives common =
163             computeLocalParametersWith(states, getSatellites().getFirst(), getDate());
164 
165         // prepare the evaluation
166         final EstimatedMeasurement<OneWayGNSSPhase> estimatedPhase =
167                         new EstimatedMeasurement<>(this, iteration, evaluation,
168                                                    new SpacecraftState[] {
169                                                        common.getState()
170                                                    }, new TimeStampedPVCoordinates[] {
171                                                      common.getRemotePV().toTimeStampedPVCoordinates(),
172                                                      common.getTransitPV().toTimeStampedPVCoordinates()
173                                                    });
174 
175         // Phase value
176         final double   cOverLambda      = Constants.SPEED_OF_LIGHT / wavelength;
177         final Gradient ambiguity        = ambiguityDriver.getValue(common.getTauD().getFreeParameters(), common.getIndices(),
178                                                                    common.getState().getDate());
179         final Gradient phase            = common.getTauD().add(common.getLocalOffset().getBias()).
180                                           subtract(common.getRemoteOffset().getBias()).
181                                           multiply(cOverLambda).add(ambiguity);
182 
183         // Return the estimated measurement
184         fillDerivatives(phase, common.getIndices(), estimatedPhase);
185         return estimatedPhase;
186 
187     }
188 
189 }