1   /* Copyright 2002-2021 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  import java.util.HashMap;
21  import java.util.Map;
22  
23  import org.hipparchus.analysis.differentiation.Gradient;
24  import org.orekit.estimation.measurements.AbstractMeasurement;
25  import org.orekit.estimation.measurements.EstimatedMeasurement;
26  import org.orekit.estimation.measurements.ObservableSatellite;
27  import org.orekit.propagation.SpacecraftState;
28  import org.orekit.time.AbsoluteDate;
29  import org.orekit.time.FieldAbsoluteDate;
30  import org.orekit.utils.Constants;
31  import org.orekit.utils.ParameterDriver;
32  import org.orekit.utils.TimeStampedFieldPVCoordinates;
33  import org.orekit.utils.TimeStampedPVCoordinates;
34  
35  /** Phase measurement between two satellites.
36   * <p>
37   * The measurement is considered to be a signal emitted from
38   * a remote satellite and received by a local satellite.
39   * Its value is the number of cycles between emission and reception.
40   * The motion of both spacecrafts during the signal flight time
41   * are taken into account. The date of the measurement corresponds to the
42   * reception on ground of the emitted signal.
43   * </p>
44   * @author Bryan Cazabonne
45   * @since 10.3
46   */
47  public class InterSatellitesPhase extends AbstractMeasurement<InterSatellitesPhase> {
48  
49      /** Name for ambiguity driver. */
50      public static final String AMBIGUITY_NAME = "ambiguity";
51  
52      /** Driver for ambiguity. */
53      private final ParameterDriver ambiguityDriver;
54  
55      /** Wavelength of the phase observed value [m]. */
56      private final double wavelength;
57  
58      /** Constructor.
59       * @param local satellite which receives the signal and performs the measurement
60       * @param remote emote satellite which simply emits the signal
61       * @param date date of the measurement
62       * @param phase observed value (cycles)
63       * @param wavelength phase observed value wavelength (m)
64       * @param sigma theoretical standard deviation
65       * @param baseWeight base weight
66       */
67      public InterSatellitesPhase(final ObservableSatellite local,
68                                  final ObservableSatellite remote,
69                                  final AbsoluteDate date, final double phase,
70                                  final double wavelength, final double sigma,
71                                  final double baseWeight) {
72          // Call to super constructor
73          super(date, phase, sigma, baseWeight, Arrays.asList(local, remote));
74  
75          // Initialize phase ambiguity driver
76          ambiguityDriver = new ParameterDriver(AMBIGUITY_NAME, 0.0, 1.0,
77                                                Double.NEGATIVE_INFINITY, Double.POSITIVE_INFINITY);
78  
79          // Add parameter drivers
80          addParameterDriver(ambiguityDriver);
81          addParameterDriver(local.getClockOffsetDriver());
82          addParameterDriver(remote.getClockOffsetDriver());
83  
84          // Initialize fields
85          this.wavelength = wavelength;
86      }
87  
88      /** Get the wavelength.
89       * @return wavelength (m)
90       */
91      public double getWavelength() {
92          return wavelength;
93      }
94  
95      /** Get the driver for phase ambiguity.
96       * @return the driver for phase ambiguity
97       */
98      public ParameterDriver getAmbiguityDriver() {
99          return ambiguityDriver;
100     }
101 
102     /** {@inheritDoc} */
103     @Override
104     protected EstimatedMeasurement<InterSatellitesPhase> theoreticalEvaluation(final int iteration,
105                                                                                final int evaluation,
106                                                                                final SpacecraftState[] states) {
107 
108         // Phase derivatives are computed with respect to spacecrafts states in inertial frame
109         // ----------------------
110         //
111         // Parameters:
112         //  - 0..2  - Position of the receiver satellite in inertial frame
113         //  - 3..5  - Velocity of the receiver satellite in inertial frame
114         //  - 6..8  - Position of the remote satellite in inertial frame
115         //  - 9..11 - Velocity of the remote satellite in inertial frame
116         //  - 12..  - Measurement parameters: ambiguity, local clock offset, remote clock offset...
117         int nbParams = 12;
118         final Map<String, Integer> indices = new HashMap<>();
119         for (ParameterDriver phaseMeasurementDriver : getParametersDrivers()) {
120             if (phaseMeasurementDriver.isSelected()) {
121                 indices.put(phaseMeasurementDriver.getName(), nbParams++);
122             }
123         }
124 
125         // Coordinates of both satellites
126         final SpacecraftState local = states[0];
127         final TimeStampedFieldPVCoordinates<Gradient> pvaL = getCoordinates(local, 0, nbParams);
128         final SpacecraftState remote = states[1];
129         final TimeStampedFieldPVCoordinates<Gradient> pvaR = getCoordinates(remote, 6, nbParams);
130 
131         // Compute propagation times
132         // Downlink delay
133         final Gradient dtl = getSatellites().get(0).getClockOffsetDriver().getValue(nbParams, indices);
134         final FieldAbsoluteDate<Gradient> arrivalDate = new FieldAbsoluteDate<>(getDate(), dtl.negate());
135 
136         final TimeStampedFieldPVCoordinates<Gradient> s1Downlink =
137                         pvaL.shiftedBy(arrivalDate.durationFrom(pvaL.getDate()));
138         final Gradient tauD = signalTimeOfFlight(pvaR, s1Downlink.getPosition(), arrivalDate);
139 
140         // Transit state
141         final double   delta      = getDate().durationFrom(remote.getDate());
142         final Gradient deltaMTauD = tauD.negate().add(delta);
143 
144         // prepare the evaluation
145         final EstimatedMeasurement<InterSatellitesPhase> estimatedPhase =
146                         new EstimatedMeasurement<>(this, iteration, evaluation,
147                                                    new SpacecraftState[] {
148                                                        local.shiftedBy(deltaMTauD.getValue()),
149                                                        remote.shiftedBy(deltaMTauD.getValue())
150                                                    }, new TimeStampedPVCoordinates[] {
151                                                        remote.shiftedBy(delta - tauD.getValue()).getPVCoordinates(),
152                                                        local.shiftedBy(delta).getPVCoordinates()
153                                                    });
154 
155         // Clock offsets
156         final Gradient dtr = getSatellites().get(1).getClockOffsetDriver().getValue(nbParams, indices);
157 
158         // Phase value
159         final double   cOverLambda = Constants.SPEED_OF_LIGHT / wavelength;
160         final Gradient ambiguity   = ambiguityDriver.getValue(nbParams, indices);
161         final Gradient phase       = tauD.add(dtl).subtract(dtr).multiply(cOverLambda).add(ambiguity);
162 
163         estimatedPhase.setEstimatedValue(phase.getValue());
164 
165         // Range partial derivatives with respect to states
166         final double[] derivatives = phase.getGradient();
167         estimatedPhase.setStateDerivatives(0, Arrays.copyOfRange(derivatives, 0,  6));
168         estimatedPhase.setStateDerivatives(1, Arrays.copyOfRange(derivatives, 6, 12));
169 
170         // Set partial derivatives with respect to parameters
171         for (final ParameterDriver driver : getParametersDrivers()) {
172             final Integer index = indices.get(driver.getName());
173             if (index != null) {
174                 estimatedPhase.setParameterDerivatives(driver, derivatives[index]);
175             }
176         }
177 
178         // Return the estimated measurement
179         return estimatedPhase;
180 
181     }
182 
183 }