OneWayGNSSPhase.java

  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. import java.util.Arrays;

  19. import org.hipparchus.analysis.differentiation.Gradient;
  20. import org.orekit.estimation.measurements.EstimatedMeasurement;
  21. import org.orekit.estimation.measurements.EstimatedMeasurementBase;
  22. import org.orekit.estimation.measurements.ObservableSatellite;
  23. import org.orekit.estimation.measurements.QuadraticClockModel;
  24. import org.orekit.propagation.SpacecraftState;
  25. import org.orekit.time.AbsoluteDate;
  26. import org.orekit.utils.Constants;
  27. import org.orekit.utils.PVCoordinatesProvider;
  28. import org.orekit.utils.ParameterDriver;
  29. import org.orekit.utils.TimeSpanMap.Span;
  30. import org.orekit.utils.TimeStampedPVCoordinates;

  31. /** One-way GNSS phase measurement.
  32.  * <p>
  33.  * This class can be used in precise orbit determination applications
  34.  * for modeling a phase measurement between a GNSS satellite (emitter)
  35.  * and a LEO satellite (receiver).
  36.  * <p>
  37.  * The one-way GNSS phase measurement assumes knowledge of the orbit and
  38.  * the clock offset of the emitting GNSS satellite. For instance, it is
  39.  * possible to use a SP3 file or a GNSS navigation message to recover
  40.  * the satellite's orbit and clock.
  41.  * <p>
  42.  * This class is very similar to {@link InterSatellitesPhase} measurement
  43.  * class. However, using the one-way GNSS phase measurement, the orbit and clock
  44.  * of the emitting GNSS satellite are <b>NOT</b> estimated simultaneously with
  45.  * LEO satellite coordinates.
  46.  *
  47.  * @author Bryan Cazabonne
  48.  * @since 10.3
  49.  */
  50. public class OneWayGNSSPhase extends AbstractOneWayGNSSMeasurement<OneWayGNSSPhase> {

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

  53.     /** Driver for ambiguity. */
  54.     private final AmbiguityDriver ambiguityDriver;

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

  57.     /** Simple constructor.
  58.      * @param remote provider for GNSS satellite which simply emits the signal
  59.      * @param remoteName name of the remote
  60.      * @param remoteClock clock offset of the GNSS satellite
  61.      * @param date date of the measurement
  62.      * @param phase observed value, in cycles
  63.      * @param wavelength phase observed value wavelength, in meters
  64.      * @param sigma theoretical standard deviation
  65.      * @param baseWeight base weight
  66.      * @param local satellite which receives the signal and perform the measurement
  67.      * @param cache from which ambiguity drive should come
  68.      * @since 12.1
  69.      */
  70.     public OneWayGNSSPhase(final PVCoordinatesProvider remote,
  71.                            final String remoteName,
  72.                            final QuadraticClockModel remoteClock,
  73.                            final AbsoluteDate date,
  74.                            final double phase, final double wavelength, final double sigma,
  75.                            final double baseWeight, final ObservableSatellite local,
  76.                            final AmbiguityCache cache) {
  77.         // Call super constructor
  78.         super(remote, remoteClock, date, phase, sigma, baseWeight, local);

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

  81.         // The local satellite clock offset affects the measurement
  82.         addParameterDriver(ambiguityDriver);
  83.         addParameterDriver(local.getClockOffsetDriver());

  84.         // Initialise fields
  85.         this.wavelength = wavelength;
  86.     }

  87.     /** Get the wavelength.
  88.      * @return wavelength (m)
  89.      */
  90.     public double getWavelength() {
  91.         return wavelength;
  92.     }

  93.     /** Get the driver for phase ambiguity.
  94.      * @return the driver for phase ambiguity
  95.      */
  96.     public AmbiguityDriver getAmbiguityDriver() {
  97.         return ambiguityDriver;
  98.     }

  99.     /** {@inheritDoc} */
  100.     @Override
  101.     protected EstimatedMeasurementBase<OneWayGNSSPhase> theoreticalEvaluationWithoutDerivatives(final int iteration,
  102.                                                                                                 final int evaluation,
  103.                                                                                                 final SpacecraftState[] states) {

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

  105.         // prepare the evaluation
  106.         final EstimatedMeasurementBase<OneWayGNSSPhase> estimatedPhase =
  107.                         new EstimatedMeasurementBase<>(this, iteration, evaluation,
  108.                                                        new SpacecraftState[] {
  109.                                                            common.getState()
  110.                                                        }, new TimeStampedPVCoordinates[] {
  111.                                                            common.getRemotePV(),
  112.                                                            common.getTransitPV()
  113.                                                        });

  114.         // Phase value
  115.         final double   cOverLambda = Constants.SPEED_OF_LIGHT / wavelength;
  116.         final double   ambiguity   = ambiguityDriver.getValue(common.getState().getDate());
  117.         final double   phase       = (common.getTauD() + common.getLocalOffset() - common.getRemoteOffset()) * cOverLambda +
  118.                                      ambiguity;

  119.         // Set value of the estimated measurement
  120.         estimatedPhase.setEstimatedValue(phase);

  121.         // Return the estimated measurement
  122.         return estimatedPhase;

  123.     }

  124.     /** {@inheritDoc} */
  125.     @Override
  126.     protected EstimatedMeasurement<OneWayGNSSPhase> theoreticalEvaluation(final int iteration,
  127.                                                                           final int evaluation,
  128.                                                                           final SpacecraftState[] states) {

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

  130.         // prepare the evaluation
  131.         final EstimatedMeasurement<OneWayGNSSPhase> estimatedPhase =
  132.                         new EstimatedMeasurement<>(this, iteration, evaluation,
  133.                                                    new SpacecraftState[] {
  134.                                                        common.getState()
  135.                                                    }, new TimeStampedPVCoordinates[] {
  136.                                                      common.getRemotePV().toTimeStampedPVCoordinates(),
  137.                                                      common.getTransitPV().toTimeStampedPVCoordinates()
  138.                                                    });

  139.         // Phase value
  140.         final double   cOverLambda      = Constants.SPEED_OF_LIGHT / wavelength;
  141.         final Gradient ambiguity        = ambiguityDriver.getValue(common.getTauD().getFreeParameters(), common.getIndices(),
  142.                                                                    common.getState().getDate());
  143.         final Gradient phase            = common.getTauD().add(common.getLocalOffset()).subtract(common.getRemoteOffset()).
  144.                                           multiply(cOverLambda).
  145.                                           add(ambiguity);
  146.         final double[] phaseDerivatives = phase.getGradient();

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

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

  153.                 final Integer index = common.getIndices().get(span.getData());
  154.                 if (index != null) {
  155.                     estimatedPhase.setParameterDerivatives(phaseMeasurementDriver, span.getStart(), phaseDerivatives[index]);
  156.                 }
  157.             }
  158.         }

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

  161.     }

  162. }