SingleFrequencySmoother.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 java.util.HashMap;
  20. import java.util.List;

  21. import org.orekit.files.rinex.observation.ObservationData;
  22. import org.orekit.files.rinex.observation.ObservationDataSet;
  23. import org.orekit.gnss.MeasurementType;
  24. import org.orekit.gnss.ObservationType;
  25. import org.orekit.gnss.SatelliteSystem;
  26. import org.orekit.time.ChronologicalComparator;

  27. /**
  28.  * Handler to perform pseudo-range smoothing using single frequency measurements.
  29.  *
  30.  * @author Louis Aucouturier
  31.  * @since 11.2
  32.  */
  33. public class SingleFrequencySmoother {

  34.     /** Window size for the hatch filter. */
  35.     private int N;

  36.     /** Interval time between two measurements.*/
  37.     private double integrationTime;

  38.     /** Threshold for the difference between smoothed and measured values. */
  39.     private double threshold;

  40.     /** Type of the smoothing measurements. */
  41.     private MeasurementType type;

  42.     /**
  43.      * Map storing the filters for each observation type.
  44.      * Observation types should not overlap for a single RINEX file.
  45.      */
  46.     private HashMap<ObservationType, SingleFrequencyHatchFilter> mapFilters;

  47.     /**
  48.      * Map storing the filtered data for each pseudo range.
  49.      * The data is stored in the form of a list of ObservationDataSetUpdate, which itself
  50.      * stores a pseudo-range ObservationData object with the filtered value, and the initial ObservationDataSet,
  51.      * needed for further processing.
  52.      */
  53.     private HashMap<ObservationType, List<SmoothedObservationDataSet>> mapFilteredData;

  54.     /**
  55.      * Simple constructor.
  56.      * @param type            type of the smoothing measurements
  57.      * @param threshold       threshold for loss of lock detection
  58.      *                        (represents the maximum difference between smoothed
  59.      *                        and measured values for loss of lock detection)
  60.      * @param N               window size of the Hatch Filter
  61.      * @param integrationTime time interval between two measurements (s)
  62.      */
  63.     public SingleFrequencySmoother(final MeasurementType type,
  64.                                    final double threshold, final int N,
  65.                                    final double integrationTime) {
  66.         this.mapFilteredData = new HashMap<>();
  67.         this.mapFilters      = new HashMap<>();
  68.         this.type            = type;
  69.         this.N               = N;
  70.         this.integrationTime = integrationTime;
  71.         this.threshold       = threshold;
  72.     }

  73.     /**
  74.      * Creates an Hatch filter given initial data.
  75.      * @param codeData      input code observation data
  76.      * @param smoothingData input smoothing observation data
  77.      * @param system        satellite system corresponding to the observations
  78.      * @return an Hatch filter for the input data
  79.      */
  80.     public SingleFrequencyHatchFilter createFilter(final ObservationData codeData,
  81.                                                    final ObservationData smoothingData,
  82.                                                    final SatelliteSystem system) {
  83.         // Wavelength in meters
  84.         final double wavelength = smoothingData.getObservationType().getFrequency(system).getWavelength();
  85.         // Return a Single Frequency Hatch Filter
  86.         return new SingleFrequencyHatchFilter(codeData, smoothingData, type, wavelength, threshold, N, integrationTime);
  87.     }

  88.     /**
  89.      * Get the map of the filtered data.
  90.      * @return a map containing the filtered data.
  91.      */
  92.     public HashMap<ObservationType, List<SmoothedObservationDataSet>> getFilteredDataMap() {
  93.         return mapFilteredData;
  94.     }

  95.     /**
  96.      * Get the map storing the filters for each observation type.
  97.      * @return the map storing the filters for each observation type
  98.      */
  99.     public final HashMap<ObservationType, SingleFrequencyHatchFilter> getMapFilters() {
  100.         return mapFilters;
  101.     }

  102.     /**
  103.      * Copy an ObservationData object.
  104.      * @param obsData observation data to copy
  105.      * @return a copy of the input observation data
  106.      */
  107.     public ObservationData copyObservationData(final ObservationData obsData) {
  108.         return new ObservationData(obsData.getObservationType(), obsData.getValue(),
  109.                                    obsData.getLossOfLockIndicator(), obsData.getSignalStrength());
  110.     }

  111.     /**
  112.      * Applies a Single Frequency Hatch filter to a list of {@link ObservationDataSet}.
  113.      * @param listODS   input observation data sets
  114.      * @param satSystem satellite System from which to filter the pseudo-range values
  115.      * @param prnNumber PRN identifier to identify the satellite from which to filter the pseudo-range values
  116.      * @param obsType   observation type to use for filtering
  117.      */
  118.     public void filterDataSet(final List<ObservationDataSet> listODS, final SatelliteSystem satSystem,
  119.                               final int prnNumber, final ObservationType obsType) {

  120.         // Sort the list in chronological way to ensure the filter work on time ordered data.
  121.         final List<ObservationDataSet> sortedListODS = new ArrayList<>(listODS);
  122.         sortedListODS.sort(new ChronologicalComparator());

  123.         // For each data set, work on those corresponding to the PRN and Satellite system.
  124.         for (ObservationDataSet obsSet : sortedListODS) {
  125.             if (obsSet.getSatellite().getSystem() == satSystem  && obsSet.getSatellite().getPRN() == prnNumber) {
  126.                 // Get all observation data
  127.                 final List<ObservationData> listObsData = obsSet.getObservationData();
  128.                 // For each ObservationData check if usable (SNR and !(isNaN))
  129.                 for (final ObservationData obsData : listObsData) {
  130.                     final double snr = obsData.getSignalStrength();
  131.                     if (!Double.isNaN(obsData.getValue()) && (snr == 0 || snr >= 4)) {

  132.                         // Check measurement type, and if range check for the chosen smooting measurement
  133.                         final ObservationType obsTypeData = obsData.getObservationType();
  134.                         if (obsTypeData.getMeasurementType() == MeasurementType.PSEUDO_RANGE) {

  135.                             ObservationData obsDataSmoothing = null;

  136.                             for (final ObservationData obsDataSmoothingCurr : listObsData) {

  137.                                 // Iterate to find the required smoothing measurement corresponding to the observationType.
  138.                                 // Then copy the observation data to store them.
  139.                                 final ObservationType obsTypeSmoothingCurr = obsDataSmoothingCurr.getObservationType();

  140.                                 if (!Double.isNaN(obsDataSmoothingCurr.getValue()) && obsTypeSmoothingCurr == obsType) {
  141.                                     obsDataSmoothing = copyObservationData(obsDataSmoothingCurr);
  142.                                 }

  143.                             }

  144.                             // Check if the filter exist in the filter map
  145.                             SingleFrequencyHatchFilter filterObject = mapFilters.get(obsTypeData);

  146.                             // If the filter does not exist and the phase object are not null, initialize a new filter and
  147.                             // store it in the map, initialize a new list of observationDataSetUpdate, and store it in the map.
  148.                             if (filterObject == null && obsDataSmoothing != null) {
  149.                                 filterObject = createFilter(obsData, obsDataSmoothing, satSystem);
  150.                                 mapFilters.put(obsTypeData, filterObject);
  151.                                 final List<SmoothedObservationDataSet> odList = new ArrayList<>();
  152.                                 odList.add(new SmoothedObservationDataSet(obsData, obsSet));
  153.                                 mapFilteredData.put(obsTypeData, odList);
  154.                             // If filter exist, check if a phase object is null, then reset the filter at the next step,
  155.                             // else, filter the data.
  156.                             } else if (filterObject != null) {
  157.                                 if (obsDataSmoothing == null ) {
  158.                                     filterObject.resetFilterNext(obsData.getValue());
  159.                                 } else {
  160.                                     final ObservationData filteredRange = filterObject.filterData(obsData, obsDataSmoothing);
  161.                                     mapFilteredData.get(obsTypeData).add(new SmoothedObservationDataSet(filteredRange, obsSet));
  162.                                 }
  163.                             } else {
  164.                                 // IF the filter does not exist and one of the phase is equal to NaN or absent
  165.                                 // just skip to the next ObservationDataSet.
  166.                             }

  167.                         }
  168.                     }
  169.                 }
  170.             }
  171.         }
  172.     }

  173. }