MelbourneWubbenaCombination.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 org.hipparchus.util.FastMath;
  21. import org.orekit.gnss.CombinedObservationData;
  22. import org.orekit.gnss.CombinedObservationDataSet;
  23. import org.orekit.gnss.MeasurementType;
  24. import org.orekit.gnss.ObservationData;
  25. import org.orekit.gnss.ObservationDataSet;
  26. import org.orekit.gnss.SatelliteSystem;

  27. /**
  28.  * Melbourne-Wübbena combination.
  29.  * <p>
  30.  * This combination allows, thanks to the wide-lane combination, a larger wavelength
  31.  * than each signal individually. Moreover, the measurement noise is reduced by the
  32.  * narrow-lane combination of code measurements.
  33.  * </p>
  34.  * <pre>
  35.  *    mMW =  ΦWL- RNL
  36.  *    mMW =  λWL * NWL+ b + ε
  37.  * </pre>
  38.  * With:
  39.  * <ul>
  40.  * <li>mMW : Melbourne-Wübbena measurement.</li>
  41.  * <li>ΦWL : Wide-Lane phase measurement.</li>
  42.  * <li>RNL : Narrow-Lane code measurement.</li>
  43.  * <li>λWL : Wide-Lane wavelength.</li>
  44.  * <li>NWL : Wide-Lane ambiguity (Nf1 - Nf2).</li>
  45.  * <li>b   : Satellite and receiver instrumental delays.</li>
  46.  * <li>ε   : Measurement noise.</li>
  47.  * </ul>
  48.  * <p>
  49.  * {@link NarrowLaneCombination Narrow-Lane} and {@link WideLaneCombination Wide-Lane}
  50.  * combinations shall be performed with the same pair of frequencies.
  51.  * </p>
  52.  *
  53.  * @see "Detector based in code and carrier phase data: The Melbourne-Wübbena combination,
  54.  *       J. Sanz Subirana, J.M. Juan Zornoza and M. Hernández-Pajares, 2011"
  55.  *
  56.  * @author Bryan Cazabonne
  57.  * @since 10.1
  58.  */
  59. public class MelbourneWubbenaCombination implements MeasurementCombination {

  60.     /** Threshold for frequency comparison. */
  61.     private static final double THRESHOLD = 1.0e-10;

  62.     /** Satellite system used for the combination. */
  63.     private final SatelliteSystem system;

  64.     /**
  65.      * Package private constructor for the factory.
  66.      * @param system satellite system for which the combination is applied
  67.      */
  68.     MelbourneWubbenaCombination(final SatelliteSystem system) {
  69.         this.system = system;
  70.     }

  71.     /** {@inheritDoc} */
  72.     @Override
  73.     public CombinedObservationDataSet combine(final ObservationDataSet observations) {

  74.         // Wide-Lane combination
  75.         final WideLaneCombination        wideLane   = MeasurementCombinationFactory.getWideLaneCombination(system);
  76.         final CombinedObservationDataSet combinedWL = wideLane.combine(observations);

  77.         // Narrow-Lane combination
  78.         final NarrowLaneCombination      narrowLane = MeasurementCombinationFactory.getNarrowLaneCombination(system);
  79.         final CombinedObservationDataSet combinedNL = narrowLane.combine(observations);

  80.         // Initialize list of combined observation data
  81.         final List<CombinedObservationData> combined = new ArrayList<>();

  82.         // Loop on Wide-Lane measurements
  83.         for (CombinedObservationData odWL : combinedWL.getObservationData()) {
  84.             // Only consider combined phase measurements
  85.             if (odWL.getMeasurementType() == MeasurementType.CARRIER_PHASE) {
  86.                 // Loop on Narrow-Lane measurements
  87.                 for (CombinedObservationData odNL : combinedNL.getObservationData()) {
  88.                     // Only consider combined range measurements
  89.                     if (odNL.getMeasurementType() == MeasurementType.PSEUDO_RANGE) {
  90.                         // Verify if the combinations have used the same frequencies
  91.                         final boolean isCombinationPossible = isCombinationPossible(odWL, odNL);
  92.                         if (isCombinationPossible) {
  93.                             // Combined value and frequency
  94.                             final double combinedValue     = odWL.getValue() - odNL.getValue();
  95.                             final double combinedFrequency = odWL.getCombinedMHzFrequency();
  96.                             // Used observation data to build the Melbourn-Wübbena measurement
  97.                             final List<ObservationData> usedData = new ArrayList<ObservationData>(4);
  98.                             usedData.add(0, odWL.getUsedObservationData().get(0));
  99.                             usedData.add(1, odWL.getUsedObservationData().get(1));
  100.                             usedData.add(2, odNL.getUsedObservationData().get(0));
  101.                             usedData.add(3, odNL.getUsedObservationData().get(1));
  102.                             // Update the combined observation data list
  103.                             combined.add(new CombinedObservationData(CombinationType.MELBOURNE_WUBBENA,
  104.                                                                      MeasurementType.COMBINED_RANGE_PHASE,
  105.                                                                      combinedValue, combinedFrequency, usedData));
  106.                         }
  107.                     }
  108.                 }
  109.             }
  110.         }

  111.         return new CombinedObservationDataSet(observations.getHeader(), observations.getSatelliteSystem(),
  112.                                               observations.getPrnNumber(), observations.getDate(),
  113.                                               observations.getRcvrClkOffset(), combined);
  114.     }

  115.     /**
  116.      * Verifies if the Melbourne-Wübbena combination is possible between both combined observation data.
  117.      * <p>
  118.      * This method compares the frequencies of the combined measurement to decide
  119.      * if the combination of measurements is possible.
  120.      * The combination is possible if :
  121.      * <pre>
  122.      *    abs(f1<sub>WL</sub> - f2<sub>WL</sub>) = abs(f1<sub>NL</sub> - f2<sub>NL</sub>)
  123.      * </pre>
  124.      * </p>
  125.      * @param odWL Wide-Lane measurement
  126.      * @param odNL Narrow-Lane measurement
  127.      * @return true if the Melbourne-Wübbena combination is possible
  128.      */
  129.     private boolean isCombinationPossible(final CombinedObservationData odWL, final CombinedObservationData odNL) {
  130.         // Frequencies
  131.         final double[] frequency = new double[4];
  132.         int j = 0;
  133.         for (int i = 0; i < odWL.getUsedObservationData().size(); i++) {
  134.             frequency[j++] = odWL.getUsedObservationData().get(i).getObservationType().getFrequency(system).getMHzFrequency();
  135.             frequency[j++] = odNL.getUsedObservationData().get(i).getObservationType().getFrequency(system).getMHzFrequency();
  136.         }
  137.         // Verify if used frequencies are the same.
  138.         // Possible numerical error is taken into account by using a threshold of acceptance
  139.         return (FastMath.abs(frequency[0] - frequency[2]) - FastMath.abs(frequency[1] - frequency[3])) < THRESHOLD;
  140.     }

  141.     /** {@inheritDoc} */
  142.     @Override
  143.     public String getName() {
  144.         return CombinationType.MELBOURNE_WUBBENA.getName();
  145.     }

  146. }