AbstractMeasurement.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;

  18. import java.util.ArrayList;
  19. import java.util.Collections;
  20. import java.util.List;

  21. import org.hipparchus.CalculusFieldElement;
  22. import org.hipparchus.analysis.differentiation.Gradient;
  23. import org.hipparchus.geometry.euclidean.threed.FieldVector3D;
  24. import org.hipparchus.geometry.euclidean.threed.Vector3D;
  25. import org.hipparchus.util.FastMath;
  26. import org.orekit.annotation.DefaultDataContext;
  27. import org.orekit.frames.Frame;
  28. import org.orekit.frames.FramesFactory;
  29. import org.orekit.propagation.SpacecraftState;
  30. import org.orekit.time.AbsoluteDate;
  31. import org.orekit.time.FieldAbsoluteDate;
  32. import org.orekit.utils.Constants;
  33. import org.orekit.utils.FieldPVCoordinatesProvider;
  34. import org.orekit.utils.PVCoordinatesProvider;
  35. import org.orekit.utils.ParameterDriver;
  36. import org.orekit.utils.FieldShiftingPVCoordinatesProvider;
  37. import org.orekit.utils.ShiftingPVCoordinatesProvider;
  38. import org.orekit.utils.TimeStampedFieldPVCoordinates;
  39. import org.orekit.utils.TimeStampedPVCoordinates;

  40. /** Abstract class handling measurements boilerplate.
  41.  * @param <T> the type of the measurement
  42.  * @author Luc Maisonobe
  43.  * @since 8.0
  44.  */
  45. public abstract class AbstractMeasurement<T extends ObservedMeasurement<T>> implements ObservedMeasurement<T> {

  46.     /** List of the supported parameters. */
  47.     private final List<ParameterDriver> supportedParameters;

  48.     /** Satellites related to this measurement.
  49.      * @since 9.3
  50.      */
  51.     private final List<ObservableSatellite> satellites;

  52.     /** Date of the measurement. */
  53.     private final AbsoluteDate date;

  54.     /** Observed value. */
  55.     private final double[] observed;

  56.     /** Theoretical standard deviation. */
  57.     private final double[] sigma;

  58.     /** Base weight. */
  59.     private final double[] baseWeight;

  60.     /** Modifiers that apply to the measurement.*/
  61.     private final List<EstimationModifier<T>> modifiers;

  62.     /** Enabling status. */
  63.     private boolean enabled;

  64.     /** Simple constructor for mono-dimensional measurements.
  65.      * <p>
  66.      * At construction, a measurement is enabled.
  67.      * </p>
  68.      * @param date date of the measurement
  69.      * @param observed observed value
  70.      * @param sigma theoretical standard deviation
  71.      * @param baseWeight base weight
  72.      * @param satellites satellites related to this measurement
  73.      * @since 9.3
  74.      */
  75.     protected AbstractMeasurement(final AbsoluteDate date, final double observed,
  76.                                   final double sigma, final double baseWeight,
  77.                                   final List<ObservableSatellite> satellites) {

  78.         this.supportedParameters = new ArrayList<ParameterDriver>();

  79.         this.date       = date;
  80.         this.observed   = new double[] {
  81.             observed
  82.         };
  83.         this.sigma      = new double[] {
  84.             sigma
  85.         };
  86.         this.baseWeight = new double[] {
  87.             baseWeight
  88.         };

  89.         this.satellites = satellites;

  90.         this.modifiers = new ArrayList<EstimationModifier<T>>();
  91.         setEnabled(true);

  92.     }

  93.     /** Simple constructor, for multi-dimensional measurements.
  94.      * <p>
  95.      * At construction, a measurement is enabled.
  96.      * </p>
  97.      * @param date date of the measurement
  98.      * @param observed observed value
  99.      * @param sigma theoretical standard deviation
  100.      * @param baseWeight base weight
  101.      * @param satellites satellites related to this measurement
  102.      * @since 9.3
  103.      */
  104.     protected AbstractMeasurement(final AbsoluteDate date, final double[] observed,
  105.                                   final double[] sigma, final double[] baseWeight,
  106.                                   final List<ObservableSatellite> satellites) {
  107.         this.supportedParameters = new ArrayList<ParameterDriver>();

  108.         this.date       = date;
  109.         this.observed   = observed.clone();
  110.         this.sigma      = sigma.clone();
  111.         this.baseWeight = baseWeight.clone();

  112.         this.satellites = satellites;

  113.         this.modifiers = new ArrayList<EstimationModifier<T>>();
  114.         setEnabled(true);

  115.     }

  116.     /** Add a parameter driver.
  117.      * @param driver parameter driver to add
  118.      * @since 9.3
  119.      */
  120.     protected void addParameterDriver(final ParameterDriver driver) {
  121.         supportedParameters.add(driver);
  122.     }

  123.     /** {@inheritDoc} */
  124.     @Override
  125.     public List<ParameterDriver> getParametersDrivers() {
  126.         return Collections.unmodifiableList(supportedParameters);
  127.     }

  128.     /** {@inheritDoc} */
  129.     @Override
  130.     public void setEnabled(final boolean enabled) {
  131.         this.enabled = enabled;
  132.     }

  133.     /** {@inheritDoc} */
  134.     @Override
  135.     public boolean isEnabled() {
  136.         return enabled;
  137.     }

  138.     /** {@inheritDoc} */
  139.     @Override
  140.     public int getDimension() {
  141.         return observed.length;
  142.     }

  143.     /** {@inheritDoc} */
  144.     @Override
  145.     public double[] getTheoreticalStandardDeviation() {
  146.         return sigma.clone();
  147.     }

  148.     /** {@inheritDoc} */
  149.     @Override
  150.     public double[] getBaseWeight() {
  151.         return baseWeight.clone();
  152.     }

  153.     /** {@inheritDoc} */
  154.     @Override
  155.     public List<ObservableSatellite> getSatellites() {
  156.         return satellites;
  157.     }

  158.     /** Estimate the theoretical value without derivatives.
  159.      * <p>
  160.      * The theoretical value does not have <em>any</em> modifiers applied.
  161.      * </p>
  162.      * @param iteration iteration number
  163.      * @param evaluation evaluation number
  164.      * @param states orbital states at measurement date
  165.      * @return theoretical value
  166.      * @see #estimate(int, int, SpacecraftState[])
  167.      * @since 12.0
  168.      */
  169.     protected abstract EstimatedMeasurementBase<T> theoreticalEvaluationWithoutDerivatives(int iteration, int evaluation,
  170.                                                                                            SpacecraftState[] states);

  171.     /** Estimate the theoretical value.
  172.      * <p>
  173.      * The theoretical value does not have <em>any</em> modifiers applied.
  174.      * </p>
  175.      * @param iteration iteration number
  176.      * @param evaluation evaluation number
  177.      * @param states orbital states at measurement date
  178.      * @return theoretical value
  179.      * @see #estimate(int, int, SpacecraftState[])
  180.      */
  181.     protected abstract EstimatedMeasurement<T> theoreticalEvaluation(int iteration, int evaluation, SpacecraftState[] states);

  182.     /** {@inheritDoc} */
  183.     @Override
  184.     public EstimatedMeasurementBase<T> estimateWithoutDerivatives(final int iteration, final int evaluation, final SpacecraftState[] states) {

  185.         // compute the theoretical value
  186.         final EstimatedMeasurementBase<T> estimation = theoreticalEvaluationWithoutDerivatives(iteration, evaluation, states);

  187.         // apply the modifiers
  188.         for (final EstimationModifier<T> modifier : modifiers) {
  189.             modifier.modifyWithoutDerivatives(estimation);
  190.         }

  191.         return estimation;

  192.     }

  193.     /** {@inheritDoc} */
  194.     @Override
  195.     public EstimatedMeasurement<T> estimate(final int iteration, final int evaluation, final SpacecraftState[] states) {

  196.         // compute the theoretical value
  197.         final EstimatedMeasurement<T> estimation = theoreticalEvaluation(iteration, evaluation, states);

  198.         // apply the modifiers
  199.         for (final EstimationModifier<T> modifier : modifiers) {
  200.             modifier.modify(estimation);
  201.         }

  202.         return estimation;

  203.     }

  204.     /** {@inheritDoc} */
  205.     @Override
  206.     public AbsoluteDate getDate() {
  207.         return date;
  208.     }

  209.     /** {@inheritDoc} */
  210.     @Override
  211.     public double[] getObservedValue() {
  212.         return observed.clone();
  213.     }

  214.     /** {@inheritDoc} */
  215.     @Override
  216.     public void addModifier(final EstimationModifier<T> modifier) {

  217.         // combine the measurement parameters and the modifier parameters
  218.         supportedParameters.addAll(modifier.getParametersDrivers());

  219.         modifiers.add(modifier);

  220.     }

  221.     /** {@inheritDoc} */
  222.     @Override
  223.     public List<EstimationModifier<T>> getModifiers() {
  224.         return Collections.unmodifiableList(modifiers);
  225.     }

  226.     /** Compute propagation delay on a link leg (typically downlink or uplink).
  227.      * @param adjustableEmitterPV position/velocity of emitter that may be adjusted
  228.      * @param receiverPosition fixed position of receiver at {@code signalArrivalDate},
  229.      * in the same frame as {@code adjustableEmitterPV}
  230.      * @param signalArrivalDate date at which the signal arrives to receiver
  231.      * @return <em>positive</em> delay between signal emission and signal reception dates
  232.      * @deprecated as of 12.1, replaced by either {@link #signalTimeOfFlight(TimeStampedPVCoordinates,
  233.      * Vector3D, AbsoluteDate, Frame)} or {@link #signalTimeOfFlight(PVCoordinatesProvider, AbsoluteDate,
  234.      * Vector3D, AbsoluteDate, Frame)}
  235.      */
  236.     @Deprecated
  237.     @DefaultDataContext
  238.     public static double signalTimeOfFlight(final TimeStampedPVCoordinates adjustableEmitterPV,
  239.                                             final Vector3D receiverPosition,
  240.                                             final AbsoluteDate signalArrivalDate) {
  241.         return signalTimeOfFlight(adjustableEmitterPV, receiverPosition, signalArrivalDate,
  242.                                   FramesFactory.getGCRF());
  243.     }

  244.     /** Compute propagation delay on a link leg (typically downlink or uplink).
  245.      * @param adjustableEmitterPV position/velocity of emitter that may be adjusted
  246.      * @param receiverPosition fixed position of receiver at {@code signalArrivalDate}
  247.      * @param receiverFrame frame in which both {@code adjustableEmitterPV} and
  248.      *                      {@code receiver receiverPosition} are defined
  249.      * @param signalArrivalDate date at which the signal arrives to receiver
  250.      * @return <em>positive</em> delay between signal emission and signal reception dates
  251.      * @since 12.1
  252.      */
  253.     public static double signalTimeOfFlight(final TimeStampedPVCoordinates adjustableEmitterPV,
  254.                                             final Vector3D receiverPosition,
  255.                                             final AbsoluteDate signalArrivalDate,
  256.                                             final Frame receiverFrame) {
  257.         return signalTimeOfFlight(new ShiftingPVCoordinatesProvider(adjustableEmitterPV,
  258.                                                                     receiverFrame),
  259.                                   adjustableEmitterPV.getDate(),
  260.                                   receiverPosition, signalArrivalDate,
  261.                                   receiverFrame);
  262.     }

  263.     /** Compute propagation delay on a link leg (typically downlink or uplink).
  264.      * @param adjustableEmitter position/velocity provider of emitter
  265.      * @param approxEmissionDate approximate emission date
  266.      * @param receiverPosition fixed position of receiver at {@code signalArrivalDate}
  267.      * @param signalArrivalDate date at which the signal arrives to receiver
  268.      * @param receiverFrame frame in which receiver is defined
  269.      * @return <em>positive</em> delay between signal emission and signal reception dates
  270.      * @since 12.1
  271.      */
  272.     public static double signalTimeOfFlight(final PVCoordinatesProvider adjustableEmitter,
  273.                                             final AbsoluteDate approxEmissionDate,
  274.                                             final Vector3D receiverPosition,
  275.                                             final AbsoluteDate signalArrivalDate,
  276.                                             final Frame receiverFrame) {

  277.         // initialize emission date search loop assuming the state is already correct
  278.         // this will be true for all but the first orbit determination iteration,
  279.         // and even for the first iteration the loop will converge very fast
  280.         final double offset = signalArrivalDate.durationFrom(approxEmissionDate);
  281.         double delay = offset;

  282.         // search signal transit date, computing the signal travel in inertial frame
  283.         final double cReciprocal = 1.0 / Constants.SPEED_OF_LIGHT;
  284.         double delta;
  285.         int count = 0;
  286.         do {
  287.             final double previous   = delay;
  288.             final Vector3D transitP = adjustableEmitter.getPosition(approxEmissionDate.shiftedBy(offset - delay),
  289.                                                                     receiverFrame);
  290.             delay                   = receiverPosition.distance(transitP) * cReciprocal;
  291.             delta                   = FastMath.abs(delay - previous);
  292.         } while (count++ < 10 && delta >= 2 * FastMath.ulp(delay));

  293.         return delay;

  294.     }

  295.     /** Compute propagation delay on a link leg (typically downlink or uplink).
  296.      * @param adjustableEmitterPV position/velocity of emitter that may be adjusted
  297.      * @param receiverPosition fixed position of receiver at {@code signalArrivalDate},
  298.      * in the same frame as {@code adjustableEmitterPV}
  299.      * @param signalArrivalDate date at which the signal arrives to receiver
  300.      * @return <em>positive</em> delay between signal emission and signal reception dates
  301.      * @param <T> the type of the components
  302.      * @deprecated as of 12.1, replaced by either {@link #signalTimeOfFlight(TimeStampedFieldPVCoordinates,
  303.      * FieldVector3D, FieldAbsoluteDate, Frame)} or {@link #signalTimeOfFlight(FieldPVCoordinatesProvider,
  304.      * FieldAbsoluteDate, FieldVector3D, FieldAbsoluteDate, Frame)}
  305.      */
  306.     @Deprecated
  307.     @DefaultDataContext
  308.     public static <T extends CalculusFieldElement<T>> T signalTimeOfFlight(final TimeStampedFieldPVCoordinates<T> adjustableEmitterPV,
  309.                                                                            final FieldVector3D<T> receiverPosition,
  310.                                                                            final FieldAbsoluteDate<T> signalArrivalDate) {
  311.         return signalTimeOfFlight(adjustableEmitterPV, receiverPosition, signalArrivalDate,
  312.                                   FramesFactory.getGCRF());
  313.     }

  314.     /** Compute propagation delay on a link leg (typically downlink or uplink).
  315.      * @param adjustableEmitterPV position/velocity of emitter that may be adjusted
  316.      * @param receiverPosition fixed position of receiver at {@code signalArrivalDate},
  317.      * in the same frame as {@code adjustableEmitterPV}
  318.      * @param signalArrivalDate date at which the signal arrives to receiver
  319.      * @return <em>positive</em> delay between signal emission and signal reception dates
  320.      * @param receiverFrame frame in which receiver is defined
  321.      * @param <T> the type of the components
  322.      * @since 12.1
  323.      */
  324.     public static <T extends CalculusFieldElement<T>> T signalTimeOfFlight(final TimeStampedFieldPVCoordinates<T> adjustableEmitterPV,
  325.                                                                            final FieldVector3D<T> receiverPosition,
  326.                                                                            final FieldAbsoluteDate<T> signalArrivalDate,
  327.                                                                            final Frame receiverFrame) {
  328.         return signalTimeOfFlight(new FieldShiftingPVCoordinatesProvider<>(adjustableEmitterPV,
  329.                                                                            receiverFrame),
  330.                                   adjustableEmitterPV.getDate(),
  331.                                   receiverPosition, signalArrivalDate,
  332.                                   receiverFrame);
  333.     }

  334.     /** Compute propagation delay on a link leg (typically downlink or uplink).
  335.      * @param adjustableEmitter position/velocity provider of emitter
  336.      * @param approxEmissionDate approximate emission date
  337.      * @param receiverPosition fixed position of receiver at {@code signalArrivalDate},
  338.      * in the same frame as {@code adjustableEmitterPV}
  339.      * @param signalArrivalDate date at which the signal arrives to receiver
  340.      * @param receiverFrame frame in which receiver is defined
  341.      * @return <em>positive</em> delay between signal emission and signal reception dates
  342.      * @param <T> the type of the components
  343.      * @since 12.1
  344.      */
  345.     public static <T extends CalculusFieldElement<T>> T signalTimeOfFlight(final FieldPVCoordinatesProvider<T> adjustableEmitter,
  346.                                                                            final FieldAbsoluteDate<T> approxEmissionDate,
  347.                                                                            final FieldVector3D<T> receiverPosition,
  348.                                                                            final FieldAbsoluteDate<T> signalArrivalDate,
  349.                                                                            final Frame receiverFrame) {

  350.         // Initialize emission date search loop assuming the emitter PV is almost correct
  351.         // this will be true for all but the first orbit determination iteration,
  352.         // and even for the first iteration the loop will converge extremely fast
  353.         final T offset = signalArrivalDate.durationFrom(approxEmissionDate);
  354.         T delay = offset;

  355.         // search signal transit date, computing the signal travel in the frame shared by emitter and receiver
  356.         final double cReciprocal = 1.0 / Constants.SPEED_OF_LIGHT;
  357.         double delta;
  358.         int count = 0;
  359.         do {
  360.             final double previous           = delay.getReal();
  361.             final FieldVector3D<T> transitP = adjustableEmitter.getPosition(approxEmissionDate.shiftedBy(offset.subtract(delay)),
  362.                                                                             receiverFrame);
  363.             delay                           = receiverPosition.distance(transitP).multiply(cReciprocal);
  364.             delta                           = FastMath.abs(delay.getReal() - previous);
  365.         } while (count++ < 10 && delta >= 2 * FastMath.ulp(delay.getReal()));

  366.         return delay;

  367.     }

  368.     /** Get Cartesian coordinates as derivatives.
  369.      * <p>
  370.      * The position will correspond to variables {@code firstDerivative},
  371.      * {@code firstDerivative + 1} and {@code firstDerivative + 2}.
  372.      * The velocity will correspond to variables {@code firstDerivative + 3},
  373.      * {@code firstDerivative + 4} and {@code firstDerivative + 5}.
  374.      * The acceleration will correspond to constants.
  375.      * </p>
  376.      * @param state state of the satellite considered
  377.      * @param firstDerivative index of the first derivative
  378.      * @param freeParameters total number of free parameters in the gradient
  379.      * @return Cartesian coordinates as derivatives
  380.      * @since 10.2
  381.      */
  382.     public static TimeStampedFieldPVCoordinates<Gradient> getCoordinates(final SpacecraftState state,
  383.                                                                          final int firstDerivative,
  384.                                                                          final int freeParameters) {

  385.         // Position of the satellite expressed as a gradient
  386.         // The components of the position are the 3 first derivative parameters
  387.         final Vector3D p = state.getPosition();
  388.         final FieldVector3D<Gradient> pDS =
  389.                         new FieldVector3D<>(Gradient.variable(freeParameters, firstDerivative + 0, p.getX()),
  390.                                             Gradient.variable(freeParameters, firstDerivative + 1, p.getY()),
  391.                                             Gradient.variable(freeParameters, firstDerivative + 2, p.getZ()));

  392.         // Velocity of the satellite expressed as a gradient
  393.         // The components of the velocity are the 3 second derivative parameters
  394.         final Vector3D v = state.getPVCoordinates().getVelocity();
  395.         final FieldVector3D<Gradient> vDS =
  396.                         new FieldVector3D<>(Gradient.variable(freeParameters, firstDerivative + 3, v.getX()),
  397.                                             Gradient.variable(freeParameters, firstDerivative + 4, v.getY()),
  398.                                             Gradient.variable(freeParameters, firstDerivative + 5, v.getZ()));

  399.         // Acceleration of the satellite
  400.         // The components of the acceleration are not derivative parameters
  401.         final Vector3D a = state.getPVCoordinates().getAcceleration();
  402.         final FieldVector3D<Gradient> aDS =
  403.                         new FieldVector3D<>(Gradient.constant(freeParameters, a.getX()),
  404.                                             Gradient.constant(freeParameters, a.getY()),
  405.                                             Gradient.constant(freeParameters, a.getZ()));

  406.         return new TimeStampedFieldPVCoordinates<>(state.getDate(), pDS, vDS, aDS);

  407.     }

  408. }