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

  21. import org.orekit.errors.OrekitException;
  22. import org.orekit.errors.OrekitMessages;
  23. import org.orekit.files.rinex.observation.ObservationData;
  24. import org.orekit.files.rinex.observation.ObservationDataSet;
  25. import org.orekit.gnss.GnssSignal;
  26. import org.orekit.gnss.MeasurementType;
  27. import org.orekit.gnss.ObservationType;
  28. import org.orekit.gnss.SatelliteSystem;
  29. import org.orekit.utils.Constants;

  30. /** Base class for dual frequency combination of measurements.
  31.  * @author Bryan Cazabonne
  32.  * @since 10.1
  33.  */
  34. public abstract class AbstractDualFrequencyCombination implements MeasurementCombination {

  35.     /** Type of combination of measurements. */
  36.     private final CombinationType type;

  37.     /** Satellite system used for the combination. */
  38.     private final SatelliteSystem system;

  39.     /**
  40.      * Constructor.
  41.      * @param type combination of measurements type
  42.      * @param system satellite system
  43.      */
  44.     protected AbstractDualFrequencyCombination(final CombinationType type, final SatelliteSystem system) {
  45.         this.type   = type;
  46.         this.system = system;
  47.     }

  48.     /** {@inheritDoc} */
  49.     @Override
  50.     public String getName() {
  51.         return type.getName();
  52.     }

  53.     /**
  54.      * Combines observation data using a dual frequency combination of measurements.
  55.      * @param od1 first observation data to combined
  56.      * @param od2 second observation data to combined
  57.      * @return a combined observation data
  58.      */
  59.     public CombinedObservationData combine(final ObservationData od1, final ObservationData od2) {

  60.         // Observation types
  61.         final ObservationType obsType1 = od1.getObservationType();
  62.         final ObservationType obsType2 = od2.getObservationType();

  63.         // Frequencies
  64.         final GnssSignal signal1 = obsType1.getSignal(system);
  65.         final GnssSignal signal2 = obsType2.getSignal(system);
  66.         // Check if the combination of measurements if performed for two different frequencies
  67.         if (signal1 == signal2) {
  68.             throw new OrekitException(OrekitMessages.INCOMPATIBLE_FREQUENCIES_FOR_COMBINATION_OF_MEASUREMENTS,
  69.                                       signal1.getFrequency(), signal2.getFrequency(), getName());
  70.         }

  71.         // Measurements types
  72.         final MeasurementType measType1 = obsType1.getMeasurementType();
  73.         final MeasurementType measType2 = obsType2.getMeasurementType();

  74.         // Check if measurement types are the same
  75.         if (measType1 != measType2) {
  76.             // If the measurement types are differents, an exception is thrown
  77.             throw new OrekitException(OrekitMessages.INVALID_MEASUREMENT_TYPES_FOR_COMBINATION_OF_MEASUREMENTS,
  78.                                       measType1, measType2, getName());
  79.         }

  80.         // Combined frequency
  81.         final double combinedFrequency = getCombinedFrequency(signal1, signal2);

  82.         // Combined value
  83.         final double combinedValue;
  84.         if (obsType1.getMeasurementType() == MeasurementType.CARRIER_PHASE && !Double.isNaN(combinedFrequency)) {
  85.             // Transform from cycle to meters measurements
  86.             final double obs1Meters = od1.getValue() * signal1.getWavelength();
  87.             final double obs2Meters = od2.getValue() * signal2.getWavelength();

  88.             // Calculate the combined value and convert it in cycles using the combined frequency
  89.             combinedValue = getCombinedValue(obs1Meters, signal1, obs2Meters, signal2) * combinedFrequency / Constants.SPEED_OF_LIGHT;
  90.         } else {
  91.             combinedValue = getCombinedValue(od1.getValue(), signal1, od2.getValue(), signal2);
  92.         }

  93.         // Combined observation data
  94.         return new CombinedObservationData(combinedValue, combinedFrequency, type, measType1, Arrays.asList(od1, od2));

  95.     }

  96.     /** {@inheritDoc} */
  97.     @Override
  98.     public CombinedObservationDataSet combine(final ObservationDataSet observations) {

  99.         // Initialize list of measurements
  100.         final List<ObservationData> pseudoRanges = new ArrayList<>();
  101.         final List<ObservationData> phases       = new ArrayList<>();

  102.         // Loop on observation data to fill lists
  103.         for (final ObservationData od : observations.getObservationData()) {
  104.             if (!Double.isNaN(od.getValue())) {
  105.                 if (od.getObservationType().getMeasurementType() == MeasurementType.PSEUDO_RANGE) {
  106.                     pseudoRanges.add(od);
  107.                 } else if (od.getObservationType().getMeasurementType() == MeasurementType.CARRIER_PHASE) {
  108.                     phases.add(od);
  109.                 }
  110.             }
  111.         }

  112.         // Initialize list of combined observation data
  113.         final List<CombinedObservationData> combined = new ArrayList<>();
  114.         // Combine pseudo-ranges
  115.         for (int i = 0; i < pseudoRanges.size() - 1; i++) {
  116.             for (int j = 1; j < pseudoRanges.size(); j++) {
  117.                 final boolean combine = isCombinationPossible(pseudoRanges.get(i), pseudoRanges.get(j));
  118.                 if (combine) {
  119.                     combined.add(combine(pseudoRanges.get(i), pseudoRanges.get(j)));
  120.                 }
  121.             }
  122.         }
  123.         // Combine carrier-phases
  124.         for (int i = 0; i < phases.size() - 1; i++) {
  125.             for (int j = 1; j < phases.size(); j++) {
  126.                 final boolean combine = isCombinationPossible(phases.get(i), phases.get(j));
  127.                 if (combine) {
  128.                     combined.add(combine(phases.get(i), phases.get(j)));
  129.                 }
  130.             }
  131.         }

  132.         return new CombinedObservationDataSet(observations.getSatellite().getSystem(),
  133.                                               observations.getSatellite().getPRN(),
  134.                                               observations.getDate(),
  135.                                               observations.getRcvrClkOffset(), combined);
  136.     }

  137.     /**
  138.      * Get the combined observed value of two measurements.
  139.      *
  140.      * @param obs1 observed value of the first measurement
  141.      * @param s1   frequency of the first measurement
  142.      * @param obs2 observed value of the second measurement
  143.      * @param s2   frequency of the second measurement
  144.      * @return combined observed value
  145.      */
  146.     protected abstract double getCombinedValue(double obs1, GnssSignal s1, double obs2, GnssSignal s2);

  147.     /**
  148.      * Get the combined frequency of two measurements.
  149.      *
  150.      * @param s1 frequency of the first measurement
  151.      * @param s2 frequency of the second measurement
  152.      * @return combined frequency in Hz
  153.      */
  154.     protected abstract double getCombinedFrequency(GnssSignal s1, GnssSignal s2);

  155.     /**
  156.      * Verifies if two observation data can be combined.
  157.      * @param data1 first observation data
  158.      * @param data2 second observation data
  159.      * @return true if observation data can be combined
  160.      */
  161.     private boolean isCombinationPossible(final ObservationData data1, final ObservationData data2) {
  162.         // Observation types
  163.         final ObservationType obsType1 = data1.getObservationType();
  164.         final ObservationType obsType2 = data2.getObservationType();
  165.         // Dual-frequency combination is possible only if observation code is the same and data frequencies are different
  166.         return obsType1.getSignal(system) != obsType2.getSignal(system) &&
  167.                obsType1.getSignalCode() == obsType2.getSignalCode();
  168.     }

  169. }