1 /* Copyright 2002-2024 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.IdentityHashMap;
21 import java.util.Map;
22
23 import org.hipparchus.analysis.differentiation.Gradient;
24 import org.orekit.estimation.measurements.EstimatedMeasurement;
25 import org.orekit.estimation.measurements.EstimatedMeasurementBase;
26 import org.orekit.estimation.measurements.ObservableSatellite;
27 import org.orekit.estimation.measurements.QuadraticClockModel;
28 import org.orekit.propagation.SpacecraftState;
29 import org.orekit.time.AbsoluteDate;
30 import org.orekit.utils.Constants;
31 import org.orekit.utils.PVCoordinatesProvider;
32 import org.orekit.utils.ParameterDriver;
33 import org.orekit.utils.TimeSpanMap.Span;
34 import org.orekit.utils.TimeStampedPVCoordinates;
35
36 /** One-way GNSS phase measurement.
37 * <p>
38 * This class can be used in precise orbit determination applications
39 * for modeling a phase measurement between a GNSS satellite (emitter)
40 * and a LEO satellite (receiver).
41 * <p>
42 * The one-way GNSS phase measurement assumes knowledge of the orbit and
43 * the clock offset of the emitting GNSS satellite. For instance, it is
44 * possible to use a SP3 file or a GNSS navigation message to recover
45 * the satellite's orbit and clock.
46 * <p>
47 * This class is very similar to {@link InterSatellitesPhase} measurement
48 * class. However, using the one-way GNSS phase measurement, the orbit and clock
49 * of the emitting GNSS satellite are <b>NOT</b> estimated simultaneously with
50 * LEO satellite coordinates.
51 *
52 * @author Bryan Cazabonne
53 * @since 10.3
54 */
55 public class OneWayGNSSPhase extends AbstractOneWayGNSSMeasurement<OneWayGNSSPhase> {
56
57 /** Type of the measurement. */
58 public static final String MEASUREMENT_TYPE = "OneWayGNSSPhase";
59
60 /** Name for ambiguity driver.
61 * @deprecated as of 12.1 not used anymore
62 */
63 @Deprecated
64 public static final String AMBIGUITY_NAME = "ambiguity";
65
66 /** Temporary map to build remote provider names.
67 * @since 12.1
68 * @deprecated this map is only a temporary hack for compatibility purposes
69 * it will be removed in Orekit 13.0
70 */
71 @Deprecated
72 private static final Map<PVCoordinatesProvider, String> REMOTE_NAMES = new IdentityHashMap<>();
73
74 /** Driver for ambiguity. */
75 private final AmbiguityDriver ambiguityDriver;
76
77 /** Wavelength of the phase observed value [m]. */
78 private final double wavelength;
79
80 /** Simple constructor.
81 * @param remote provider for GNSS satellite which simply emits the signal
82 * @param dtRemote clock offset of the GNSS satellite, in seconds
83 * @param date date of the measurement
84 * @param phase observed value, in cycles
85 * @param wavelength phase observed value wavelength, in meters
86 * @param sigma theoretical standard deviation
87 * @param baseWeight base weight
88 * @param local satellite which receives the signal and perform the measurement
89 * @deprecated as of 12.1, replaced by {@link #OneWayGNSSPhase(PVCoordinatesProvider,
90 * String, QuadraticClockModel, AbsoluteDate, double, double, double, double,
91 * ObservableSatellite, AmbiguityCache)}
92 */
93 @Deprecated
94 public OneWayGNSSPhase(final PVCoordinatesProvider remote,
95 final double dtRemote,
96 final AbsoluteDate date,
97 final double phase, final double wavelength, final double sigma,
98 final double baseWeight, final ObservableSatellite local) {
99 this(remote,
100 REMOTE_NAMES.computeIfAbsent(remote, r -> "remote-" + REMOTE_NAMES.size()),
101 new QuadraticClockModel(date, dtRemote, 0.0, 0.0),
102 date, phase, wavelength, sigma, baseWeight, local,
103 AmbiguityCache.DEFAULT_CACHE);
104 }
105
106 /** Simple constructor.
107 * @param remote provider for GNSS satellite which simply emits the signal
108 * @param remoteName name of the remote
109 * @param remoteClock clock offset of the GNSS satellite
110 * @param date date of the measurement
111 * @param phase observed value, in cycles
112 * @param wavelength phase observed value wavelength, in meters
113 * @param sigma theoretical standard deviation
114 * @param baseWeight base weight
115 * @param local satellite which receives the signal and perform the measurement
116 * @param cache from which ambiguity drive should come
117 * @since 12.1
118 */
119 public OneWayGNSSPhase(final PVCoordinatesProvider remote,
120 final String remoteName,
121 final QuadraticClockModel remoteClock,
122 final AbsoluteDate date,
123 final double phase, final double wavelength, final double sigma,
124 final double baseWeight, final ObservableSatellite local,
125 final AmbiguityCache cache) {
126 // Call super constructor
127 super(remote, remoteClock, date, phase, sigma, baseWeight, local);
128
129 // Initialize phase ambiguity driver
130 ambiguityDriver = cache.getAmbiguity(remoteName, local.getName(), wavelength);
131
132 // The local satellite clock offset affects the measurement
133 addParameterDriver(ambiguityDriver);
134 addParameterDriver(local.getClockOffsetDriver());
135
136 // Initialise fields
137 this.wavelength = wavelength;
138 }
139
140 /** Get the wavelength.
141 * @return wavelength (m)
142 */
143 public double getWavelength() {
144 return wavelength;
145 }
146
147 /** Get the driver for phase ambiguity.
148 * @return the driver for phase ambiguity
149 */
150 public AmbiguityDriver getAmbiguityDriver() {
151 return ambiguityDriver;
152 }
153
154 /** {@inheritDoc} */
155 @Override
156 protected EstimatedMeasurementBase<OneWayGNSSPhase> theoreticalEvaluationWithoutDerivatives(final int iteration,
157 final int evaluation,
158 final SpacecraftState[] states) {
159
160 final OnBoardCommonParametersWithoutDerivatives common = computeCommonParametersWithout(states, false);
161
162 // prepare the evaluation
163 final EstimatedMeasurementBase<OneWayGNSSPhase> estimatedPhase =
164 new EstimatedMeasurementBase<>(this, iteration, evaluation,
165 new SpacecraftState[] {
166 common.getState()
167 }, new TimeStampedPVCoordinates[] {
168 common.getRemotePV(),
169 common.getTransitPV()
170 });
171
172 // Phase value
173 final double cOverLambda = Constants.SPEED_OF_LIGHT / wavelength;
174 final double ambiguity = ambiguityDriver.getValue(common.getState().getDate());
175 final double phase = (common.getTauD() + common.getLocalOffset() - common.getRemoteOffset()) * cOverLambda +
176 ambiguity;
177
178 // Set value of the estimated measurement
179 estimatedPhase.setEstimatedValue(phase);
180
181 // Return the estimated measurement
182 return estimatedPhase;
183
184 }
185
186 /** {@inheritDoc} */
187 @Override
188 protected EstimatedMeasurement<OneWayGNSSPhase> theoreticalEvaluation(final int iteration,
189 final int evaluation,
190 final SpacecraftState[] states) {
191
192 final OnBoardCommonParametersWithDerivatives common = computeCommonParametersWith(states, false);
193
194 // prepare the evaluation
195 final EstimatedMeasurement<OneWayGNSSPhase> estimatedPhase =
196 new EstimatedMeasurement<>(this, iteration, evaluation,
197 new SpacecraftState[] {
198 common.getState()
199 }, new TimeStampedPVCoordinates[] {
200 common.getRemotePV().toTimeStampedPVCoordinates(),
201 common.getTransitPV().toTimeStampedPVCoordinates()
202 });
203
204 // Phase value
205 final double cOverLambda = Constants.SPEED_OF_LIGHT / wavelength;
206 final Gradient ambiguity = ambiguityDriver.getValue(common.getTauD().getFreeParameters(), common.getIndices(),
207 common.getState().getDate());
208 final Gradient phase = common.getTauD().add(common.getLocalOffset()).subtract(common.getRemoteOffset()).
209 multiply(cOverLambda).
210 add(ambiguity);
211 final double[] phaseDerivatives = phase.getGradient();
212
213 // Set value and state first order derivatives of the estimated measurement
214 estimatedPhase.setEstimatedValue(phase.getValue());
215 estimatedPhase.setStateDerivatives(0, Arrays.copyOfRange(phaseDerivatives, 0, 6));
216
217 // Set first order derivatives with respect to parameters
218 for (final ParameterDriver phaseMeasurementDriver : getParametersDrivers()) {
219 for (Span<String> span = phaseMeasurementDriver.getNamesSpanMap().getFirstSpan(); span != null; span = span.next()) {
220
221 final Integer index = common.getIndices().get(span.getData());
222 if (index != null) {
223 estimatedPhase.setParameterDerivatives(phaseMeasurementDriver, span.getStart(), phaseDerivatives[index]);
224 }
225 }
226 }
227
228 // Return the estimated measurement
229 return estimatedPhase;
230
231 }
232
233 }