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 }