CRD.java

  1. /* Copyright 2002-2022 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.files.ilrs;

  18. import java.util.ArrayList;
  19. import java.util.Collections;
  20. import java.util.List;
  21. import java.util.SortedSet;
  22. import java.util.TreeSet;
  23. import java.util.stream.Collectors;

  24. import org.orekit.time.AbsoluteDate;
  25. import org.orekit.time.ChronologicalComparator;
  26. import org.orekit.time.TimeStamped;
  27. import org.orekit.utils.ImmutableTimeStampedCache;

  28. /**
  29.  * This class stores all the information of the Consolidated laser ranging Data Format (CRD) parsed
  30.  * by CRDParser. It contains the header and a list of data records.
  31.  * @author Bryan Cazabonne
  32.  * @since 10.3
  33.  */
  34. public class CRD {

  35.     /** List of comments contained in the file. */
  36.     private List<String> comments;

  37.     /** List of data blocks contain in the CDR file. */
  38.     private List<CRDDataBlock> dataBlocks;

  39.     /**
  40.      * Constructor.
  41.      */
  42.     public CRD() {
  43.         // Initialise empty lists
  44.         this.comments   = new ArrayList<>();
  45.         this.dataBlocks = new ArrayList<>();
  46.     }

  47.     /**
  48.      * Add a data block to the current list of data blocks.
  49.      * @param dataBlock data block to add
  50.      */
  51.     public void addDataBlock(final CRDDataBlock dataBlock) {
  52.         dataBlocks.add(dataBlock);
  53.     }

  54.     /**
  55.      * Get the comments contained in the file.
  56.      * @return the comments contained in the file
  57.      */
  58.     public List<String> getComments() {
  59.         return comments;
  60.     }

  61.     /**
  62.      * Get the data blocks contain in the file.
  63.      * @return the data blocks contain in the file
  64.      */
  65.     public List<CRDDataBlock> getDataBlocks() {
  66.         return Collections.unmodifiableList(dataBlocks);
  67.     }

  68.     /**
  69.      * Data block containing a set of data contain in the CRD file.
  70.      * <p>
  71.      * A data block consists of a header, configuration data and
  72.      * recorded data (range, angles, meteorological, etc.).
  73.      * </p>
  74.      */
  75.     public static class CRDDataBlock {

  76.         /** Data block header. */
  77.         private CRDHeader header;

  78.         /** Configuration record. */
  79.         private CRDConfiguration configurationRecords;

  80.         /** Range records. */
  81.         private List<RangeMeasurement> rangeData;

  82.         /** Meteorological records. */
  83.         private final SortedSet<MeteorologicalMeasurement> meteoData;

  84.         /** Pointing angles records. */
  85.         private List<AnglesMeasurement> anglesData;

  86.         /**
  87.          * Constructor.
  88.          */
  89.         public CRDDataBlock() {
  90.             // Initialise empty lists
  91.             this.rangeData  = new ArrayList<>();
  92.             this.meteoData  = new TreeSet<>(new ChronologicalComparator());
  93.             this.anglesData = new ArrayList<>();
  94.         }

  95.         /**
  96.          * Get the header of the current data block.
  97.          * @return the header of the current data block
  98.          */
  99.         public CRDHeader getHeader() {
  100.             return header;
  101.         }

  102.         /**
  103.          * Set the header for the current data block.
  104.          * @param header the header to set
  105.          */
  106.         public void setHeader(final CRDHeader header) {
  107.             this.header = header;
  108.         }

  109.         /**
  110.          * Get the system configuration records.
  111.          * @return the system configuration records
  112.          */
  113.         public CRDConfiguration getConfigurationRecords() {
  114.             return configurationRecords;
  115.         }

  116.         /**
  117.          * Set the configuration records for the current data block.
  118.          * @param configurationRecords the configuration records to set
  119.          */
  120.         public void setConfigurationRecords(final CRDConfiguration configurationRecords) {
  121.             this.configurationRecords = configurationRecords;
  122.         }

  123.         /**
  124.          * Add an entry to the list of range data.
  125.          * @param range entry to add
  126.          */
  127.         public void addRangeData(final RangeMeasurement range) {
  128.             rangeData.add(range);
  129.         }

  130.         /**
  131.          * Add an entry to the list of meteorological data.
  132.          * @param meteorologicalMeasurement entry to add
  133.          */
  134.         public void addMeteoData(final MeteorologicalMeasurement meteorologicalMeasurement) {
  135.             meteoData.add(meteorologicalMeasurement);
  136.         }

  137.         /**
  138.          * Add an entry to the list of angles data.
  139.          * @param angles entry to add
  140.          */
  141.         public void addAnglesData(final AnglesMeasurement angles) {
  142.             anglesData.add(angles);
  143.         }

  144.         /**
  145.          * Get the range data for the data block.
  146.          * @return an unmodifiable list of range data
  147.          */
  148.         public List<RangeMeasurement> getRangeData() {
  149.             return Collections.unmodifiableList(rangeData);
  150.         }

  151.         /**
  152.          * Get the angles data for the data block.
  153.          * @return an unmodifiable list of angles data
  154.          */
  155.         public List<AnglesMeasurement> getAnglesData() {
  156.             return Collections.unmodifiableList(anglesData);
  157.         }

  158.         /**
  159.          * Get the meteorological data for the data block.
  160.          * @return an unmodifiable list of meteorological data
  161.          */
  162.         public Meteo getMeteoData() {
  163.             return new Meteo(meteoData);
  164.         }

  165.     }

  166.     /** Range record. */
  167.     public static class RangeMeasurement implements TimeStamped {

  168.         /** Data epoch. */
  169.         private AbsoluteDate date;

  170.         /** Time of flight [s]. */
  171.         private final double timeOfFlight;

  172.         /** Time event reference indicator.
  173.          * 0 = ground receive time (at SRP) (two-way)
  174.          * 1 = spacecraft bounce time (two-way)
  175.          * 2 = ground transmit time (at SRP) (two-way)
  176.          * 3 = spacecraft receive time (one-way)
  177.          * 4 = spacecraft transmit time (one-way)
  178.          * 5 = ground transmit time (at SRP) and spacecraft receive time (one-way)
  179.          * 6 = spacecraft transmit time and ground receive time (at SRP) (one-way)
  180.          * Currently, only 1 and 2 are used for laser ranging data.
  181.          */
  182.         private final int epochEvent;

  183.         /** Signal to noise ration. */
  184.         private final double snr;

  185.         /**
  186.          * Constructor.
  187.          * @param date data epoch
  188.          * @param timeOfFlight time of flight in seconds
  189.          * @param epochEvent indicates the time event reference
  190.          */
  191.         public RangeMeasurement(final AbsoluteDate date,
  192.                                 final double timeOfFlight,
  193.                                 final int epochEvent) {
  194.             this(date, timeOfFlight, epochEvent, Double.NaN);
  195.         }

  196.         /**
  197.          * Constructor.
  198.          * @param date data epoch
  199.          * @param timeOfFlight time of flight in seconds
  200.          * @param epochEvent indicates the time event reference
  201.          * @param snr signal to noise ratio (can be Double.NaN if unkonwn)
  202.          */
  203.         public RangeMeasurement(final AbsoluteDate date,
  204.                                 final double timeOfFlight,
  205.                                 final int epochEvent, final double snr) {
  206.             this.date         = date;
  207.             this.timeOfFlight = timeOfFlight;
  208.             this.epochEvent   = epochEvent;
  209.             this.snr          = snr;
  210.         }

  211.         /**
  212.          * Get the time-of-flight.
  213.          * @return the time-of-flight in seconds
  214.          */
  215.         public double getTimeOfFlight() {
  216.             return timeOfFlight;
  217.         }

  218.         /**
  219.          * Get the indicator for the time event reference.
  220.          * <ul>
  221.          * <li>0 = ground receive time (at SRP) (two-way)</li>
  222.          * <li>1 = spacecraft bounce time (two-way)</li>
  223.          * <li>2 = ground transmit time (at SRP) (two-way)</li>
  224.          * <li>3 = spacecraft receive time (one-way)</li>
  225.          * <li>4 = spacecraft transmit time (one-way)</li>
  226.          * <li>5 = ground transmit time (at SRP) and spacecraft receive time (one-way)</li>
  227.          * <li>6 = spacecraft transmit time and ground receive time (at SRP) (one-way)</li>
  228.          * </ul>
  229.          * Currently, only 1 and 2 are used for laser ranging data
  230.          * @return the indicator for the time event reference
  231.          */
  232.         public int getEpochEvent() {
  233.             return epochEvent;
  234.         }

  235.         /**
  236.          * Get the signal to noise ratio.
  237.          * @return the signal to noise ratio
  238.          */
  239.         public double getSnr() {
  240.             return snr;
  241.         }

  242.         /** {@inheritDoc} */
  243.         @Override
  244.         public AbsoluteDate getDate() {
  245.             return date;
  246.         }

  247.     }

  248.     /** This data record contains a minimal set of meteorological data. */
  249.     public static class MeteorologicalMeasurement implements TimeStamped {

  250.         /** Data epoch. */
  251.         private AbsoluteDate date;

  252.         /** Surface pressure [bar]. */
  253.         private final double pressure;

  254.         /** Surface temperature [K]. */
  255.         private final double temperature;

  256.         /** Relative humidity at the surface [%]. */
  257.         private final double humidity;

  258.         /**
  259.          * Constructor.
  260.          * @param date data epoch
  261.          * @param pressure the surface pressure in bars
  262.          * @param temperature the surface temperature in degrees Kelvin
  263.          * @param humidity the relative humidity at the surface in percents
  264.          */
  265.         public MeteorologicalMeasurement(final AbsoluteDate date,
  266.                                          final double pressure, final double temperature,
  267.                                          final double humidity) {
  268.             this.date        = date;
  269.             this.pressure    = pressure;
  270.             this.temperature = temperature;
  271.             this.humidity    = humidity;
  272.         }

  273.         /**
  274.          * Get the surface pressure.
  275.          * @return the surface pressure in bars
  276.          */
  277.         public double getPressure() {
  278.             return pressure;
  279.         }

  280.         /**
  281.          * Get the surface temperature.
  282.          * @return the surface temperature in degrees Kelvin
  283.          */
  284.         public double getTemperature() {
  285.             return temperature;
  286.         }

  287.         /**
  288.          * Get the relative humidity at the surface.
  289.          * @return the relative humidity at the surface in percents
  290.          */
  291.         public double getHumidity() {
  292.             return humidity;
  293.         }

  294.         /** {@inheritDoc} */
  295.         @Override
  296.         public AbsoluteDate getDate() {
  297.             return date;
  298.         }

  299.     }

  300.     /** Pointing angles record. */
  301.     public static class AnglesMeasurement implements TimeStamped {

  302.         /** Data epoch. */
  303.         private AbsoluteDate date;

  304.         /** Azimuth [rad]. */
  305.         private final double azimuth;

  306.         /** Elevation [rad]. */
  307.         private final double elevation;

  308.         /** Direction flag (0 = transmit &#38; receive ; 1 = transmit ; 2 = receive). */
  309.         private final int directionFlag;

  310.         /** Angle origin indicator.
  311.          * 0 = unknown
  312.          * 1 = computed
  313.          * 2 = commanded (from predictions)
  314.          * 3 = measured (from encoders)
  315.          */
  316.         private final int originIndicator;

  317.         /** Refraction corrected. */
  318.         private final boolean refractionCorrected;

  319.         /** Azimuth rate [rad/sec]. */
  320.         private final double azimuthRate;

  321.         /** Elevation rate [rad/sec]. */
  322.         private final double elevationRate;

  323.         /**
  324.          * Constructor.
  325.          * @param date data epoch
  326.          * @param azimuth azimuth angle in radians
  327.          * @param elevation elevation angle in radians
  328.          * @param directionFlag direction flag
  329.          * @param originIndicator angle origin indicator
  330.          * @param refractionCorrected flag to indicate if the refraction is corrected
  331.          * @param azimuthRate azimuth rate in radians per second (equal to Double.NaN if unknown)
  332.          * @param elevationRate elevation rate in radians per second (equal to Double.NaN if unknown)
  333.          */
  334.         public AnglesMeasurement(final AbsoluteDate date, final double azimuth,
  335.                                  final double elevation, final int directionFlag,
  336.                                  final int originIndicator,
  337.                                  final boolean refractionCorrected,
  338.                                  final double azimuthRate, final double elevationRate) {
  339.             this.date                = date;
  340.             this.azimuth             = azimuth;
  341.             this.elevation           = elevation;
  342.             this.directionFlag       = directionFlag;
  343.             this.originIndicator     = originIndicator;
  344.             this.refractionCorrected = refractionCorrected;
  345.             this.azimuthRate         = azimuthRate;
  346.             this.elevationRate       = elevationRate;
  347.         }

  348.         /**
  349.          * Get the azimuth angle.
  350.          * @return the azimuth angle in radians
  351.          */
  352.         public double getAzimuth() {
  353.             return azimuth;
  354.         }

  355.         /**
  356.          * Get the elevation angle.
  357.          * @return the elevation angle in radians
  358.          */
  359.         public double getElevation() {
  360.             return elevation;
  361.         }

  362.         /**
  363.          * Get the direction flag (0 = transmit &#38; receive ; 1 = transmit ; 2 = receive).
  364.          * @return the direction flag
  365.          */
  366.         public int getDirectionFlag() {
  367.             return directionFlag;
  368.         }

  369.         /**
  370.          * Get the angle origin indicator.
  371.          * <p>
  372.          * 0 = unknown;
  373.          * 1 = computed;
  374.          * 2 = commanded (from predictions);
  375.          * 3 = measured (from encoders)
  376.          * </p>
  377.          * @return the angle origin indicator
  378.          */
  379.         public int getOriginIndicator() {
  380.             return originIndicator;
  381.         }

  382.         /**
  383.          * Get the flag indicating if the refraction is corrected.
  384.          * @return true if refraction is corrected
  385.          */
  386.         public boolean isRefractionCorrected() {
  387.             return refractionCorrected;
  388.         }

  389.         /**
  390.          * Get the azimuth rate.
  391.          * <p>
  392.          * Is equal to Double.NaN if the value is unknown.
  393.          * </p>
  394.          * @return the azimuth rate in radians per second
  395.          */
  396.         public double getAzimuthRate() {
  397.             return azimuthRate;
  398.         }

  399.         /**
  400.          * Get the elevation rate.
  401.          * <p>
  402.          * Is equal to Double.NaN if the value is unknown.
  403.          * </p>
  404.          * @return the elevation rate in radians per second
  405.          */
  406.         public double getElevationRate() {
  407.             return elevationRate;
  408.         }

  409.         /** {@inheritDoc} */
  410.         @Override
  411.         public AbsoluteDate getDate() {
  412.             return date;
  413.         }

  414.     }

  415.     /** Meteorological data. */
  416.     public static class Meteo {

  417.         /** Number of neighbors for meteo data interpolation. */
  418.         private static final int N_NEIGHBORS = 2;

  419.         /** First available date. */
  420.         private final AbsoluteDate firstDate;

  421.         /** Last available date. */
  422.         private final AbsoluteDate lastDate;

  423.         /** Previous set of meteorological parameters. */
  424.         private transient MeteorologicalMeasurement previousParam;

  425.         /** Next set of solar meteorological parameters. */
  426.         private transient MeteorologicalMeasurement nextParam;

  427.         /** List of meteo data. */
  428.         private final transient ImmutableTimeStampedCache<MeteorologicalMeasurement> meteo;

  429.         /**
  430.          * Constructor.
  431.          * @param meteoData list of meteo data
  432.          */
  433.         public Meteo(final SortedSet<MeteorologicalMeasurement> meteoData) {

  434.             // Size
  435.             final int neighborsSize = (meteoData.size() < 2) ? meteoData.size() : N_NEIGHBORS;

  436.             // Check neighbors size
  437.             if (neighborsSize == 0) {

  438.                 // Meteo data -> empty cache
  439.                 this.meteo = ImmutableTimeStampedCache.emptyCache();

  440.                 // Null epochs (will ne be used)
  441.                 this.firstDate = null;
  442.                 this.lastDate  = null;

  443.             } else {

  444.                 // Meteo data
  445.                 this.meteo = new ImmutableTimeStampedCache<MeteorologicalMeasurement>(neighborsSize, meteoData);

  446.                 // Initialize first and last available dates
  447.                 this.firstDate = meteoData.first().getDate();
  448.                 this.lastDate  = meteoData.last().getDate();

  449.             }

  450.         }

  451.         /** Get an unmodifiable view of the tabulated meteorological data.
  452.          * @return unmodifiable view of the tabulated meteorological data
  453.          * @since 11.0
  454.          */
  455.         public List<MeteorologicalMeasurement> getData() {
  456.             return meteo.getAll();
  457.         }

  458.         /**
  459.          * Get the meteorological parameters at a given date.
  460.          * @param date date when user wants the meteorological parameters
  461.          * @return the meteorological parameters at date (can be null if
  462.          *         meteorological data are empty).
  463.          */
  464.         public MeteorologicalMeasurement getMeteo(final AbsoluteDate date) {

  465.             // Check if meteorological data are available
  466.             if (meteo.getNeighborsSize() == 0) {
  467.                 return null;
  468.             }

  469.             // Interpolating two neighboring meteorological parameters
  470.             bracketDate(date);
  471.             if (date.durationFrom(firstDate) <= 0 || date.durationFrom(lastDate) > 0) {
  472.                 // Date is outside file range
  473.                 return previousParam;
  474.             } else {
  475.                 // Perform interpolations
  476.                 final double pressure    = getLinearInterpolation(date, previousParam.getPressure(), nextParam.getPressure());
  477.                 final double temperature = getLinearInterpolation(date, previousParam.getTemperature(), nextParam.getTemperature());
  478.                 final double humidity    = getLinearInterpolation(date, previousParam.getHumidity(), nextParam.getHumidity());
  479.                 return new MeteorologicalMeasurement(date, pressure, temperature, humidity);
  480.             }

  481.         }

  482.         /**
  483.          * Find the data bracketing a specified date.
  484.          * @param date date to bracket
  485.          */
  486.         private void bracketDate(final AbsoluteDate date) {

  487.             // don't search if the cached selection is fine
  488.             if (previousParam != null &&
  489.                 date.durationFrom(previousParam.getDate()) > 0 &&
  490.                 date.durationFrom(nextParam.getDate()) <= 0) {
  491.                 return;
  492.             }

  493.             // Initialize previous and next parameters
  494.             if (date.durationFrom(firstDate) <= 0) {
  495.                 // Current date is before the first date
  496.                 previousParam = meteo.getEarliest();
  497.                 nextParam     = previousParam;
  498.             } else if (date.durationFrom(lastDate) > 0) {
  499.                 // Current date is after the last date
  500.                 previousParam = meteo.getLatest();
  501.                 nextParam     = previousParam;
  502.             } else {
  503.                 // Current date is between first and last date
  504.                 final List<MeteorologicalMeasurement> neighbors = meteo.getNeighbors(date).collect(Collectors.toList());
  505.                 previousParam = neighbors.get(0);
  506.                 nextParam     = neighbors.get(1);
  507.             }

  508.         }

  509.         /**
  510.          * Performs a linear interpolation between two values The weights are computed
  511.          * from the time delta between previous date, current date, next date.
  512.          * @param date the current date
  513.          * @param previousValue the value at previous date
  514.          * @param nextValue the value at next date
  515.          * @return the value interpolated for the current date
  516.          */
  517.         private double getLinearInterpolation(final AbsoluteDate date,
  518.                                               final double previousValue,
  519.                                               final double nextValue) {
  520.             // Perform a linear interpolation
  521.             final AbsoluteDate previousDate = previousParam.getDate();
  522.             final AbsoluteDate currentDate = nextParam.getDate();
  523.             final double dt = currentDate.durationFrom(previousDate);
  524.             final double previousWeight = currentDate.durationFrom(date) / dt;
  525.             final double nextWeight = date.durationFrom(previousDate) / dt;

  526.             // Returns the data interpolated at the date
  527.             return previousValue * previousWeight + nextValue * nextWeight;
  528.         }

  529.     }

  530. }