GeometryFreeCycleSlipDetector.java

  1. /* Copyright 2002-2022 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.ArrayList;
  19. import java.util.List;
  20. import java.util.Map;

  21. import org.hipparchus.fitting.PolynomialCurveFitter;
  22. import org.hipparchus.fitting.WeightedObservedPoint;
  23. import org.hipparchus.util.FastMath;
  24. import org.orekit.gnss.CombinedObservationData;
  25. import org.orekit.gnss.CombinedObservationDataSet;
  26. import org.orekit.gnss.Frequency;
  27. import org.orekit.gnss.MeasurementType;
  28. import org.orekit.gnss.ObservationDataSet;
  29. import org.orekit.gnss.SatelliteSystem;
  30. import org.orekit.time.AbsoluteDate;


  31. /**
  32.  * Geometry free cycle slip detectors.
  33.  * The detector is based the algorithm given in <a
  34.  * href="https://gssc.esa.int/navipedia/index.php/Detector_based_in_carrier_phase_data:_The_geometry-free_combination">
  35.  * Detector based in carrier phase data: The geometry-free combination</a> by Zornoza and M. Hernández-Pajares. Within this class
  36.  * a second order polynomial is used to smooth the data. We consider a cycle-slip occurring if the current measurement is  too
  37.  * far from the one predicted with the polynomial.
  38.  * <p>
  39.  * For building the detector, one should give a threshold and a gap time limit.
  40.  * After construction of the detectors, one can have access to a List of CycleData. Each CycleDate represents
  41.  * a link between the station (define by the RINEX file) and a satellite at a specific frequency. For each cycle data,
  42.  * one has access to the begin and end of availability, and a sorted set which contains all the date at which
  43.  * cycle-slip have been detected
  44.  * </p>
  45.  * <p>
  46.  * @author David Soulard
  47.  * @author Bryan Cazabonne
  48.  * @since 10.2
  49.  */
  50. public class GeometryFreeCycleSlipDetector extends AbstractCycleSlipDetector {

  51.     /** Threshold above which cycle-slip occurs. */
  52.     private final double threshold;

  53.     /**
  54.      * Constructor.
  55.      * @param dt time gap threshold between two consecutive measurement (if time between two consecutive measurement is greater than dt, a cycle slip is declared)
  56.      * @param threshold threshold above which cycle-slip occurs
  57.      * @param n number of measurement before starting
  58.      */
  59.     public GeometryFreeCycleSlipDetector(final double dt, final double threshold, final int n) {
  60.         super(dt, n);
  61.         this.threshold = threshold;
  62.     }


  63.     /** {@inheritDoc} */
  64.     @Override
  65.     protected void manageData(final ObservationDataSet observation) {

  66.         // Extract observation data
  67.         final int             prn    = observation.getPrnNumber();
  68.         final AbsoluteDate    date   = observation.getDate();
  69.         final SatelliteSystem system = observation.getSatelliteSystem();

  70.         // Geometry-free combination of measurements
  71.         final GeometryFreeCombination geometryFree = MeasurementCombinationFactory.getGeometryFreeCombination(system);
  72.         final CombinedObservationDataSet cods = geometryFree.combine(observation);

  73.         // Initialize list of measurements
  74.         final List<CombinedObservationData> phasesGF = new ArrayList<>();

  75.         // Loop on observation data to fill lists
  76.         for (final CombinedObservationData cod : cods.getObservationData()) {
  77.             if (!Double.isNaN(cod.getValue()) && cod.getMeasurementType() == MeasurementType.CARRIER_PHASE) {
  78.                 phasesGF.add(cod);
  79.             }
  80.         }

  81.         // Loop on Geometry-free phase measurements
  82.         for (CombinedObservationData cod : phasesGF) {
  83.             final String nameSat = setName(prn, observation.getSatelliteSystem());
  84.             // Check for cycle-slip detection
  85.             final Frequency frequency = cod.getUsedObservationData().get(0).getObservationType().getFrequency(system);
  86.             final boolean slip = cycleSlipDetection(nameSat, date, cod.getValue(), frequency);
  87.             if (!slip) {
  88.                 // Update cycle slip data
  89.                 cycleSlipDataSet(nameSat, date, cod.getValue(), cod.getUsedObservationData().get(0).getObservationType().getFrequency(system));
  90.             }
  91.         }

  92.     }

  93.     /**
  94.      * Compute if there is a cycle slip at an specific date.
  95.      * @param nameSat name of the satellite, on the pre-defined format (e.g.: GPS - 07 for satellite 7 of GPS constellation)
  96.      * @param currentDate the date at which we check if a cycle-slip occurs
  97.      * @param valueGF geometry free measurement
  98.      * @param frequency frequency used
  99.      * @return true if a cycle slip has been detected.
  100.      */
  101.     private boolean cycleSlipDetection(final String nameSat, final AbsoluteDate currentDate,
  102.                                        final double valueGF, final Frequency frequency) {

  103.         // Access the cycle slip results to know if a cycle-slip already occurred
  104.         final List<CycleSlipDetectorResults>         data  = getResults();
  105.         final List<Map<Frequency, DataForDetection>> stuff = getStuffReference();

  106.         // If a cycle-slip already occurred
  107.         if (data != null) {

  108.             // Loop on cycle-slip results
  109.             for (CycleSlipDetectorResults resultGF : data) {

  110.                 // Found the right cycle data
  111.                 if (resultGF.getSatelliteName().compareTo(nameSat) == 0 && resultGF.getCycleSlipMap().containsKey(frequency)) {
  112.                     final Map<Frequency, DataForDetection> values = stuff.get(data.indexOf(resultGF));
  113.                     final DataForDetection dataForDetection = values.get(frequency);

  114.                     // Check the time gap condition
  115.                     final double deltaT = FastMath.abs(currentDate.durationFrom(dataForDetection.getFiguresReference()[dataForDetection.getWrite()].getDate()));
  116.                     if (deltaT > getMaxTimeBeetween2Measurement()) {
  117.                         resultGF.addCycleSlipDate(frequency, currentDate);
  118.                         dataForDetection.resetFigures(new SlipComputationData[getMinMeasurementNumber()], valueGF, currentDate);
  119.                         resultGF.setDate(frequency, currentDate);
  120.                         return true;
  121.                     }

  122.                     // Compute the fitting polynomial if there are enough measurement since last cycle-slip
  123.                     if (dataForDetection.getCanBeComputed() >= getMinMeasurementNumber()) {
  124.                         final List<WeightedObservedPoint> xy = new ArrayList<>();
  125.                         for (int i = 0; i < getMinMeasurementNumber(); i++) {
  126.                             final SlipComputationData current = dataForDetection.getFiguresReference()[i];
  127.                             xy.add(new WeightedObservedPoint(1.0, current.getDate().durationFrom(currentDate),
  128.                                                              current.getValue()));
  129.                         }

  130.                         final PolynomialCurveFitter fitting = PolynomialCurveFitter.create(2);
  131.                         // Check if there is a cycle_slip
  132.                         if (FastMath.abs(fitting.fit(xy)[0] - valueGF) > threshold) {
  133.                             resultGF.addCycleSlipDate(frequency, currentDate);
  134.                             dataForDetection.resetFigures(new SlipComputationData[getMinMeasurementNumber()], valueGF, currentDate);
  135.                             resultGF.setDate(frequency, currentDate);
  136.                             return true;
  137.                         }

  138.                     } else {
  139.                         break;
  140.                     }

  141.                 }

  142.             }

  143.         }

  144.         // No cycle-slip
  145.         return false;
  146.     }

  147. }