1   /* Copyright 2022-2025 Luc Maisonobe
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.Collections;
20  
21  import org.hipparchus.analysis.differentiation.Gradient;
22  import org.orekit.estimation.measurements.ObservableSatellite;
23  import org.orekit.estimation.measurements.ObservedMeasurement;
24  import org.orekit.estimation.measurements.QuadraticClockModel;
25  import org.orekit.propagation.SpacecraftState;
26  import org.orekit.time.AbsoluteDate;
27  import org.orekit.utils.FieldPVCoordinatesProvider;
28  import org.orekit.utils.PVCoordinatesProvider;
29  import org.orekit.utils.TimeStampedFieldPVCoordinates;
30  import org.orekit.utils.TimeStampedPVCoordinates;
31  
32  /** Base class for one-way GNSS measurement.
33   * <p>
34   * This class can be used in precise orbit determination applications
35   * for modeling a range measurement between a GNSS satellite (emitter)
36   * and a LEO satellite (receiver).
37   * </p>
38   * <p>
39   * The one-way GNSS range measurement assumes knowledge of the orbit and
40   * the clock offset of the emitting GNSS satellite. For instance, it is
41   * possible to use a SP3 file or a GNSS navigation message to recover
42   * the satellite's orbit and clock.
43   * </p>
44   * <p>
45   * This class is very similar to {@link AbstractInterSatellitesMeasurement} measurement
46   * class. However, using the one-way GNSS range measurement, the orbit and clock
47   * of the emitting GNSS satellite are <b>NOT</b> estimated simultaneously with
48   * LEO satellite coordinates.
49   * </p>
50   *
51   * @param <T> type of the measurement
52   * @author Luc Maisonobe
53   * @since 12.1
54   */
55  public abstract class AbstractOneWayGNSSMeasurement<T extends ObservedMeasurement<T>>
56      extends AbstractOnBoardMeasurement<T> {
57  
58      /** Emitting satellite. */
59      private final PVCoordinatesProvider remotePV;
60  
61      /** Clock offset of the emitting satellite. */
62      private final QuadraticClockModel remoteClock;
63  
64      /** Simple constructor.
65       * @param remotePV provider for GNSS satellite which simply emits the signal
66       * @param remoteClock clock offset of the GNSS satellite
67       * @param date date of the measurement
68       * @param range observed value
69       * @param sigma theoretical standard deviation
70       * @param baseWeight base weight
71       * @param local satellite which receives the signal and perform the measurement
72       */
73      public AbstractOneWayGNSSMeasurement(final PVCoordinatesProvider remotePV,
74                                           final QuadraticClockModel remoteClock,
75                                           final AbsoluteDate date,
76                                           final double range, final double sigma,
77                                           final double baseWeight, final ObservableSatellite local) {
78          // Call super constructor
79          super(date, range, sigma, baseWeight, Collections.singletonList(local));
80  
81          // Initialise fields
82          this.remotePV    = remotePV;
83          this.remoteClock = remoteClock;
84      }
85  
86      /** {@inheritDoc} */
87      @Override
88      protected PVCoordinatesProvider getRemotePV(final SpacecraftState[] states) {
89          return remotePV;
90      }
91  
92      /** {@inheritDoc} */
93      @Override
94      protected QuadraticClockModel getRemoteClock() {
95          return remoteClock;
96      }
97  
98      /** {@inheritDoc} */
99      @Override
100     protected FieldPVCoordinatesProvider<Gradient> getRemotePV(final SpacecraftState[] states,
101                                                                final int freeParameters) {
102         // convert the PVCoordinatesProvider to a FieldPVCoordinatesProvider<Gradient>
103         return (date, frame) -> {
104 
105             // apply the raw (no derivatives) remote provider
106             final AbsoluteDate             dateBase = date.toAbsoluteDate();
107             final TimeStampedPVCoordinates pvBase   = remotePV.getPVCoordinates(dateBase, frame);
108             final TimeStampedFieldPVCoordinates<Gradient> pvWithoutDerivatives =
109                 new TimeStampedFieldPVCoordinates<>(date.getField(), pvBase);
110 
111             // add derivatives, using a trick: we shift the date by 0, with derivatives
112             final Gradient zeroWithDerivatives = date.durationFrom(dateBase);
113             return pvWithoutDerivatives.shiftedBy(zeroWithDerivatives);
114 
115         };
116     }
117 
118 }