MelbourneWubbenaCombination.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.ArrayList;
  19. import java.util.List;

  20. import org.hipparchus.util.FastMath;
  21. import org.orekit.files.rinex.observation.ObservationData;
  22. import org.orekit.files.rinex.observation.ObservationDataSet;
  23. import org.orekit.gnss.MeasurementType;
  24. import org.orekit.gnss.SatelliteSystem;

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

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

  60.     /** Satellite system used for the combination. */
  61.     private final SatelliteSystem system;

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

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

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

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

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

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

  109.         return new CombinedObservationDataSet(observations.getSatellite().getSystem(),
  110.                                               observations.getSatellite().getPRN(),
  111.                                               observations.getDate(),
  112.                                               observations.getRcvrClkOffset(), combined);
  113.     }

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

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

  145. }