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