Range.java

  1. /* Copyright 2002-2025 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;

  18. import java.util.Arrays;

  19. import org.hipparchus.analysis.differentiation.Gradient;
  20. import org.orekit.propagation.SpacecraftState;
  21. import org.orekit.time.AbsoluteDate;
  22. import org.orekit.utils.Constants;
  23. import org.orekit.utils.ParameterDriver;
  24. import org.orekit.utils.TimeSpanMap.Span;
  25. import org.orekit.utils.TimeStampedFieldPVCoordinates;
  26. import org.orekit.utils.TimeStampedPVCoordinates;

  27. /** Class modeling a range measurement from a ground station.
  28.  * <p>
  29.  * For one-way measurements, a signal is emitted by the satellite
  30.  * and received by the ground station. The measurement value is the
  31.  * elapsed time between emission and reception multiplied by c where
  32.  * c is the speed of light.
  33.  * </p>
  34.  * <p>
  35.  * For two-way measurements, the measurement is considered to be a signal
  36.  * emitted from a ground station, reflected on spacecraft, and received
  37.  * on the same ground station. Its value is the elapsed time between
  38.  * emission and reception multiplied by c/2 where c is the speed of light.
  39.  * </p>
  40.  * <p>
  41.  * The motion of both the station and the spacecraft during the signal
  42.  * flight time are taken into account. The date of the measurement
  43.  * corresponds to the reception on ground of the emitted or reflected signal.
  44.  * </p>
  45.  * <p>
  46.  * The clock offsets of both the ground station and the satellite are taken
  47.  * into account. These offsets correspond to the values that must be subtracted
  48.  * from station (resp. satellite) reading of time to compute the real physical
  49.  * date. These offsets have two effects:
  50.  * </p>
  51.  * <ul>
  52.  *   <li>as measurement date is evaluated at reception time, the real physical date
  53.  *   of the measurement is the observed date to which the receiving ground station
  54.  *   clock offset is subtracted</li>
  55.  *   <li>as range is evaluated using the total signal time of flight, for one-way
  56.  *   measurements the observed range is the real physical signal time of flight to
  57.  *   which (Δtg - Δts) ⨯ c is added, where Δtg (resp. Δts) is the clock offset for the
  58.  *   receiving ground station (resp. emitting satellite). A similar effect exists in
  59.  *   two-way measurements but it is computed as (Δtg - Δtg) ⨯ c / 2 as the same ground
  60.  *   station clock is used for initial emission and final reception and therefore it evaluates
  61.  *   to zero.</li>
  62.  * </ul>
  63.  * @author Thierry Ceolin
  64.  * @author Luc Maisonobe
  65.  * @author Maxime Journot
  66.  * @since 8.0
  67.  */
  68. public class Range extends GroundReceiverMeasurement<Range> {

  69.     /** Type of the measurement. */
  70.     public static final String MEASUREMENT_TYPE = "Range";

  71.     /** Simple constructor.
  72.      * @param station ground station from which measurement is performed
  73.      * @param twoWay flag indicating whether it is a two-way measurement
  74.      * @param date date of the measurement
  75.      * @param range observed value
  76.      * @param sigma theoretical standard deviation
  77.      * @param baseWeight base weight
  78.      * @param satellite satellite related to this measurement
  79.      * @since 9.3
  80.      */
  81.     public Range(final GroundStation station, final boolean twoWay, final AbsoluteDate date,
  82.                  final double range, final double sigma, final double baseWeight,
  83.                  final ObservableSatellite satellite) {
  84.         super(station, twoWay, date, range, sigma, baseWeight, satellite);
  85.     }

  86.     /** {@inheritDoc} */
  87.     @Override
  88.     protected EstimatedMeasurementBase<Range> theoreticalEvaluationWithoutDerivatives(final int iteration,
  89.                                                                                       final int evaluation,
  90.                                                                                       final SpacecraftState[] states) {

  91.         final GroundReceiverCommonParametersWithoutDerivatives common = computeCommonParametersWithout(states[0]);
  92.         final TimeStampedPVCoordinates transitPV = common.getTransitState().getPVCoordinates();

  93.         // prepare the evaluation
  94.         final EstimatedMeasurementBase<Range> estimated;
  95.         final double range;

  96.         if (isTwoWay()) {

  97.             // Station at transit state date (derivatives of tauD taken into account)
  98.             final TimeStampedPVCoordinates stationAtTransitDate = common.getStationDownlink().shiftedBy(-common.getTauD());
  99.             // Uplink delay
  100.             final double tauU = signalTimeOfFlightAdjustableEmitter(stationAtTransitDate, transitPV.getPosition(),
  101.                                                                     transitPV.getDate(), common.getState().getFrame());
  102.             final TimeStampedPVCoordinates stationUplink = common.getStationDownlink().shiftedBy(-common.getTauD() - tauU);

  103.             // Prepare the evaluation
  104.             estimated = new EstimatedMeasurementBase<>(this, iteration, evaluation,
  105.                                                         new SpacecraftState[] {
  106.                                                             common.getTransitState()
  107.                                                         }, new TimeStampedPVCoordinates[] {
  108.                                                             stationUplink,
  109.                                                             transitPV,
  110.                                                             common.getStationDownlink()
  111.                                                         });

  112.             // Range value
  113.             final double cOver2 = 0.5 * Constants.SPEED_OF_LIGHT;
  114.             final double tau    = common.getTauD() + tauU;
  115.             range               = tau * cOver2;

  116.         } else {

  117.             estimated = new EstimatedMeasurementBase<>(this, iteration, evaluation,
  118.                                                        new SpacecraftState[] {
  119.                                                            common.getTransitState()
  120.                                                        }, new TimeStampedPVCoordinates[] {
  121.                                                            transitPV,
  122.                                                            common.getStationDownlink()
  123.                                                        });

  124.             // Clock offsets
  125.             final ObservableSatellite satellite = getSatellites().get(0);
  126.             final double              dts       = satellite.getClockOffsetDriver().getValue(common.getState().getDate());
  127.             final double              dtg       = getStation().getClockOffsetDriver().getValue(common.getState().getDate());

  128.             // Range value
  129.             range = (common.getTauD() + dtg - dts) * Constants.SPEED_OF_LIGHT;

  130.         }

  131.         estimated.setEstimatedValue(range);

  132.         return estimated;

  133.     }

  134.     /** {@inheritDoc} */
  135.     @Override
  136.     protected EstimatedMeasurement<Range> theoreticalEvaluation(final int iteration,
  137.                                                                 final int evaluation,
  138.                                                                 final SpacecraftState[] states) {

  139.         final SpacecraftState state = states[0];

  140.         // Range derivatives are computed with respect to spacecraft state in inertial frame
  141.         // and station parameters
  142.         // ----------------------
  143.         //
  144.         // Parameters:
  145.         //  - 0..2 - Position of the spacecraft in inertial frame
  146.         //  - 3..5 - Velocity of the spacecraft in inertial frame
  147.         //  - 6..n - measurements parameters (clock offset, station offsets, pole, prime meridian, sat clock offset...)
  148.         final GroundReceiverCommonParametersWithDerivatives common = computeCommonParametersWithDerivatives(state);
  149.         final int nbParams = common.getTauD().getFreeParameters();
  150.         final TimeStampedFieldPVCoordinates<Gradient> transitPV = common.getTransitPV();

  151.         // prepare the evaluation
  152.         final EstimatedMeasurement<Range> estimated;
  153.         final Gradient range;

  154.         if (isTwoWay()) {

  155.             // Station at transit state date (derivatives of tauD taken into account)
  156.             final TimeStampedFieldPVCoordinates<Gradient> stationAtTransitDate =
  157.                             common.getStationDownlink().shiftedBy(common.getTauD().negate());
  158.             // Uplink delay
  159.             final Gradient tauU =
  160.                             signalTimeOfFlightAdjustableEmitter(stationAtTransitDate, transitPV.getPosition(), transitPV.getDate(),
  161.                                                                 state.getFrame());
  162.             final TimeStampedFieldPVCoordinates<Gradient> stationUplink =
  163.                             common.getStationDownlink().shiftedBy(-common.getTauD().getValue() - tauU.getValue());

  164.             // Prepare the evaluation
  165.             estimated = new EstimatedMeasurement<>(this, iteration, evaluation,
  166.                                                             new SpacecraftState[] {
  167.                                                                 common.getTransitState()
  168.                                                             }, new TimeStampedPVCoordinates[] {
  169.                                                                 stationUplink.toTimeStampedPVCoordinates(),
  170.                                                                 transitPV.toTimeStampedPVCoordinates(),
  171.                                                                 common.getStationDownlink().toTimeStampedPVCoordinates()
  172.                                                             });

  173.             // Range value
  174.             final double   cOver2 = 0.5 * Constants.SPEED_OF_LIGHT;
  175.             final Gradient tau    = common.getTauD().add(tauU);
  176.             range                 = tau.multiply(cOver2);

  177.         } else {

  178.             estimated = new EstimatedMeasurement<>(this, iteration, evaluation,
  179.                             new SpacecraftState[] {
  180.                                 common.getTransitState()
  181.                             }, new TimeStampedPVCoordinates[] {
  182.                                 transitPV.toTimeStampedPVCoordinates(),
  183.                                 common.getStationDownlink().toTimeStampedPVCoordinates()
  184.                             });

  185.             // Clock offsets
  186.             final ObservableSatellite satellite = getSatellites().get(0);
  187.             final Gradient            dts       = satellite.getClockOffsetDriver().getValue(nbParams, common.getIndices(), state.getDate());
  188.             final Gradient            dtg       = getStation().getClockOffsetDriver().getValue(nbParams, common.getIndices(), state.getDate());

  189.             // Range value
  190.             range = common.getTauD().add(dtg).subtract(dts).multiply(Constants.SPEED_OF_LIGHT);

  191.         }

  192.         estimated.setEstimatedValue(range.getValue());

  193.         // Range first order derivatives with respect to state
  194.         final double[] derivatives = range.getGradient();
  195.         estimated.setStateDerivatives(0, Arrays.copyOfRange(derivatives, 0, 6));

  196.         // Set first order derivatives with respect to parameters
  197.         for (final ParameterDriver driver : getParametersDrivers()) {
  198.             for (Span<String> span = driver.getNamesSpanMap().getFirstSpan(); span != null; span = span.next()) {
  199.                 final Integer index = common.getIndices().get(span.getData());
  200.                 if (index != null) {
  201.                     estimated.setParameterDerivatives(driver, span.getStart(), derivatives[index]);
  202.                 }
  203.             }
  204.         }

  205.         return estimated;

  206.     }

  207. }