HatchFilter.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;
- /** Base class for Hatch filters
- * <p>
- * Hatch filters are generally used to smooth the pseudo-range measurements with a set
- * of measurements, that might be combined or not, in order to mitigate the effect of multipath.
- * <p>
- * The original Hatch filter uses a single carrier-phase measurement as a smoothing value,
- * while a divergence free combination of carrier phases can be used, as well as Doppler measurements.
- * </p>
- * @see "Subirana, J. S., Hernandez-Pajares, M., and José Miguel Juan Zornoza. (2013).
- * GNSS Data Processing: Fundamentals and Algorithms. European Space Agency."
- *
- * @see "Zhou, Z., and Li, B. (2017). Optimal Doppler-aided smoothing strategy for GNSS navigation.
- * GPS solutions, 21(1), 197-210."
- *
- * @author Louis Aucouturier
- * @since 11.2
- */
- abstract class HatchFilter {
- /** Current index for the filter. */
- private int k;
- /** Boolean used to delay the reset of the filter. */
- private boolean resetNextBoolean;
- /** Last smoothed value for the pseudo-range. */
- private double previousSmoothedCode;
- /** Last smoothing value. */
- private double previousSmoothingValue;
- /** History of the pseudo-range value, appended at each filter iteration. */
- private ArrayList<Double> codeHistory;
- /** History of the smoothed pseudo-range value, appended at each filter iteration. */
- private ArrayList<Double> smoothedCodeHistory;
- /** Threshold for the difference between smoothed and measured values. */
- private double threshold;
- /** Window size of the Hatch Filter. */
- private final int N;
- /**
- * Constructor for the Abstract Hatch Filter.
- * <p>
- * Initialize the variables and set the initial pseudo-range state.
- * </p>
- * @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
- */
- HatchFilter(final double threshold, final int N) {
- // Initialize fields
- this.codeHistory = new ArrayList<>();
- this.smoothedCodeHistory = new ArrayList<>();
- this.threshold = threshold;
- this.resetNextBoolean = false;
- this.k = 1;
- this.N = N;
- }
- /**
- * Get the history of the pseudo-range values used by the filter.
- * @return the history of the pseudo-range values used by the filter
- */
- public ArrayList<Double> getCodeHistory() {
- return codeHistory;
- }
- /**
- * Get the history of the smoothed pseudo-range values used by the filter.
- * @return the smoothedCodeHistory
- */
- public ArrayList<Double> getSmoothedCodeHistory() {
- return smoothedCodeHistory;
- }
- /**
- * Get the threshold for loss of lock detection.
- * <p>
- * It represents the maximum difference between smoothed
- * and measured values for loss of lock detection.
- * </p>
- * @return the threshold for loss of lock detection
- */
- public double getThreshold() {
- return threshold;
- }
- /**
- * Update the previous smoothed value for the pseudo-range.
- * @param smoothedCode the previous smoothed value for the pseudo-range
- */
- public void updatePreviousSmoothedCode(final double smoothedCode) {
- this.previousSmoothedCode = smoothedCode;
- }
- /**
- * Update the previous smoothing value.
- * @param smoothingValue the previous smoothing value
- */
- public void updatePreviousSmoothingValue(final double smoothingValue) {
- this.previousSmoothingValue = smoothingValue;
- }
- /**
- * Add a value to the history of the pseudo-range value.
- * @param codeValue the value to add to the history
- */
- public void addToCodeHistory(final double codeValue) {
- codeHistory.add(codeValue);
- }
- /**
- * Add a value to the history of the smoothed pseudo-range value.
- * @param smoothedCodeValue the value to add to the history
- */
- public void addToSmoothedCodeHistory(final double smoothedCodeValue) {
- smoothedCodeHistory.add(smoothedCodeValue);
- }
- /**
- * Reset the filter in the case of a NaN phase value, skipping the smoothing at the present instant
- * and initializing at the next one, keeping the current code value.
- *
- * @param codeValue pseudo range value before the reset.
- * */
- public void resetFilterNext(final double codeValue) {
- resetK();
- resetNextBoolean();
- updatePreviousSmoothingValue(Double.NaN);
- updatePreviousSmoothedCode(codeValue);
- }
- /**
- * Set the flag for resetting the filter to true.
- */
- protected void resetNextBoolean() {
- this.resetNextBoolean = true;
- }
- /**
- * Reset the current index of the filter to 1.
- */
- protected void resetK() {
- this.k = 1;
- }
- /**
- * Computes the smoothed code value.
- * <p>
- * This method corresponds to Eq. (4.23) of
- * "Subirana, J. S., Hernandez-Pajares, M., and José Miguel Juan Zornoza.
- * GNSS Data Processing: Fundamentals and Algorithms.
- * European Space Agency."
- * </p>
- * @param codeValue value of the input code measurement (non-smoothed)
- * @param smoothingValue value of the measurement used to smooth the code measurement
- * @return the smoothed code value
- */
- protected double smoothedCode(final double codeValue,
- final double smoothingValue) {
- // Equation 4.23
- return (codeValue + (k - 1) * (previousSmoothedCode + (smoothingValue - previousSmoothingValue))) / k;
- }
- /**
- * Checks if need to reset the filter or if cycle slip occurred.
- * <p>
- * If yes, the smoothed value is reinitialized to the last code value.
- * If no, the smoothed value value is not changed and the filter counter is updated.
- * </p>
- * @param codeValue value of the input code measurement (non-smoothed)
- * @param smoothedValue the smoothed code value
- * @param cycleSlip true if cycle slip is detected
- * @return the smoothed or non-smoothed value depending if the filter must be reseted
- */
- protected double checkValidData(final double codeValue, final double smoothedValue, final boolean cycleSlip) {
- // Initialize the returned value to the smoothed value
- double validValue = smoothedValue;
- // This algorithm must be initialised every time that a carrier phase cycle slip occurs
- // Check if need to reset the filter
- if (resetNextBoolean || cycleSlip || FastMath.abs(smoothedValue - codeValue) > threshold) {
- // The smoothed value is updated to the non smoothed value, and reset the filter counter to 1
- resetK();
- validValue = codeValue;
- } else {
- // No reset, just increase the counter
- k = (k > N) ? N : k + 1;
- }
- // Return
- return validValue;
- }
- }