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.propagation.SpacecraftState;
  27. import org.orekit.time.AbsoluteDate;
  28. import org.orekit.time.FieldAbsoluteDate;
  29. import org.orekit.utils.Constants;
  30. import org.orekit.utils.ParameterDriver;
  31. import org.orekit.utils.TimeStampedFieldPVCoordinates;
  32. import org.orekit.utils.TimeStampedPVCoordinates;

  33. /** Abstract class handling measurements boilerplate.
  34.  * @param <T> the type of the measurement
  35.  * @author Luc Maisonobe
  36.  * @since 8.0
  37.  */
  38. public abstract class AbstractMeasurement<T extends ObservedMeasurement<T>> implements ObservedMeasurement<T> {

  39.     /** List of the supported parameters. */
  40.     private final List<ParameterDriver> supportedParameters;

  41.     /** Satellites related to this measurement.
  42.      * @since 9.3
  43.      */
  44.     private final List<ObservableSatellite> satellites;

  45.     /** Date of the measurement. */
  46.     private final AbsoluteDate date;

  47.     /** Observed value. */
  48.     private final double[] observed;

  49.     /** Theoretical standard deviation. */
  50.     private final double[] sigma;

  51.     /** Base weight. */
  52.     private final double[] baseWeight;

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

  55.     /** Enabling status. */
  56.     private boolean enabled;

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

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

  72.         this.date       = date;
  73.         this.observed   = new double[] {
  74.             observed
  75.         };
  76.         this.sigma      = new double[] {
  77.             sigma
  78.         };
  79.         this.baseWeight = new double[] {
  80.             baseWeight
  81.         };

  82.         this.satellites = satellites;

  83.         this.modifiers = new ArrayList<EstimationModifier<T>>();
  84.         setEnabled(true);

  85.     }

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

  101.         this.date       = date;
  102.         this.observed   = observed.clone();
  103.         this.sigma      = sigma.clone();
  104.         this.baseWeight = baseWeight.clone();

  105.         this.satellites = satellites;

  106.         this.modifiers = new ArrayList<EstimationModifier<T>>();
  107.         setEnabled(true);

  108.     }

  109.     /** Add a parameter driver.
  110.      * @param driver parameter driver to add
  111.      * @since 9.3
  112.      */
  113.     protected void addParameterDriver(final ParameterDriver driver) {
  114.         supportedParameters.add(driver);
  115.     }

  116.     /** {@inheritDoc} */
  117.     @Override
  118.     public List<ParameterDriver> getParametersDrivers() {
  119.         return Collections.unmodifiableList(supportedParameters);
  120.     }

  121.     /** {@inheritDoc} */
  122.     @Override
  123.     public void setEnabled(final boolean enabled) {
  124.         this.enabled = enabled;
  125.     }

  126.     /** {@inheritDoc} */
  127.     @Override
  128.     public boolean isEnabled() {
  129.         return enabled;
  130.     }

  131.     /** {@inheritDoc} */
  132.     @Override
  133.     public int getDimension() {
  134.         return observed.length;
  135.     }

  136.     /** {@inheritDoc} */
  137.     @Override
  138.     public double[] getTheoreticalStandardDeviation() {
  139.         return sigma.clone();
  140.     }

  141.     /** {@inheritDoc} */
  142.     @Override
  143.     public double[] getBaseWeight() {
  144.         return baseWeight.clone();
  145.     }

  146.     /** {@inheritDoc} */
  147.     @Override
  148.     public List<ObservableSatellite> getSatellites() {
  149.         return satellites;
  150.     }

  151.     /** Estimate the theoretical value without derivatives.
  152.      * <p>
  153.      * The theoretical value does not have <em>any</em> modifiers applied.
  154.      * </p>
  155.      * @param iteration iteration number
  156.      * @param evaluation evaluation number
  157.      * @param states orbital states at measurement date
  158.      * @return theoretical value
  159.      * @see #estimate(int, int, SpacecraftState[])
  160.      * @since 12.0
  161.      */
  162.     protected abstract EstimatedMeasurementBase<T> theoreticalEvaluationWithoutDerivatives(int iteration, int evaluation,
  163.                                                                                            SpacecraftState[] states);

  164.     /** Estimate the theoretical value.
  165.      * <p>
  166.      * The theoretical value does not have <em>any</em> modifiers applied.
  167.      * </p>
  168.      * @param iteration iteration number
  169.      * @param evaluation evaluation number
  170.      * @param states orbital states at measurement date
  171.      * @return theoretical value
  172.      * @see #estimate(int, int, SpacecraftState[])
  173.      */
  174.     protected abstract EstimatedMeasurement<T> theoreticalEvaluation(int iteration, int evaluation, SpacecraftState[] states);

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

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

  180.         // apply the modifiers
  181.         for (final EstimationModifier<T> modifier : modifiers) {
  182.             modifier.modifyWithoutDerivatives(estimation);
  183.         }

  184.         return estimation;

  185.     }

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

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

  191.         // apply the modifiers
  192.         for (final EstimationModifier<T> modifier : modifiers) {
  193.             modifier.modify(estimation);
  194.         }

  195.         return estimation;

  196.     }

  197.     /** {@inheritDoc} */
  198.     @Override
  199.     public AbsoluteDate getDate() {
  200.         return date;
  201.     }

  202.     /** {@inheritDoc} */
  203.     @Override
  204.     public double[] getObservedValue() {
  205.         return observed.clone();
  206.     }

  207.     /** {@inheritDoc} */
  208.     @Override
  209.     public void addModifier(final EstimationModifier<T> modifier) {

  210.         // combine the measurement parameters and the modifier parameters
  211.         supportedParameters.addAll(modifier.getParametersDrivers());

  212.         modifiers.add(modifier);

  213.     }

  214.     /** {@inheritDoc} */
  215.     @Override
  216.     public List<EstimationModifier<T>> getModifiers() {
  217.         return Collections.unmodifiableList(modifiers);
  218.     }

  219.     /** Compute propagation delay on a link leg (typically downlink or uplink).
  220.      * @param adjustableEmitterPV position/velocity of emitter that may be adjusted
  221.      * @param receiverPosition fixed position of receiver at {@code signalArrivalDate},
  222.      * in the same frame as {@code adjustableEmitterPV}
  223.      * @param signalArrivalDate date at which the signal arrives to receiver
  224.      * @return <em>positive</em> delay between signal emission and signal reception dates
  225.      */
  226.     public static double signalTimeOfFlight(final TimeStampedPVCoordinates adjustableEmitterPV,
  227.                                             final Vector3D receiverPosition,
  228.                                             final AbsoluteDate signalArrivalDate) {

  229.         // initialize emission date search loop assuming the state is already correct
  230.         // this will be true for all but the first orbit determination iteration,
  231.         // and even for the first iteration the loop will converge very fast
  232.         final double offset = signalArrivalDate.durationFrom(adjustableEmitterPV.getDate());
  233.         double delay = offset;

  234.         // search signal transit date, computing the signal travel in inertial frame
  235.         final double cReciprocal = 1.0 / Constants.SPEED_OF_LIGHT;
  236.         double delta;
  237.         int count = 0;
  238.         do {
  239.             final double previous   = delay;
  240.             final Vector3D transitP = adjustableEmitterPV.shiftedBy(offset - delay).getPosition();
  241.             delay                   = receiverPosition.distance(transitP) * cReciprocal;
  242.             delta                   = FastMath.abs(delay - previous);
  243.         } while (count++ < 10 && delta >= 2 * FastMath.ulp(delay));

  244.         return delay;

  245.     }

  246.     /** Compute propagation delay on a link leg (typically downlink or uplink).
  247.      * @param adjustableEmitterPV position/velocity of emitter that may be adjusted
  248.      * @param receiverPosition fixed position of receiver at {@code signalArrivalDate},
  249.      * in the same frame as {@code adjustableEmitterPV}
  250.      * @param signalArrivalDate date at which the signal arrives to receiver
  251.      * @return <em>positive</em> delay between signal emission and signal reception dates
  252.      * @param <T> the type of the components
  253.      */
  254.     public static <T extends CalculusFieldElement<T>> T signalTimeOfFlight(final TimeStampedFieldPVCoordinates<T> adjustableEmitterPV,
  255.                                                                            final FieldVector3D<T> receiverPosition,
  256.                                                                            final FieldAbsoluteDate<T> signalArrivalDate) {

  257.         // Initialize emission date search loop assuming the emitter PV is almost correct
  258.         // this will be true for all but the first orbit determination iteration,
  259.         // and even for the first iteration the loop will converge extremely fast
  260.         final T offset = signalArrivalDate.durationFrom(adjustableEmitterPV.getDate());
  261.         T delay = offset;

  262.         // search signal transit date, computing the signal travel in the frame shared by emitter and receiver
  263.         final double cReciprocal = 1.0 / Constants.SPEED_OF_LIGHT;
  264.         double delta;
  265.         int count = 0;
  266.         do {
  267.             final double previous           = delay.getReal();
  268.             final FieldVector3D<T> transitP = adjustableEmitterPV.shiftedBy(delay.negate().add(offset)).getPosition();
  269.             delay                           = receiverPosition.distance(transitP).multiply(cReciprocal);
  270.             delta                           = FastMath.abs(delay.getReal() - previous);
  271.         } while (count++ < 10 && delta >= 2 * FastMath.ulp(delay.getReal()));

  272.         return delay;

  273.     }

  274.     /** Get Cartesian coordinates as derivatives.
  275.      * <p>
  276.      * The position will correspond to variables {@code firstDerivative},
  277.      * {@code firstDerivative + 1} and {@code firstDerivative + 2}.
  278.      * The velocity will correspond to variables {@code firstDerivative + 3},
  279.      * {@code firstDerivative + 4} and {@code firstDerivative + 5}.
  280.      * The acceleration will correspond to constants.
  281.      * </p>
  282.      * @param state state of the satellite considered
  283.      * @param firstDerivative index of the first derivative
  284.      * @param freeParameters total number of free parameters in the gradient
  285.      * @return Cartesian coordinates as derivatives
  286.      * @since 10.2
  287.      */
  288.     public static TimeStampedFieldPVCoordinates<Gradient> getCoordinates(final SpacecraftState state,
  289.                                                                          final int firstDerivative,
  290.                                                                          final int freeParameters) {

  291.         // Position of the satellite expressed as a gradient
  292.         // The components of the position are the 3 first derivative parameters
  293.         final Vector3D p = state.getPosition();
  294.         final FieldVector3D<Gradient> pDS =
  295.                         new FieldVector3D<>(Gradient.variable(freeParameters, firstDerivative + 0, p.getX()),
  296.                                             Gradient.variable(freeParameters, firstDerivative + 1, p.getY()),
  297.                                             Gradient.variable(freeParameters, firstDerivative + 2, p.getZ()));

  298.         // Velocity of the satellite expressed as a gradient
  299.         // The components of the velocity are the 3 second derivative parameters
  300.         final Vector3D v = state.getPVCoordinates().getVelocity();
  301.         final FieldVector3D<Gradient> vDS =
  302.                         new FieldVector3D<>(Gradient.variable(freeParameters, firstDerivative + 3, v.getX()),
  303.                                             Gradient.variable(freeParameters, firstDerivative + 4, v.getY()),
  304.                                             Gradient.variable(freeParameters, firstDerivative + 5, v.getZ()));

  305.         // Acceleration of the satellite
  306.         // The components of the acceleration are not derivative parameters
  307.         final Vector3D a = state.getPVCoordinates().getAcceleration();
  308.         final FieldVector3D<Gradient> aDS =
  309.                         new FieldVector3D<>(Gradient.constant(freeParameters, a.getX()),
  310.                                             Gradient.constant(freeParameters, a.getY()),
  311.                                             Gradient.constant(freeParameters, a.getZ()));

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

  313.     }

  314. }