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 }