DualFrequencyHatchFilter.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.filtering;
- import java.util.ArrayList;
- import org.hipparchus.util.FastMath;
- import org.orekit.files.rinex.observation.ObservationData;
- import org.orekit.utils.Constants;
- /**
- * Hatch Filter using Carrier-Phase measurements taken at two different frequencies,
- * to form a Divergence-Free phase combination.
- * <p>
- * This filter uses a phase combination to mitigate the effects of the
- * temporally varying ionospheric delays. Still, the spatial variation of the ionospheric delays
- * are not compensated by this phase combination.
- * </p>
- * @see "Subirana, J. S., Hernandez-Pajares, M., and José Miguel Juan Zornoza. (2013).
- * GNSS Data Processing: Fundamentals and Algorithms. European Space Agency.
- * Section 4.2.3.1.1"
- *
- * @author Louis Aucouturier
- * @since 11.2
- */
- public class DualFrequencyHatchFilter extends HatchFilter {
- /** First wavelength used for smoothing. */
- private double wavelengthFreq1;
- /** Second wavelength used for smoothing. */
- private double wavelengthFreq2;
- /** List used to store the phase value of the first frequency. */
- private ArrayList<Double> phase1History;
- /** List used to store the phase value of the second frequency.*/
- private ArrayList<Double> phase2History;
- /**
- * Constructor for the Dual Frequency Hatch Filter.
- * <p>
- * The threshold parameter corresponds to the maximum difference between
- * non-smoothed and smoothed pseudo range value, above which the filter
- * is reset.
- * </p>
- * @param initCode initial code measurement
- * @param initPhaseFreq1 initial phase measurement for the first chosen frequency
- * @param initPhaseFreq2 initial phase measurement for the second chosen frequency
- * @param wavelengthFreq1 initPhaseFreq1 observed value wavelength (m)
- * @param wavelengthFreq2 initPhaseFreq2 observed value wavelength (m)
- * @param threshold threshold for loss of lock detection
- * (it represents the maximum difference between smoothed
- * and measured values for loss of lock detection)
- * @param N window size of the Hatch Filter
- */
- public DualFrequencyHatchFilter(final ObservationData initCode,
- final ObservationData initPhaseFreq1, final ObservationData initPhaseFreq2,
- final double wavelengthFreq1, final double wavelengthFreq2,
- final double threshold, final int N) {
- super(threshold, N);
- // Initialize wavelength and compute frequencies
- this.wavelengthFreq1 = wavelengthFreq1;
- this.wavelengthFreq2 = wavelengthFreq2;
- // Initialize array of phase values used during smoothing
- this.phase1History = new ArrayList<>();
- this.phase2History = new ArrayList<>();
- phase1History.add(initPhaseFreq1.getValue() * wavelengthFreq1);
- phase2History.add(initPhaseFreq2.getValue() * wavelengthFreq2);
- updatePreviousSmoothedCode(initCode.getValue());
- updatePreviousSmoothingValue(divergenceFreeCombination(initPhaseFreq1.getValue(), initPhaseFreq2.getValue(), wavelengthFreq1, wavelengthFreq2));
- addToSmoothedCodeHistory(initCode.getValue());
- addToCodeHistory(initCode.getValue());
- }
- /**
- * This method filters the provided data given the state of the filter.
- * @param codeData input code observation data
- * @param phaseDataFreq1 input phase observation data for the first frequency
- * @param phaseDataFreq2 input phase observation data for the second frequency
- * @return the smoothed observation data
- */
- public ObservationData filterData(final ObservationData codeData, final ObservationData phaseDataFreq1, final ObservationData phaseDataFreq2) {
- // Current code value
- final double code = codeData.getValue();
- addToCodeHistory(code);
- // Computes the phase combination and smoothing value (Ref Eq. 4.32)
- final double phaseFreq1 = wavelengthFreq1 * phaseDataFreq1.getValue();
- final double phaseFreq2 = wavelengthFreq2 * phaseDataFreq2.getValue();
- final double phaseDF = divergenceFreeCombination(phaseDataFreq1.getValue(), phaseDataFreq2.getValue(), wavelengthFreq1, wavelengthFreq2);
- phase1History.add(phaseFreq1);
- phase2History.add(phaseFreq2);
- // Check for carrier phase cycle slip (check on the two phase data)
- final boolean cycleSlip = FastMath.floorMod(phaseDataFreq1.getLossOfLockIndicator(), 2) != 0 ||
- FastMath.floorMod(phaseDataFreq2.getLossOfLockIndicator(), 2) != 0;
- // Computes the smoothed code value
- double smoothedValue = smoothedCode(code, phaseDF);
- updatePreviousSmoothingValue(phaseDF);
- // Check if filter reset needed, if not return smoothedValue, and increase k if necessary.
- smoothedValue = checkValidData(code, smoothedValue, cycleSlip);
- addToSmoothedCodeHistory(smoothedValue);
- updatePreviousSmoothedCode(smoothedValue);
- // Return the smoothed observed data
- return new ObservationData(codeData.getObservationType(), smoothedValue,
- codeData.getLossOfLockIndicator(), codeData.getSignalStrength());
- }
- /**
- * Get the history of phase values of the first frequency.
- * @return the history of phase values of the first frequency
- */
- public ArrayList<Double> getFirstFrequencyPhaseHistory() {
- return phase1History;
- }
- /**
- * Get the history of phase values of the second frequency.
- * @return the history of phase values of the second frequency
- */
- public ArrayList<Double> getSecondFrequencyPhaseHistory() {
- return phase2History;
- }
- /**
- * Divergence-free combination (Ref Eq. 4.32).
- * <p>
- * phase_DF = phase_F1 + 2.0 * alpha + (phase_F1 - phase_F2)
- * </p>
- * @param phase1 phase value for frequency 1
- * @param phase2 phase value for frequency 2
- * @param lambda1 wavelength of the first phase (m)
- * @param lambda2 wavelength of the second phase (m)
- * @return the value of the divergence-free combination
- */
- private static double divergenceFreeCombination(final double phase1, final double phase2,
- final double lambda1, final double lambda2) {
- // Multiply phase value by its wavelength
- final double phaseFreq1 = lambda1 * phase1;
- final double phaseFreq2 = lambda2 * phase2;
- // Convert wavelength to frequencies
- final double f1 = Constants.SPEED_OF_LIGHT / lambda1;
- final double f2 = Constants.SPEED_OF_LIGHT / lambda2;
- // Alpha
- final double alpha = 1.0 / ((f1 * f1) / (f2 * f2) - 1.0);
- // Return
- return phaseFreq1 + 2.0 * alpha * (phaseFreq1 - phaseFreq2);
- }
- }