AbstractMeasurement.java

  1. /* Copyright 2002-2019 CS Systèmes d'Information
  2.  * Licensed to CS Systèmes d'Information (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 java.util.stream.Collectors;

  22. import org.hipparchus.RealFieldElement;
  23. import org.hipparchus.analysis.differentiation.DSFactory;
  24. import org.hipparchus.analysis.differentiation.DerivativeStructure;
  25. import org.hipparchus.geometry.euclidean.threed.FieldVector3D;
  26. import org.hipparchus.geometry.euclidean.threed.Vector3D;
  27. import org.hipparchus.util.FastMath;
  28. import org.orekit.propagation.SpacecraftState;
  29. import org.orekit.time.AbsoluteDate;
  30. import org.orekit.time.FieldAbsoluteDate;
  31. import org.orekit.utils.Constants;
  32. import org.orekit.utils.ParameterDriver;
  33. import org.orekit.utils.TimeStampedFieldPVCoordinates;
  34. import org.orekit.utils.TimeStampedPVCoordinates;

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

  42.     /** List of the supported parameters. */
  43.     private final List<ParameterDriver> supportedParameters;

  44.     /** Satellites related to this measurement.
  45.      * @since 9.3
  46.      */
  47.     private final List<ObservableSatellite> satellites;

  48.     /** Date of the measurement. */
  49.     private final AbsoluteDate date;

  50.     /** Observed value. */
  51.     private final double[] observed;

  52.     /** Theoretical standard deviation. */
  53.     private final double[] sigma;

  54.     /** Base weight. */
  55.     private final double[] baseWeight;

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

  58.     /** Enabling status. */
  59.     private boolean enabled;

  60.     /** Simple constructor for mono-dimensional measurements.
  61.      * <p>
  62.      * At construction, a measurement is enabled.
  63.      * </p>
  64.      * @param date date of the measurement
  65.      * @param observed observed value
  66.      * @param sigma theoretical standard deviation
  67.      * @param baseWeight base weight
  68.      * @param propagatorsIndices indices of the propagators related to this measurement
  69.      * @param supportedParameters supported parameters
  70.      * @deprecated since 9.3, replaced bew {@link #AbstractMeasurement(AbsoluteDate,
  71.      * double, double, double, List)} followed by {@link #addParameterDriver(ParameterDriver)}
  72.      */
  73.     @Deprecated
  74.     protected AbstractMeasurement(final AbsoluteDate date, final double observed,
  75.                                   final double sigma, final double baseWeight,
  76.                                   final List<Integer> propagatorsIndices,
  77.                                   final ParameterDriver... supportedParameters) {
  78.         this(date, observed, sigma, baseWeight,
  79.              propagatorsIndices.stream().map(i -> new ObservableSatellite(i)).collect(Collectors.toList()));
  80.         for (final ParameterDriver parameterDriver : supportedParameters) {
  81.             this.supportedParameters.add(parameterDriver);
  82.         }
  83.     }

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

  98.         this.supportedParameters = new ArrayList<ParameterDriver>();
  99.         for (final ParameterDriver parameterDriver : supportedParameters) {
  100.             this.supportedParameters.add(parameterDriver);
  101.         }

  102.         this.date       = date;
  103.         this.observed   = new double[] {
  104.             observed
  105.         };
  106.         this.sigma      = new double[] {
  107.             sigma
  108.         };
  109.         this.baseWeight = new double[] {
  110.             baseWeight
  111.         };

  112.         this.satellites = satellites;

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

  115.     }

  116.     /** Simple constructor, for multi-dimensional measurements.
  117.      * <p>
  118.      * At construction, a measurement is enabled.
  119.      * </p>
  120.      * @param date date of the measurement
  121.      * @param observed observed value
  122.      * @param sigma theoretical standard deviation
  123.      * @param baseWeight base weight
  124.      * @param propagatorsIndices indices of the propagators related to this measurement
  125.      * @param supportedParameters supported parameters
  126.      * @deprecated since 9.3, replaced bew {@link #AbstractMeasurement(AbsoluteDate,
  127.      * double[], double[], double[], List)} followed by {@link #addParameterDriver(ParameterDriver)}
  128.      */
  129.     @Deprecated
  130.     protected AbstractMeasurement(final AbsoluteDate date, final double[] observed,
  131.                                   final double[] sigma, final double[] baseWeight,
  132.                                   final List<Integer> propagatorsIndices,
  133.                                   final ParameterDriver... supportedParameters) {
  134.         this(date, observed, sigma, baseWeight,
  135.              propagatorsIndices.stream().map(i -> new ObservableSatellite(i)).collect(Collectors.toList()));
  136.         for (final ParameterDriver parameterDriver : supportedParameters) {
  137.             this.supportedParameters.add(parameterDriver);
  138.         }
  139.     }

  140.     /** Simple constructor, for multi-dimensional measurements.
  141.      * <p>
  142.      * At construction, a measurement is enabled.
  143.      * </p>
  144.      * @param date date of the measurement
  145.      * @param observed observed value
  146.      * @param sigma theoretical standard deviation
  147.      * @param baseWeight base weight
  148.      * @param satellites satellites related to this measurement
  149.      * @since 9.3
  150.      */
  151.     protected AbstractMeasurement(final AbsoluteDate date, final double[] observed,
  152.                                   final double[] sigma, final double[] baseWeight,
  153.                                   final List<ObservableSatellite> satellites) {
  154.         this.supportedParameters = new ArrayList<ParameterDriver>();

  155.         this.date       = date;
  156.         this.observed   = observed.clone();
  157.         this.sigma      = sigma.clone();
  158.         this.baseWeight = baseWeight.clone();

  159.         this.satellites = satellites;

  160.         this.modifiers = new ArrayList<EstimationModifier<T>>();
  161.         setEnabled(true);

  162.     }

  163.     /** Add a parameter driver.
  164.      * @param driver parameter driver to add
  165.      * @since 9.3
  166.      */
  167.     protected void addParameterDriver(final ParameterDriver driver) {
  168.         supportedParameters.add(driver);
  169.     }

  170.     /** {@inheritDoc} */
  171.     @Override
  172.     public List<ParameterDriver> getParametersDrivers() {
  173.         return Collections.unmodifiableList(supportedParameters);
  174.     }

  175.     /** {@inheritDoc} */
  176.     @Override
  177.     public void setEnabled(final boolean enabled) {
  178.         this.enabled = enabled;
  179.     }

  180.     /** {@inheritDoc} */
  181.     @Override
  182.     public boolean isEnabled() {
  183.         return enabled;
  184.     }

  185.     /** {@inheritDoc} */
  186.     @Override
  187.     public int getDimension() {
  188.         return observed.length;
  189.     }

  190.     /** {@inheritDoc} */
  191.     @Override
  192.     public double[] getTheoreticalStandardDeviation() {
  193.         return sigma.clone();
  194.     }

  195.     /** {@inheritDoc} */
  196.     @Override
  197.     public double[] getBaseWeight() {
  198.         return baseWeight.clone();
  199.     }

  200.     /** {@inheritDoc}
  201.      * @deprecated as of 9.3, replaced by {@link #getSatellites()}
  202.      */
  203.     @Deprecated
  204.     public List<Integer> getPropagatorsIndices() {
  205.         return satellites.stream().map(s -> s.getPropagatorIndex()).collect(Collectors.toList());
  206.     }

  207.     /** {@inheritDoc} */
  208.     @Override
  209.     public List<ObservableSatellite> getSatellites() {
  210.         return satellites;
  211.     }

  212.     /** Estimate the theoretical value.
  213.      * <p>
  214.      * The theoretical value does not have <em>any</em> modifiers applied.
  215.      * </p>
  216.      * @param iteration iteration number
  217.      * @param evaluation evaluation number
  218.      * @param states orbital states at measurement date
  219.      * @return theoretical value
  220.      * @see #estimate(int, int, SpacecraftState[])
  221.      */
  222.     protected abstract EstimatedMeasurement<T> theoreticalEvaluation(int iteration, int evaluation, SpacecraftState[] states);

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

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

  228.         // apply the modifiers
  229.         for (final EstimationModifier<T> modifier : modifiers) {
  230.             modifier.modify(estimation);
  231.         }

  232.         return estimation;

  233.     }

  234.     /** {@inheritDoc} */
  235.     @Override
  236.     public AbsoluteDate getDate() {
  237.         return date;
  238.     }

  239.     /** {@inheritDoc} */
  240.     @Override
  241.     public double[] getObservedValue() {
  242.         return observed.clone();
  243.     }

  244.     /** {@inheritDoc} */
  245.     @Override
  246.     public void addModifier(final EstimationModifier<T> modifier) {

  247.         // combine the measurement parameters and the modifier parameters
  248.         supportedParameters.addAll(modifier.getParametersDrivers());

  249.         modifiers.add(modifier);

  250.     }

  251.     /** {@inheritDoc} */
  252.     @Override
  253.     public List<EstimationModifier<T>> getModifiers() {
  254.         return Collections.unmodifiableList(modifiers);
  255.     }

  256.     /** Compute propagation delay on a link leg (typically downlink or uplink).
  257.      * @param adjustableEmitterPV position/velocity of emitter that may be adjusted
  258.      * @param receiverPosition fixed position of receiver at {@code signalArrivalDate},
  259.      * in the same frame as {@code adjustableEmitterPV}
  260.      * @param signalArrivalDate date at which the signal arrives to receiver
  261.      * @return <em>positive</em> delay between signal emission and signal reception dates
  262.      */
  263.     public static double signalTimeOfFlight(final TimeStampedPVCoordinates adjustableEmitterPV,
  264.                                             final Vector3D receiverPosition,
  265.                                             final AbsoluteDate signalArrivalDate) {

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

  271.         // search signal transit date, computing the signal travel in inertial frame
  272.         final double cReciprocal = 1.0 / Constants.SPEED_OF_LIGHT;
  273.         double delta;
  274.         int count = 0;
  275.         do {
  276.             final double previous   = delay;
  277.             final Vector3D transitP = adjustableEmitterPV.shiftedBy(offset - delay).getPosition();
  278.             delay                   = receiverPosition.distance(transitP) * cReciprocal;
  279.             delta                   = FastMath.abs(delay - previous);
  280.         } while (count++ < 10 && delta >= 2 * FastMath.ulp(delay));

  281.         return delay;

  282.     }

  283.     /** Compute propagation delay on a link leg (typically downlink or uplink).
  284.      * @param adjustableEmitterPV position/velocity of emitter that may be adjusted
  285.      * @param receiverPosition fixed position of receiver at {@code signalArrivalDate},
  286.      * in the same frame as {@code adjustableEmitterPV}
  287.      * @param signalArrivalDate date at which the signal arrives to receiver
  288.      * @return <em>positive</em> delay between signal emission and signal reception dates
  289.      * @param <T> the type of the components
  290.      */
  291.     public static <T extends RealFieldElement<T>> T signalTimeOfFlight(final TimeStampedFieldPVCoordinates<T> adjustableEmitterPV,
  292.                                                                        final FieldVector3D<T> receiverPosition,
  293.                                                                        final FieldAbsoluteDate<T> signalArrivalDate) {

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

  299.         // search signal transit date, computing the signal travel in the frame shared by emitter and receiver
  300.         final double cReciprocal = 1.0 / Constants.SPEED_OF_LIGHT;
  301.         double delta;
  302.         int count = 0;
  303.         do {
  304.             final double previous           = delay.getReal();
  305.             final FieldVector3D<T> transitP = adjustableEmitterPV.shiftedBy(delay.negate().add(offset)).getPosition();
  306.             delay                           = receiverPosition.distance(transitP).multiply(cReciprocal);
  307.             delta                           = FastMath.abs(delay.getReal() - previous);
  308.         } while (count++ < 10 && delta >= 2 * FastMath.ulp(delay.getReal()));

  309.         return delay;

  310.     }

  311.     /** Get Cartesian coordinates as derivatives.
  312.      * <p>
  313.      * The position will correspond to variables {@code firstDerivative},
  314.      * {@code firstDerivative + 1} and {@code firstDerivative + 2}.
  315.      * The velocity will correspond to variables {@code firstDerivative + 3},
  316.      * {@code firstDerivative + 4} and {@code firstDerivative + 5}.
  317.      * The acceleration will correspond to constants.
  318.      * </p>
  319.      * @param state state of the satellite considered
  320.      * @param firstDerivative index of the first derivative
  321.      * @param factory factory for building the derivatives
  322.      * @return Cartesian coordinates as derivatives
  323.      */
  324.     public static TimeStampedFieldPVCoordinates<DerivativeStructure> getCoordinates(final SpacecraftState state,
  325.                                                                                     final int firstDerivative,
  326.                                                                                     final DSFactory factory) {

  327.         // Position of the satellite expressed as a derivative structure
  328.         // The components of the position are the 3 first derivative parameters
  329.         final Vector3D p = state.getPVCoordinates().getPosition();
  330.         final FieldVector3D<DerivativeStructure> pDS =
  331.                         new FieldVector3D<>(factory.variable(firstDerivative + 0, p.getX()),
  332.                                             factory.variable(firstDerivative + 1, p.getY()),
  333.                                             factory.variable(firstDerivative + 2, p.getZ()));

  334.         // Velocity of the satellite expressed as a derivative structure
  335.         // The components of the velocity are the 3 second derivative parameters
  336.         final Vector3D v = state.getPVCoordinates().getVelocity();
  337.         final FieldVector3D<DerivativeStructure> vDS =
  338.                         new FieldVector3D<>(factory.variable(firstDerivative + 3, v.getX()),
  339.                                             factory.variable(firstDerivative + 4, v.getY()),
  340.                                             factory.variable(firstDerivative + 5, v.getZ()));

  341.         // Acceleration of the satellite
  342.         // The components of the acceleration are not derivative parameters
  343.         final Vector3D a = state.getPVCoordinates().getAcceleration();
  344.         final FieldVector3D<DerivativeStructure> aDS =
  345.                         new FieldVector3D<>(factory.constant(a.getX()),
  346.                                             factory.constant(a.getY()),
  347.                                             factory.constant(a.getZ()));

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

  349.     }

  350. }