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