OneWayGNSSPhase.java

  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. import java.util.Arrays;
  19. import java.util.IdentityHashMap;
  20. import java.util.Map;

  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.estimation.measurements.QuadraticClockModel;
  26. import org.orekit.propagation.SpacecraftState;
  27. import org.orekit.time.AbsoluteDate;
  28. import org.orekit.utils.Constants;
  29. import org.orekit.utils.PVCoordinatesProvider;
  30. import org.orekit.utils.ParameterDriver;
  31. import org.orekit.utils.TimeSpanMap.Span;
  32. import org.orekit.utils.TimeStampedPVCoordinates;

  33. /** One-way GNSS phase measurement.
  34.  * <p>
  35.  * This class can be used in precise orbit determination applications
  36.  * for modeling a phase measurement between a GNSS satellite (emitter)
  37.  * and a LEO satellite (receiver).
  38.  * <p>
  39.  * The one-way GNSS phase 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.  * This class is very similar to {@link InterSatellitesPhase} measurement
  45.  * class. However, using the one-way GNSS phase measurement, the orbit and clock
  46.  * of the emitting GNSS satellite are <b>NOT</b> estimated simultaneously with
  47.  * LEO satellite coordinates.
  48.  *
  49.  * @author Bryan Cazabonne
  50.  * @since 10.3
  51.  */
  52. public class OneWayGNSSPhase extends AbstractOneWayGNSSMeasurement<OneWayGNSSPhase> {

  53.     /** Type of the measurement. */
  54.     public static final String MEASUREMENT_TYPE = "OneWayGNSSPhase";

  55.     /** Name for ambiguity driver.
  56.      * @deprecated as of 12.1 not used anymore
  57.      */
  58.     @Deprecated
  59.     public static final String AMBIGUITY_NAME = "ambiguity";

  60.     /** Temporary map to build remote provider names.
  61.      * @since 12.1
  62.      * @deprecated this map is only a temporary hack for compatibility purposes
  63.      * it will be removed in Orekit 13.0
  64.      */
  65.     @Deprecated
  66.     private static final Map<PVCoordinatesProvider, String> REMOTE_NAMES = new IdentityHashMap<>();

  67.     /** Driver for ambiguity. */
  68.     private final AmbiguityDriver ambiguityDriver;

  69.     /** Wavelength of the phase observed value [m]. */
  70.     private final double wavelength;

  71.     /** Simple constructor.
  72.      * @param remote provider for GNSS satellite which simply emits the signal
  73.      * @param dtRemote clock offset of the GNSS satellite, in seconds
  74.      * @param date date of the measurement
  75.      * @param phase observed value, in cycles
  76.      * @param wavelength phase observed value wavelength, in meters
  77.      * @param sigma theoretical standard deviation
  78.      * @param baseWeight base weight
  79.      * @param local satellite which receives the signal and perform the measurement
  80.      * @deprecated as of 12.1, replaced by {@link #OneWayGNSSPhase(PVCoordinatesProvider,
  81.      * String, QuadraticClockModel, AbsoluteDate, double, double, double, double,
  82.      * ObservableSatellite, AmbiguityCache)}
  83.      */
  84.     @Deprecated
  85.     public OneWayGNSSPhase(final PVCoordinatesProvider remote,
  86.                            final double dtRemote,
  87.                            final AbsoluteDate date,
  88.                            final double phase, final double wavelength, final double sigma,
  89.                            final double baseWeight, final ObservableSatellite local) {
  90.         this(remote,
  91.              REMOTE_NAMES.computeIfAbsent(remote, r -> "remote-" + REMOTE_NAMES.size()),
  92.              new QuadraticClockModel(date, dtRemote, 0.0, 0.0),
  93.              date, phase, wavelength, sigma, baseWeight, local,
  94.              AmbiguityCache.DEFAULT_CACHE);
  95.     }

  96.     /** Simple constructor.
  97.      * @param remote provider for GNSS satellite which simply emits the signal
  98.      * @param remoteName name of the remote
  99.      * @param remoteClock clock offset of the GNSS satellite
  100.      * @param date date of the measurement
  101.      * @param phase observed value, in cycles
  102.      * @param wavelength phase observed value wavelength, in meters
  103.      * @param sigma theoretical standard deviation
  104.      * @param baseWeight base weight
  105.      * @param local satellite which receives the signal and perform the measurement
  106.      * @param cache from which ambiguity drive should come
  107.      * @since 12.1
  108.      */
  109.     public OneWayGNSSPhase(final PVCoordinatesProvider remote,
  110.                            final String remoteName,
  111.                            final QuadraticClockModel remoteClock,
  112.                            final AbsoluteDate date,
  113.                            final double phase, final double wavelength, final double sigma,
  114.                            final double baseWeight, final ObservableSatellite local,
  115.                            final AmbiguityCache cache) {
  116.         // Call super constructor
  117.         super(remote, remoteClock, date, phase, sigma, baseWeight, local);

  118.         // Initialize phase ambiguity driver
  119.         ambiguityDriver = cache.getAmbiguity(remoteName, local.getName(), wavelength);

  120.         // The local satellite clock offset affects the measurement
  121.         addParameterDriver(ambiguityDriver);
  122.         addParameterDriver(local.getClockOffsetDriver());

  123.         // Initialise fields
  124.         this.wavelength = wavelength;
  125.     }

  126.     /** Get the wavelength.
  127.      * @return wavelength (m)
  128.      */
  129.     public double getWavelength() {
  130.         return wavelength;
  131.     }

  132.     /** Get the driver for phase ambiguity.
  133.      * @return the driver for phase ambiguity
  134.      */
  135.     public AmbiguityDriver getAmbiguityDriver() {
  136.         return ambiguityDriver;
  137.     }

  138.     /** {@inheritDoc} */
  139.     @Override
  140.     protected EstimatedMeasurementBase<OneWayGNSSPhase> theoreticalEvaluationWithoutDerivatives(final int iteration,
  141.                                                                                                 final int evaluation,
  142.                                                                                                 final SpacecraftState[] states) {

  143.         final OnBoardCommonParametersWithoutDerivatives common = computeCommonParametersWithout(states, false);

  144.         // prepare the evaluation
  145.         final EstimatedMeasurementBase<OneWayGNSSPhase> estimatedPhase =
  146.                         new EstimatedMeasurementBase<>(this, iteration, evaluation,
  147.                                                        new SpacecraftState[] {
  148.                                                            common.getState()
  149.                                                        }, new TimeStampedPVCoordinates[] {
  150.                                                            common.getRemotePV(),
  151.                                                            common.getTransitPV()
  152.                                                        });

  153.         // Phase value
  154.         final double   cOverLambda = Constants.SPEED_OF_LIGHT / wavelength;
  155.         final double   ambiguity   = ambiguityDriver.getValue(common.getState().getDate());
  156.         final double   phase       = (common.getTauD() + common.getLocalOffset() - common.getRemoteOffset()) * cOverLambda +
  157.                                      ambiguity;

  158.         // Set value of the estimated measurement
  159.         estimatedPhase.setEstimatedValue(phase);

  160.         // Return the estimated measurement
  161.         return estimatedPhase;

  162.     }

  163.     /** {@inheritDoc} */
  164.     @Override
  165.     protected EstimatedMeasurement<OneWayGNSSPhase> theoreticalEvaluation(final int iteration,
  166.                                                                           final int evaluation,
  167.                                                                           final SpacecraftState[] states) {

  168.         final OnBoardCommonParametersWithDerivatives common = computeCommonParametersWith(states, false);

  169.         // prepare the evaluation
  170.         final EstimatedMeasurement<OneWayGNSSPhase> estimatedPhase =
  171.                         new EstimatedMeasurement<>(this, iteration, evaluation,
  172.                                                    new SpacecraftState[] {
  173.                                                        common.getState()
  174.                                                    }, new TimeStampedPVCoordinates[] {
  175.                                                      common.getRemotePV().toTimeStampedPVCoordinates(),
  176.                                                      common.getTransitPV().toTimeStampedPVCoordinates()
  177.                                                    });

  178.         // Phase value
  179.         final double   cOverLambda      = Constants.SPEED_OF_LIGHT / wavelength;
  180.         final Gradient ambiguity        = ambiguityDriver.getValue(common.getTauD().getFreeParameters(), common.getIndices(),
  181.                                                                    common.getState().getDate());
  182.         final Gradient phase            = common.getTauD().add(common.getLocalOffset()).subtract(common.getRemoteOffset()).
  183.                                           multiply(cOverLambda).
  184.                                           add(ambiguity);
  185.         final double[] phaseDerivatives = phase.getGradient();

  186.         // Set value and state first order derivatives of the estimated measurement
  187.         estimatedPhase.setEstimatedValue(phase.getValue());
  188.         estimatedPhase.setStateDerivatives(0, Arrays.copyOfRange(phaseDerivatives, 0,  6));

  189.         // Set first order derivatives with respect to parameters
  190.         for (final ParameterDriver phaseMeasurementDriver : getParametersDrivers()) {
  191.             for (Span<String> span = phaseMeasurementDriver.getNamesSpanMap().getFirstSpan(); span != null; span = span.next()) {

  192.                 final Integer index = common.getIndices().get(span.getData());
  193.                 if (index != null) {
  194.                     estimatedPhase.setParameterDerivatives(phaseMeasurementDriver, span.getStart(), phaseDerivatives[index]);
  195.                 }
  196.             }
  197.         }

  198.         // Return the estimated measurement
  199.         return estimatedPhase;

  200.     }

  201. }