AbstractCycleSlipDetector.java
- /* Copyright 2002-2025 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.gnss;
- import java.util.ArrayList;
- import java.util.HashMap;
- import java.util.List;
- import java.util.Map;
- import org.orekit.files.rinex.observation.ObservationDataSet;
- import org.orekit.gnss.GnssSignal;
- import org.orekit.gnss.SatelliteSystem;
- import org.orekit.time.AbsoluteDate;
- /**
- * Base class for cycle-slip detectors.
- * @author David Soulard
- * @since 10.2
- */
- public abstract class AbstractCycleSlipDetector implements CycleSlipDetectors {
- /** Separator for satellite name. */
- private static final String SEPARATOR = " - ";
- /** Minimum number of measurement needed before being able to figure out cycle-slip occurrence.*/
- private final int minMeasurementNumber;
- /** Maximum time lapse between two measurements without considering a cycle-slip occurred [s]. */
- private final double dt;
- /** List which contains all the info regarding the cycle slip. */
- private final List<CycleSlipDetectorResults> data;
- /** List of all the things use for cycle-slip detections. */
- private final List<Map<GnssSignal, DataForDetection>> stuff;
- /**
- * Cycle-slip detector Abstract Constructor.
- * @param dt time gap between two consecutive measurements in seconds
- * (if time between two consecutive measurement is greater than dt, a cycle slip is declared)
- * @param n number of measures needed before starting test if a cycle-slip occurs
- */
- AbstractCycleSlipDetector(final double dt, final int n) {
- this.minMeasurementNumber = n;
- this.dt = dt;
- this.data = new ArrayList<>();
- this.stuff = new ArrayList<>();
- }
- /** {@inheritDoc} */
- @Override
- public List<CycleSlipDetectorResults> detect(final List<ObservationDataSet> observations) {
- // Loop on observation data set
- for (ObservationDataSet observation: observations) {
- // Manage data
- manageData(observation);
- }
- // Return the results of the cycle-slip detection
- return getResults();
- }
- /**
- * The method is in charge of collecting the measurements, manage them, and call the detection method.
- * @param observation observation data set
- */
- protected abstract void manageData(ObservationDataSet observation);
- /**
- * Get the minimum number of measurement needed before being able to figure out cycle-slip occurrence.
- * @return the minimum number of measurement needed before being able to figure out cycle-slip occurrence.
- */
- protected int getMinMeasurementNumber() {
- return minMeasurementNumber;
- }
- /**
- * Get the maximum time lapse between 2 measurements without considering a cycle-slip has occurring between both.
- * @return the maximum time lapse between 2 measurements
- */
- protected double getMaxTimeBeetween2Measurement() {
- return dt;
- }
- /**
- * Get on all the results computed by the detector (e.g.: dates of cycle-slip).
- * @return all the results computed by the detector (e.g.: dates of cycle-slip).
- */
- protected List<CycleSlipDetectorResults> getResults() {
- return data;
- }
- /**
- * Get the stuff (all the things needed for, the detector).
- * @return return stuff
- */
- protected List<Map<GnssSignal, DataForDetection>> getStuffReference() {
- return stuff;
- }
- /** Set the data: collect data at the current Date, at the current frequency, for a given satellite, add it within the attributes data and stuff.
- * @param nameSat name of the satellite (e.g. "GPS - 7")
- * @param date date of the measurement
- * @param value measurement at the current date
- * @param signal signal used
- */
- protected void cycleSlipDataSet(final String nameSat, final AbsoluteDate date,
- final double value, final GnssSignal signal) {
- // Check if cycle-slip data are empty
- if (data.isEmpty()) {
- data.add(new CycleSlipDetectorResults(nameSat, date, signal));
- final Map<GnssSignal, DataForDetection> newMap = new HashMap<>();
- newMap.put(signal, new DataForDetection(value, date));
- stuff.add(newMap);
- } else {
- if (!alreadyExist(nameSat, signal)) {
- // As the couple satellite-frequency, first possibility is that the satellite already exist within the data but not at this frequency
- for (CycleSlipDetectorResults r: data) {
- if (r.getSatelliteName().compareTo(nameSat) == 0) {
- r.addAtOtherFrequency(signal, date);
- final Map<GnssSignal, DataForDetection> newMap = stuff.get(data.indexOf(r));
- newMap.put(signal, new DataForDetection(value, date));
- stuff.set(data.indexOf(r), newMap);
- return;
- }
- }
- //If w've reach this point is because the name does not exist, in this case another element in the two list should be added
- data.add(new CycleSlipDetectorResults(nameSat, date, signal));
- final Map<GnssSignal, DataForDetection> newMap = new HashMap<>();
- newMap.put(signal, new DataForDetection(value, date));
- stuff.add(newMap);
- } else {
- // We add the value of the combination of measurements
- addValue(nameSat, date, value, signal);
- }
- }
- }
- /**
- * Create the name of a satellite from its PRN number and satellite System it belongs to.
- * @param numSat satellite PRN number
- * @param sys Satellite System of the satellite
- * @return the satellite name on a specified format (e.g.: "GPS - 7")
- */
- protected String setName(final int numSat, final SatelliteSystem sys) {
- return sys.name() + SEPARATOR + numSat;
- }
- /**
- * Return true if the link (defined by a frequency and a satellite) has been already built.
- * @param nameSat name of the satellite (e.g.: GPS - 07 for satelite 7 of GPS constellation).
- * @param signal signal used in the link
- * @return true if it already exists within attribute data
- */
- private boolean alreadyExist(final String nameSat, final GnssSignal signal) {
- if (data != null) {
- for (CycleSlipDetectorResults result: data) {
- if (result.getSatelliteName().compareTo(nameSat) == 0) {
- return result.getCycleSlipMap().containsKey(signal);
- }
- }
- }
- return false;
- }
- /**
- * Add a value the data.
- * @param nameSat name of the satellite (satellite system - PRN)
- * @param date date of the measurement
- * @param value phase measurement minus code measurement
- * @param signal signal used
- */
- private void addValue(final String nameSat, final AbsoluteDate date,
- final double value, final GnssSignal signal) {
- // Loop on cycle-slip data
- for (CycleSlipDetectorResults result: data) {
- // Find the good position to add the data
- if (result.getSatelliteName().compareTo(nameSat) == 0 && result.getCycleSlipMap().containsKey(signal)) {
- // The date is not to far away from the last one
- final Map<GnssSignal, DataForDetection> valuesMap = stuff.get(data.indexOf(result));
- final DataForDetection detect = valuesMap.get(signal);
- detect.write = (detect.write + 1) % minMeasurementNumber;
- detect.figures[detect.write] = new SlipComputationData(value, date);
- result.setDate(signal, date);
- detect.canBeComputed++;
- break;
- }
- }
- }
- /**
- * Container for computed if cycle-slip occurs.
- * @author David Soulard
- */
- static class SlipComputationData {
- /** Value of the measurement. */
- private final double value;
- /** Date of measurement. */
- private final AbsoluteDate date;
- /**
- * Simple constructor.
- * @param value value of the measurement
- * @param date date of the measurement
- */
- SlipComputationData(final double value, final AbsoluteDate date) {
- this.value = value;
- this.date = date;
- }
- /**
- * Get the value of the measurement.
- * @return value of the measurement
- */
- protected double getValue() {
- return value;
- }
- /**
- * Get the date of measurement saved within this.
- * @return date of measurement saved within this
- */
- protected AbsoluteDate getDate() {
- return date;
- }
- }
- /**
- * Container for all the data need for doing cycle-slip detection.
- * @author David Soulard
- */
- class DataForDetection {
- /** Array used to compute cycle slip. */
- private SlipComputationData[] figures;
- /** Integer to make the array above circular. */
- private int write;
- /** Integer to know how many data have been added since last cycle-slip. */
- private int canBeComputed;
- /**
- * Constructor.
- * @param value measurement
- * @param date date at which measurements are taken.
- */
- DataForDetection(final double value, final AbsoluteDate date) {
- this.figures = new SlipComputationData[minMeasurementNumber];
- this.figures[0] = new SlipComputationData(value, date);
- this.canBeComputed = 1;
- this.write = 0;
- }
- /**
- * Get the array of values used for computation of cycle-slip detectors.
- * @return SlipComputationDatat array
- */
- protected SlipComputationData[] getFiguresReference() {
- return figures;
- }
- /**
- * Get the reference of the counter of position into the array.
- * @return the position on which writing should occur within the circular array figures.
- */
- protected int getWrite() {
- return write;
- }
- /**
- * Get the counter on the number of measurement which have been saved up to the current date.
- * @return the number of measurement which have been saved up to the current date
- */
- protected int getCanBeComputed() {
- return canBeComputed;
- }
- /**
- * Reset this to the initial value when a cycle slip occurs.
- * The first element is already setting with a value and a date
- * @param newF new SlipComputationData[] to be used within the detector
- * @param value to be added in the first element of the array
- * @param date at which the value is given.
- */
- protected void resetFigures(final SlipComputationData[] newF, final double value, final AbsoluteDate date) {
- this.figures = newF;
- this.figures[0] = new SlipComputationData(value, date);
- this.write = 0;
- this.canBeComputed = 1;
- }
- }
- }