MelbourneWubbenaCombination.java
- /* Copyright 2002-2024 CS GROUP
- * Licensed to CS GROUP (CS) under one or more
- * contributor license agreements. See the NOTICE file distributed with
- * this work for additional information regarding copyright ownership.
- * CS licenses this file to You under the Apache License, Version 2.0
- * (the "License"); you may not use this file except in compliance with
- * the License. You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
- package org.orekit.estimation.measurements.gnss;
- import java.util.ArrayList;
- import java.util.List;
- import org.hipparchus.util.FastMath;
- import org.orekit.files.rinex.observation.ObservationData;
- import org.orekit.files.rinex.observation.ObservationDataSet;
- import org.orekit.gnss.MeasurementType;
- import org.orekit.gnss.SatelliteSystem;
- /**
- * Melbourne-Wübbena combination.
- * <p>
- * This combination allows, thanks to the wide-lane combination, a larger wavelength
- * than each signal individually. Moreover, the measurement noise is reduced by the
- * narrow-lane combination of code measurements.
- * </p>
- * <pre>
- * mMW = ΦWL- RNL
- * mMW = λWL * NWL+ b + ε
- * </pre>
- * With:
- * <ul>
- * <li>mMW : Melbourne-Wübbena measurement.</li>
- * <li>ΦWL : Wide-Lane phase measurement.</li>
- * <li>RNL : Narrow-Lane code measurement.</li>
- * <li>λWL : Wide-Lane wavelength.</li>
- * <li>NWL : Wide-Lane ambiguity (Nf1 - Nf2).</li>
- * <li>b : Satellite and receiver instrumental delays.</li>
- * <li>ε : Measurement noise.</li>
- * </ul>
- * <p>
- * {@link NarrowLaneCombination Narrow-Lane} and {@link WideLaneCombination Wide-Lane}
- * combinations shall be performed with the same pair of frequencies.
- * </p>
- *
- * @see "Detector based in code and carrier phase data: The Melbourne-Wübbena combination,
- * J. Sanz Subirana, J.M. Juan Zornoza and M. Hernández-Pajares, 2011"
- *
- * @author Bryan Cazabonne
- * @since 10.1
- */
- public class MelbourneWubbenaCombination implements MeasurementCombination {
- /** Threshold for frequency comparison. */
- private static final double THRESHOLD = 1.0e-10;
- /** Satellite system used for the combination. */
- private final SatelliteSystem system;
- /**
- * Package private constructor for the factory.
- * @param system satellite system for which the combination is applied
- */
- MelbourneWubbenaCombination(final SatelliteSystem system) {
- this.system = system;
- }
- /** {@inheritDoc} */
- @Override
- public CombinedObservationDataSet combine(final ObservationDataSet observations) {
- // Wide-Lane combination
- final WideLaneCombination wideLane = MeasurementCombinationFactory.getWideLaneCombination(system);
- final CombinedObservationDataSet combinedWL = wideLane.combine(observations);
- // Narrow-Lane combination
- final NarrowLaneCombination narrowLane = MeasurementCombinationFactory.getNarrowLaneCombination(system);
- final CombinedObservationDataSet combinedNL = narrowLane.combine(observations);
- // Initialize list of combined observation data
- final List<CombinedObservationData> combined = new ArrayList<>();
- // Loop on Wide-Lane measurements
- for (CombinedObservationData odWL : combinedWL.getObservationData()) {
- // Only consider combined phase measurements
- if (odWL.getMeasurementType() == MeasurementType.CARRIER_PHASE) {
- // Loop on Narrow-Lane measurements
- for (CombinedObservationData odNL : combinedNL.getObservationData()) {
- // Only consider combined range measurements
- if (odNL.getMeasurementType() == MeasurementType.PSEUDO_RANGE) {
- // Verify if the combinations have used the same frequencies
- final boolean isCombinationPossible = isCombinationPossible(odWL, odNL);
- if (isCombinationPossible) {
- // Combined value and frequency
- final double combinedValue = odWL.getValue() - odNL.getValue();
- final double combinedFrequency = odWL.getCombinedMHzFrequency();
- // Used observation data to build the Melbourn-Wübbena measurement
- final List<ObservationData> usedData = new ArrayList<ObservationData>(4);
- usedData.add(0, odWL.getUsedObservationData().get(0));
- usedData.add(1, odWL.getUsedObservationData().get(1));
- usedData.add(2, odNL.getUsedObservationData().get(0));
- usedData.add(3, odNL.getUsedObservationData().get(1));
- // Update the combined observation data list
- combined.add(new CombinedObservationData(CombinationType.MELBOURNE_WUBBENA,
- MeasurementType.COMBINED_RANGE_PHASE,
- combinedValue, combinedFrequency, usedData));
- }
- }
- }
- }
- }
- return new CombinedObservationDataSet(observations.getSatellite().getSystem(),
- observations.getSatellite().getPRN(),
- observations.getDate(),
- observations.getRcvrClkOffset(), combined);
- }
- /**
- * Verifies if the Melbourne-Wübbena combination is possible between both combined observation data.
- * <p>
- * This method compares the frequencies of the combined measurement to decide
- * if the combination of measurements is possible.
- * The combination is possible if :
- * <pre>
- * abs(f1<sub>WL</sub> - f2<sub>WL</sub>) = abs(f1<sub>NL</sub> - f2<sub>NL</sub>)
- * </pre>
- * </p>
- * @param odWL Wide-Lane measurement
- * @param odNL Narrow-Lane measurement
- * @return true if the Melbourne-Wübbena combination is possible
- */
- private boolean isCombinationPossible(final CombinedObservationData odWL, final CombinedObservationData odNL) {
- // Frequencies
- final double[] frequency = new double[4];
- int j = 0;
- for (int i = 0; i < odWL.getUsedObservationData().size(); i++) {
- frequency[j++] = odWL.getUsedObservationData().get(i).getObservationType().getFrequency(system).getMHzFrequency();
- frequency[j++] = odNL.getUsedObservationData().get(i).getObservationType().getFrequency(system).getMHzFrequency();
- }
- // Verify if used frequencies are the same.
- // Possible numerical error is taken into account by using a threshold of acceptance
- return (FastMath.abs(frequency[0] - frequency[2]) - FastMath.abs(frequency[1] - frequency[3])) < THRESHOLD;
- }
- /** {@inheritDoc} */
- @Override
- public String getName() {
- return CombinationType.MELBOURNE_WUBBENA.getName();
- }
- }