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.InterSatellitesRange;
25  import org.orekit.estimation.measurements.ObservableSatellite;
26  import org.orekit.estimation.measurements.QuadraticClockModel;
27  import org.orekit.propagation.SpacecraftState;
28  import org.orekit.time.AbsoluteDate;
29  import org.orekit.utils.Constants;
30  import org.orekit.utils.PVCoordinatesProvider;
31  import org.orekit.utils.ParameterDriver;
32  import org.orekit.utils.TimeSpanMap.Span;
33  import org.orekit.utils.TimeStampedPVCoordinates;
34  
35  /** One-way GNSS range measurement.
36   * <p>
37   * This class can be used in precise orbit determination applications
38   * for modeling a range measurement between a GNSS satellite (emitter)
39   * and a LEO satellite (receiver).
40   * <p>
41   * The one-way GNSS range measurement assumes knowledge of the orbit and
42   * the clock offset of the emitting GNSS satellite. For instance, it is
43   * possible to use a SP3 file or a GNSS navigation message to recover
44   * the satellite's orbit and clock.
45   * <p>
46   * This class is very similar to {@link InterSatellitesRange} measurement
47   * class. However, using the one-way GNSS range measurement, the orbit and clock
48   * of the emitting GNSS satellite are <b>NOT</b> estimated simultaneously with
49   * LEO satellite coordinates.
50   *
51   * @author Bryan Cazabonne
52   * @since 10.3
53   */
54  public class OneWayGNSSRange extends AbstractOneWayGNSSMeasurement<OneWayGNSSRange> {
55  
56      /** Type of the measurement. */
57      public static final String MEASUREMENT_TYPE = "OneWayGNSSRange";
58  
59      /** Simple constructor.
60       * @param remote provider for GNSS satellite which simply emits the signal
61       * @param dtRemote clock offset of the GNSS satellite, in seconds
62       * @param date date of the measurement
63       * @param range observed value
64       * @param sigma theoretical standard deviation
65       * @param baseWeight base weight
66       * @param local satellite which receives the signal and perform the measurement
67       */
68      public OneWayGNSSRange(final PVCoordinatesProvider remote,
69                             final double dtRemote,
70                             final AbsoluteDate date,
71                             final double range, final double sigma,
72                             final double baseWeight, final ObservableSatellite local) {
73          this(remote, new QuadraticClockModel(date, dtRemote, 0.0, 0.0), date, range, sigma, baseWeight, local);
74      }
75  
76      /** Simple constructor.
77       * @param remote provider for GNSS satellite which simply emits the signal
78       * @param remoteClock clock offset of the GNSS satellite
79       * @param date date of the measurement
80       * @param range observed value
81       * @param sigma theoretical standard deviation
82       * @param baseWeight base weight
83       * @param local satellite which receives the signal and perform the measurement
84       * @since 12.1
85       */
86      public OneWayGNSSRange(final PVCoordinatesProvider remote,
87                             final QuadraticClockModel remoteClock,
88                             final AbsoluteDate date,
89                             final double range, final double sigma,
90                             final double baseWeight, final ObservableSatellite local) {
91          // Call super constructor
92          super(remote, remoteClock, date, range, sigma, baseWeight, local);
93      }
94  
95      /** {@inheritDoc} */
96      @Override
97      protected EstimatedMeasurementBase<OneWayGNSSRange> theoreticalEvaluationWithoutDerivatives(final int iteration,
98                                                                                                  final int evaluation,
99                                                                                                  final SpacecraftState[] states) {
100 
101 
102         final OnBoardCommonParametersWithoutDerivatives common = computeCommonParametersWithout(states, false);
103 
104         // Estimated measurement
105         final EstimatedMeasurementBase<OneWayGNSSRange> estimatedRange =
106                         new EstimatedMeasurementBase<>(this, iteration, evaluation,
107                                                        new SpacecraftState[] {
108                                                            common.getState()
109                                                        }, new TimeStampedPVCoordinates[] {
110                                                            common.getRemotePV(),
111                                                            common.getTransitPV()
112                                                        });
113 
114         // Range value
115         final double range = (common.getTauD() + common.getLocalOffset() - common.getRemoteOffset()) *
116                              Constants.SPEED_OF_LIGHT;
117 
118         // Set value of the estimated measurement
119         estimatedRange.setEstimatedValue(range);
120 
121         // Return the estimated measurement
122         return estimatedRange;
123 
124     }
125 
126     /** {@inheritDoc} */
127     @Override
128     protected EstimatedMeasurement<OneWayGNSSRange> theoreticalEvaluation(final int iteration,
129                                                                           final int evaluation,
130                                                                           final SpacecraftState[] states) {
131 
132         final OnBoardCommonParametersWithDerivatives common = computeCommonParametersWith(states, false);
133 
134         // Estimated measurement
135         final EstimatedMeasurement<OneWayGNSSRange> estimatedRange =
136                         new EstimatedMeasurement<>(this, iteration, evaluation,
137                                                    new SpacecraftState[] {
138                                                        common.getState()
139                                                    }, new TimeStampedPVCoordinates[] {
140                                                        common.getRemotePV().toTimeStampedPVCoordinates(),
141                                                        common.getTransitPV().toTimeStampedPVCoordinates()
142                                                    });
143 
144         // Range value
145         final Gradient range            = common.getTauD().add(common.getLocalOffset()).subtract(common.getRemoteOffset()).
146                                           multiply(Constants.SPEED_OF_LIGHT);
147         final double[] rangeDerivatives = range.getGradient();
148 
149         // Set value and state first order derivatives of the estimated measurement
150         estimatedRange.setEstimatedValue(range.getValue());
151         estimatedRange.setStateDerivatives(0, Arrays.copyOfRange(rangeDerivatives, 0,  6));
152 
153         // Set first order derivatives with respect to parameters
154         for (final ParameterDriver measurementDriver : getParametersDrivers()) {
155             for (Span<String> span = measurementDriver.getNamesSpanMap().getFirstSpan(); span != null; span = span.next()) {
156 
157                 final Integer index = common.getIndices().get(span.getData());
158                 if (index != null) {
159                     estimatedRange.setParameterDerivatives(measurementDriver, span.getStart(), rangeDerivatives[index]);
160                 }
161             }
162         }
163 
164         // Return the estimated measurement
165         return estimatedRange;
166 
167     }
168 
169 }