DualFrequencyHatchFilter.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.filtering;

  18. import java.util.ArrayList;

  19. import org.hipparchus.util.FastMath;
  20. import org.orekit.files.rinex.observation.ObservationData;
  21. import org.orekit.utils.Constants;

  22. /**
  23.  * Hatch Filter using Carrier-Phase measurements taken at two different frequencies,
  24.  * to form a Divergence-Free phase combination.
  25.  * <p>
  26.  * This filter uses a phase combination to mitigate the effects of the
  27.  * temporally varying ionospheric delays. Still, the spatial variation of the ionospheric delays
  28.  * are not compensated by this phase combination.
  29.  * </p>
  30.  * @see "Subirana, J. S., Hernandez-Pajares, M., and José Miguel Juan Zornoza. (2013).
  31.  *       GNSS Data Processing: Fundamentals and Algorithms. European Space Agency.
  32.  *       Section 4.2.3.1.1"
  33.  *
  34.  * @author Louis Aucouturier
  35.  * @since 11.2
  36.  */
  37. public class DualFrequencyHatchFilter extends HatchFilter {

  38.     /** First wavelength used for smoothing. */
  39.     private double wavelengthFreq1;

  40.     /** Second wavelength used for smoothing. */
  41.     private double wavelengthFreq2;

  42.     /** List used to store the phase value of the first frequency. */
  43.     private ArrayList<Double> phase1History;

  44.     /** List used to store the phase value of the second frequency.*/
  45.     private ArrayList<Double> phase2History;

  46.     /**
  47.      * Constructor for the Dual Frequency Hatch Filter.
  48.      * <p>
  49.      * The threshold parameter corresponds to the maximum difference between
  50.      * non-smoothed and smoothed pseudo range value, above which the filter
  51.      * is reset.
  52.      * </p>
  53.      * @param initCode        initial code measurement
  54.      * @param initPhaseFreq1  initial phase measurement for the first chosen frequency
  55.      * @param initPhaseFreq2  initial phase measurement for the second chosen frequency
  56.      * @param wavelengthFreq1 initPhaseFreq1 observed value wavelength (m)
  57.      * @param wavelengthFreq2 initPhaseFreq2 observed value wavelength (m)
  58.      * @param threshold       threshold for loss of lock detection
  59.      *                        (it represents the maximum difference between smoothed
  60.      *                        and measured values for loss of lock detection)
  61.      * @param N               window size of the Hatch Filter
  62.      */
  63.     public DualFrequencyHatchFilter(final ObservationData initCode,
  64.                                     final ObservationData initPhaseFreq1, final ObservationData initPhaseFreq2,
  65.                                     final double wavelengthFreq1, final double wavelengthFreq2,
  66.                                     final double threshold, final int N) {
  67.         super(threshold, N);
  68.         // Initialize wavelength and compute frequencies
  69.         this.wavelengthFreq1 = wavelengthFreq1;
  70.         this.wavelengthFreq2 = wavelengthFreq2;

  71.         // Initialize array of phase values used during smoothing
  72.         this.phase1History = new ArrayList<>();
  73.         this.phase2History = new ArrayList<>();
  74.         phase1History.add(initPhaseFreq1.getValue() * wavelengthFreq1);
  75.         phase2History.add(initPhaseFreq2.getValue() * wavelengthFreq2);
  76.         updatePreviousSmoothedCode(initCode.getValue());
  77.         updatePreviousSmoothingValue(divergenceFreeCombination(initPhaseFreq1.getValue(), initPhaseFreq2.getValue(), wavelengthFreq1, wavelengthFreq2));
  78.         addToSmoothedCodeHistory(initCode.getValue());
  79.         addToCodeHistory(initCode.getValue());
  80.     }

  81.     /**
  82.      * This method filters the provided data given the state of the filter.
  83.      * @param codeData       input code observation data
  84.      * @param phaseDataFreq1 input phase observation data for the first frequency
  85.      * @param phaseDataFreq2 input phase observation data for the second frequency
  86.      * @return the smoothed observation data
  87.      */
  88.     public ObservationData filterData(final ObservationData codeData, final ObservationData phaseDataFreq1, final ObservationData phaseDataFreq2) {

  89.         // Current code value
  90.         final double code = codeData.getValue();
  91.         addToCodeHistory(code);

  92.         // Computes the phase combination and smoothing value (Ref Eq. 4.32)
  93.         final double phaseFreq1 = wavelengthFreq1 * phaseDataFreq1.getValue();
  94.         final double phaseFreq2 = wavelengthFreq2 * phaseDataFreq2.getValue();
  95.         final double phaseDF = divergenceFreeCombination(phaseDataFreq1.getValue(), phaseDataFreq2.getValue(), wavelengthFreq1, wavelengthFreq2);
  96.         phase1History.add(phaseFreq1);
  97.         phase2History.add(phaseFreq2);

  98.         // Check for carrier phase cycle slip (check on the two phase data)
  99.         final boolean cycleSlip = FastMath.floorMod(phaseDataFreq1.getLossOfLockIndicator(), 2) != 0 ||
  100.                         FastMath.floorMod(phaseDataFreq2.getLossOfLockIndicator(), 2) != 0;

  101.         // Computes the smoothed code value
  102.         double smoothedValue = smoothedCode(code, phaseDF);
  103.         updatePreviousSmoothingValue(phaseDF);

  104.         // Check if filter reset needed, if not return smoothedValue, and increase k if necessary.
  105.         smoothedValue = checkValidData(code, smoothedValue, cycleSlip);
  106.         addToSmoothedCodeHistory(smoothedValue);
  107.         updatePreviousSmoothedCode(smoothedValue);

  108.         // Return the smoothed observed data
  109.         return new ObservationData(codeData.getObservationType(), smoothedValue,
  110.                                    codeData.getLossOfLockIndicator(), codeData.getSignalStrength());

  111.     }

  112.     /**
  113.      * Get the history of phase values of the first frequency.
  114.      * @return the history of phase values of the first frequency
  115.      */
  116.     public ArrayList<Double> getFirstFrequencyPhaseHistory() {
  117.         return phase1History;
  118.     }

  119.     /**
  120.      * Get the history of phase values of the second frequency.
  121.      * @return the history of phase values of the second frequency
  122.      */
  123.     public ArrayList<Double> getSecondFrequencyPhaseHistory() {
  124.         return phase2History;
  125.     }

  126.     /**
  127.      * Divergence-free combination (Ref Eq. 4.32).
  128.      * <p>
  129.      * phase_DF = phase_F1 + 2.0 * alpha + (phase_F1 - phase_F2)
  130.      * </p>
  131.      * @param phase1  phase value for frequency 1
  132.      * @param phase2  phase value for frequency 2
  133.      * @param lambda1 wavelength of the first phase (m)
  134.      * @param lambda2 wavelength of the second phase (m)
  135.      * @return the value of the divergence-free combination
  136.      */
  137.     private static double divergenceFreeCombination(final double phase1, final double phase2,
  138.                                                     final double lambda1, final double lambda2) {

  139.         // Multiply phase value by its wavelength
  140.         final double phaseFreq1 = lambda1 * phase1;
  141.         final double phaseFreq2 = lambda2 * phase2;

  142.         // Convert wavelength to frequencies
  143.         final double f1 = Constants.SPEED_OF_LIGHT / lambda1;
  144.         final double f2 = Constants.SPEED_OF_LIGHT / lambda2;

  145.         // Alpha
  146.         final double alpha = 1.0 / ((f1 * f1) / (f2 * f2) - 1.0);

  147.         // Return
  148.         return  phaseFreq1 + 2.0 * alpha * (phaseFreq1 - phaseFreq2);

  149.     }

  150. }