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 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.MeasurementQuality;
25  import org.orekit.estimation.measurements.ObservableSatellite;
26  import org.orekit.propagation.SpacecraftState;
27  import org.orekit.signal.SignalTravelTimeModel;
28  import org.orekit.time.AbsoluteDate;
29  import org.orekit.utils.Constants;
30  import org.orekit.utils.drivers.ParameterDriver;
31  import org.orekit.utils.TimeStampedPVCoordinates;
32  
33  /** Phase measurement between two satellites.
34   * <p>
35   * The measurement is considered to be a signal emitted from
36   * a remote satellite and received by a local satellite.
37   * Its value is the number of cycles between emission and reception.
38   * The motion of both spacecraft during the signal flight time
39   * are taken into account. The date of the measurement corresponds to the
40   * reception on ground of the emitted signal.
41   * </p>
42   * @author Bryan Cazabonne
43   * @since 10.3
44   */
45  public class InterSatellitesPhase extends AbstractInterSatellitesMeasurement<InterSatellitesPhase> {
46  
47      /** Type of the measurement. */
48      public static final String MEASUREMENT_TYPE = "InterSatellitesPhase";
49  
50      /** Driver for ambiguity. */
51      private final AmbiguityDriver ambiguityDriver;
52  
53      /** Wavelength of the phase observed value [m]. */
54      private final double wavelength;
55  
56      /** Constructor with default signal travel time model.
57       * @param local satellite which receives the signal and performs the measurement
58       * @param remote remote satellite which simply emits the signal
59       * @param date date of the measurement
60       * @param phase observed value (cycles)
61       * @param wavelength phase observed value wavelength (m)
62       * @param sigma theoretical standard deviation
63       * @param baseWeight base weight
64       * @param cache from which ambiguity drive should come
65       * @since 12.1
66       */
67      public InterSatellitesPhase(final ObservableSatellite local, final ObservableSatellite remote,
68                                  final AbsoluteDate date, final double phase,
69                                  final double wavelength, final double sigma, final double baseWeight,
70                                  final AmbiguityCache cache) {
71          this(local, remote, date, phase, wavelength, new MeasurementQuality(sigma, baseWeight),
72                  new SignalTravelTimeModel(), cache);
73      }
74  
75      /** Constructor.
76       * @param local satellite which receives the signal and performs the measurement
77       * @param remote remote satellite which simply emits the signal
78       * @param date date of the measurement
79       * @param phase observed value (cycles)
80       * @param wavelength phase observed value wavelength (m)
81       * @param measurementQuality measurement quality data as used in orbit determination
82       * @param signalTravelTimeModel signal model
83       * @param cache from which ambiguity drive should come
84       * @since 14.0
85       */
86      public InterSatellitesPhase(final ObservableSatellite local, final ObservableSatellite remote,
87                                  final AbsoluteDate date, final double phase, final double wavelength,
88                                  final MeasurementQuality measurementQuality,
89                                  final SignalTravelTimeModel signalTravelTimeModel, final AmbiguityCache cache) {
90          // Call to super constructor
91          super(date, phase, measurementQuality, signalTravelTimeModel, local, remote);
92  
93          // Initialize phase ambiguity driver
94          this.ambiguityDriver = cache.getAmbiguity(remote.getName(), local.getName(), wavelength);
95  
96          // Add parameter drivers
97          addParameterDriver(ambiguityDriver);
98  
99          // Initialize fields
100         this.wavelength = wavelength;
101     }
102 
103     /** Get the wavelength.
104      * @return wavelength (m)
105      */
106     public double getWavelength() {
107         return wavelength;
108     }
109 
110     /** Get the driver for phase ambiguity.
111      * @return the driver for phase ambiguity
112      */
113     public ParameterDriver getAmbiguityDriver() {
114         return ambiguityDriver;
115     }
116 
117     /** {@inheritDoc} */
118     @Override
119     protected EstimatedMeasurementBase<InterSatellitesPhase> theoreticalEvaluationWithoutDerivatives(final int iteration,
120                                                                                                      final int evaluation,
121                                                                                                      final SpacecraftState[] states,
122                                                                                                      final boolean fillParticipants) {
123 
124         final CommonParametersWithoutDerivatives common = computeCommonParametersWithout(states);
125 
126         // prepare the evaluation
127         final EstimatedMeasurementBase<InterSatellitesPhase> estimatedPhase =
128                         new EstimatedMeasurementBase<>(this, iteration, evaluation,
129                                                        new SpacecraftState[] {
130                                                            common.getState(),
131                                                            states[1]
132                                                        }, fillParticipants ? new TimeStampedPVCoordinates[] {
133                                                            common.getRemotePV(), common.getTransitPV()
134                                                        } : new TimeStampedPVCoordinates[0]);
135 
136         // Phase value
137         final double cOverLambda = Constants.SPEED_OF_LIGHT / wavelength;
138         final double ambiguity   = ambiguityDriver.getValue();
139         final double phase       = (common.getTauD() + common.getLocalOffset().getBias() -
140                                     common.getRemoteOffset().getBias()) * cOverLambda +
141                                    ambiguity;
142 
143         estimatedPhase.setEstimatedValue(phase);
144 
145         // Return the estimated measurement
146         return estimatedPhase;
147 
148     }
149 
150     /** {@inheritDoc} */
151     @Override
152     protected EstimatedMeasurement<InterSatellitesPhase> theoreticalEvaluation(final int iteration,
153                                                                                final int evaluation,
154                                                                                final SpacecraftState[] states) {
155 
156         final CommonParametersWithDerivatives common = computeCommonParametersWith(states);
157 
158        // prepare the evaluation
159         final EstimatedMeasurement<InterSatellitesPhase> estimatedPhase =
160                         new EstimatedMeasurement<>(this, iteration, evaluation,
161                                                    new SpacecraftState[] {
162                                                        common.getState(),
163                                                        states[1]
164                                                    }, new TimeStampedPVCoordinates[] {
165                                                        common.getRemotePV().toTimeStampedPVCoordinates(),
166                                                        common.getTransitPV().toTimeStampedPVCoordinates()
167                                                    });
168 
169         // Phase value
170         final double   cOverLambda = Constants.SPEED_OF_LIGHT / wavelength;
171         final Gradient ambiguity   = ambiguityDriver.getValue(common.getTauD().getFreeParameters(),
172                                                               common.getIndices());
173         final Gradient phase       = common.getTauD().
174                                      add(common.getLocalOffset().getBias()).
175                                      subtract(common.getRemoteOffset().getBias()).
176                                      multiply(cOverLambda).
177                                      add(ambiguity);
178 
179         estimatedPhase.setEstimatedValue(phase.getValue());
180 
181         // Range first order derivatives with respect to states
182         final double[] derivatives = phase.getGradient();
183         estimatedPhase.setStateDerivatives(0, Arrays.copyOfRange(derivatives, 0,  6));
184         estimatedPhase.setStateDerivatives(1, Arrays.copyOfRange(derivatives, 6, 12));
185 
186         // Set first order derivatives with respect to parameters
187         for (final ParameterDriver driver : getParametersDrivers()) {
188             final Integer index = common.getIndices().get(driver.getName());
189             if (index != null) {
190                 estimatedPhase.setParameterDerivatives(driver, derivatives[index]);
191             }
192         }
193 
194         // Return the estimated measurement
195         return estimatedPhase;
196 
197     }
198 
199 }