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