RangeRateTroposphericDelayModifier.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.modifiers;

  18. import java.util.Arrays;
  19. import java.util.List;

  20. import org.hipparchus.Field;
  21. import org.hipparchus.RealFieldElement;
  22. import org.hipparchus.analysis.differentiation.DerivativeStructure;
  23. import org.hipparchus.geometry.euclidean.threed.FieldVector3D;
  24. import org.hipparchus.geometry.euclidean.threed.Vector3D;
  25. import org.orekit.estimation.measurements.EstimatedMeasurement;
  26. import org.orekit.estimation.measurements.EstimationModifier;
  27. import org.orekit.estimation.measurements.GroundStation;
  28. import org.orekit.estimation.measurements.RangeRate;
  29. import org.orekit.models.earth.DiscreteTroposphericModel;
  30. import org.orekit.models.earth.TroposphericModel;
  31. import org.orekit.orbits.OrbitType;
  32. import org.orekit.orbits.PositionAngle;
  33. import org.orekit.propagation.FieldSpacecraftState;
  34. import org.orekit.propagation.Propagator;
  35. import org.orekit.propagation.SpacecraftState;
  36. import org.orekit.utils.Differentiation;
  37. import org.orekit.utils.ParameterDriver;
  38. import org.orekit.utils.ParameterFunction;
  39. import org.orekit.utils.StateFunction;

  40. /** Class modifying theoretical range-rate measurements with tropospheric delay.
  41.  * The effect of tropospheric correction on the range-rate is directly computed
  42.  * through the computation of the tropospheric delay difference with respect to
  43.  * time.
  44.  *
  45.  * In general, for GNSS, VLBI, ... there is hardly any frequency dependence in the delay.
  46.  * For SLR techniques however, the frequency dependence is sensitive.
  47.  *
  48.  * @author Joris Olympio
  49.  * @since 8.0
  50.  */
  51. public class RangeRateTroposphericDelayModifier implements EstimationModifier<RangeRate> {

  52.     /** Tropospheric delay model. */
  53.     private final DiscreteTroposphericModel tropoModel;

  54.     /** Two-way measurement factor. */
  55.     private final double fTwoWay;

  56.     /** Constructor.
  57.      *
  58.      * @param model  Tropospheric delay model appropriate for the current range-rate measurement method.
  59.      * @param tw     Flag indicating whether the measurement is two-way.
  60.      */
  61.     public RangeRateTroposphericDelayModifier(final DiscreteTroposphericModel model, final boolean tw) {
  62.         tropoModel = model;
  63.         if (tw) {
  64.             fTwoWay = 2.;
  65.         } else {
  66.             fTwoWay = 1.;
  67.         }
  68.     }

  69.     /** Get the station height above mean sea level.
  70.      *
  71.      * @param station  ground station (or measuring station)
  72.      * @return the measuring station height above sea level, m
  73.      */
  74.     private double getStationHeightAMSL(final GroundStation station) {
  75.         // FIXME heigth should be computed with respect to geoid WGS84+GUND = EGM2008 for example
  76.         final double height = station.getBaseFrame().getPoint().getAltitude();
  77.         return height;
  78.     }

  79.     /** Get the station height above mean sea level.
  80.     * @param <T> type of the element
  81.     * @param field field of the elements
  82.     * @param station  ground station (or measuring station)
  83.     * @return the measuring station height above sea level, m
  84.     */
  85.     private <T extends RealFieldElement<T>> T getStationHeightAMSL(final Field<T> field, final GroundStation station) {
  86.         // FIXME heigth should be computed with respect to geoid WGS84+GUND = EGM2008 for example
  87.         final T height = station.getBaseFrame().getPoint(field).getAltitude();
  88.         return height;
  89.     }

  90.     /** Compute the measurement error due to Troposphere.
  91.      * @param station station
  92.      * @param state spacecraft state
  93.      * @return the measurement error due to Troposphere
  94.      */
  95.     public double rangeRateErrorTroposphericModel(final GroundStation station,
  96.                                                   final SpacecraftState state) {
  97.         // The effect of tropospheric correction on the range rate is
  98.         // computed using finite differences.

  99.         final double dt = 10; // s

  100.         // station altitude AMSL in meters
  101.         final double height = getStationHeightAMSL(station);

  102.         // spacecraft position and elevation as seen from the ground station
  103.         final Vector3D position = state.getPVCoordinates().getPosition();

  104.         // elevation
  105.         final double elevation1 = station.getBaseFrame().getElevation(position,
  106.                                                                       state.getFrame(),
  107.                                                                       state.getDate());

  108.         // only consider measures above the horizon
  109.         if (elevation1 > 0) {
  110.             // tropospheric delay in meters
  111.             final double d1 = tropoModel.pathDelay(elevation1, height, tropoModel.getParameters(), state.getDate());

  112.             // propagate spacecraft state forward by dt
  113.             final SpacecraftState state2 = state.shiftedBy(dt);

  114.             // spacecraft position and elevation as seen from the ground station
  115.             final Vector3D position2 = state2.getPVCoordinates().getPosition();

  116.             // elevation
  117.             final double elevation2 = station.getBaseFrame().getElevation(position2,
  118.                                                                           state2.getFrame(),
  119.                                                                           state2.getDate());

  120.             // tropospheric delay dt after
  121.             final double d2 = tropoModel.pathDelay(elevation2, height, tropoModel.getParameters(), state2.getDate());

  122.             return fTwoWay * (d2 - d1) / dt;
  123.         }

  124.         return 0;
  125.     }


  126.     /** Compute the measurement error due to Troposphere.
  127.      * @param <T> type of the element
  128.      * @param station station
  129.      * @param state spacecraft state
  130.      * @param parameters tropospheric model parameters
  131.      * @return the measurement error due to Troposphere
  132.      */
  133.     public <T extends RealFieldElement<T>> T rangeRateErrorTroposphericModel(final GroundStation station,
  134.                                                                              final FieldSpacecraftState<T> state,
  135.                                                                              final T[] parameters) {
  136.         // Field
  137.         final Field<T> field = state.getDate().getField();
  138.         final T zero         = field.getZero();

  139.         // The effect of tropospheric correction on the range rate is
  140.         // computed using finite differences.

  141.         final double dt = 10; // s

  142.         // station altitude AMSL in meters
  143.         final T height = getStationHeightAMSL(field, station);

  144.         // spacecraft position and elevation as seen from the ground station
  145.         final FieldVector3D<T> position     = state.getPVCoordinates().getPosition();
  146.         final T elevation1                  = station.getBaseFrame().getElevation(position,
  147.                                                                                   state.getFrame(),
  148.                                                                                   state.getDate());

  149.         // only consider measures above the horizon
  150.         if (elevation1.getReal() > 0) {
  151.             // tropospheric delay in meters
  152.             final T d1 = tropoModel.pathDelay(elevation1, height, parameters, state.getDate());

  153.             // propagate spacecraft state forward by dt
  154.             final FieldSpacecraftState<T> state2 = state.shiftedBy(dt);

  155.             // spacecraft position and elevation as seen from the ground station
  156.             final FieldVector3D<T> position2     = state2.getPVCoordinates().getPosition();

  157.             // elevation
  158.             final T elevation2 = station.getBaseFrame().getElevation(position2,
  159.                                                                      state2.getFrame(),
  160.                                                                      state2.getDate());


  161.             // tropospheric delay dt after
  162.             final T d2 = tropoModel.pathDelay(elevation2, height, parameters, state2.getDate());

  163.             return (d2.subtract(d1)).divide(dt).multiply(fTwoWay);
  164.         }

  165.         return zero;
  166.     }

  167.     /** Compute the Jacobian of the delay term wrt state.
  168.     *
  169.     * @param station station
  170.     * @param refstate spacecraft state
  171.     * @return Jacobian of the delay wrt state
  172.     */
  173.     private double[][] rangeRateErrorJacobianState(final GroundStation station,
  174.                                                    final SpacecraftState refstate) {
  175.         final double[][] finiteDifferencesJacobian =
  176.                         Differentiation.differentiate(new StateFunction() {
  177.                             public double[] value(final SpacecraftState state) {
  178.                                 // evaluate target's elevation with a changed target position
  179.                                 final double value = rangeRateErrorTroposphericModel(station, state);

  180.                                 return new double[] {value };
  181.                             }
  182.                         }, 1, Propagator.DEFAULT_LAW, OrbitType.CARTESIAN,
  183.                         PositionAngle.TRUE, 15.0, 3).value(refstate);

  184.         return finiteDifferencesJacobian;
  185.     }

  186.     /** Compute the Jacobian of the delay term wrt state using
  187.     * automatic differentiation.
  188.     *
  189.     * @param derivatives tropospheric delay derivatives
  190.     * @param freeStateParameters dimension of the state.
  191.     *
  192.     * @return Jacobian of the delay wrt state
  193.     */
  194.     private double[][] rangeRateErrorJacobianState(final double[] derivatives, final int freeStateParameters) {
  195.         final double[][] finiteDifferencesJacobian = new double[1][6];
  196.         for (int i = 0; i < freeStateParameters; i++) {
  197.             // First element is the value of the delay
  198.             finiteDifferencesJacobian[0][i] = derivatives[i + 1];
  199.         }
  200.         return finiteDifferencesJacobian;
  201.     }

  202.     /** Compute the derivative of the delay term wrt parameters.
  203.     *
  204.     * @param station ground station
  205.     * @param driver driver for the station offset parameter
  206.     * @param state spacecraft state
  207.     * @return derivative of the delay wrt station offset parameter
  208.     */
  209.     private double rangeRateErrorParameterDerivative(final GroundStation station,
  210.                                                      final ParameterDriver driver,
  211.                                                      final SpacecraftState state) {

  212.         final ParameterFunction rangeError = new ParameterFunction() {
  213.             /** {@inheritDoc} */
  214.             @Override
  215.             public double value(final ParameterDriver parameterDriver) {
  216.                 return rangeRateErrorTroposphericModel(station, state);
  217.             }
  218.         };

  219.         final ParameterFunction rangeErrorDerivative =
  220.                         Differentiation.differentiate(rangeError, 3, 10.0 * driver.getScale());

  221.         return rangeErrorDerivative.value(driver);

  222.     }

  223.     /** Compute the derivative of the delay term wrt parameters using
  224.     * automatic differentiation.
  225.     *
  226.     * @param derivatives tropospheric delay derivatives
  227.     * @param freeStateParameters dimension of the state.
  228.     * @return derivative of the delay wrt tropospheric model parameters
  229.     */
  230.     private double[] rangeRateErrorParameterDerivative(final double[] derivatives, final int freeStateParameters) {
  231.         // 0                               -> value of the delay
  232.         // 1 ... freeStateParameters       -> derivatives of the delay wrt state
  233.         // freeStateParameters + 1 ... n   -> derivatives of the delay wrt tropospheric parameters
  234.         final int dim = derivatives.length - 1 - freeStateParameters;
  235.         final double[] rangeError = new double[dim];

  236.         for (int i = 0; i < dim; i++) {
  237.             rangeError[i] = derivatives[1 + freeStateParameters + i];
  238.         }

  239.         return rangeError;
  240.     }

  241.     /** {@inheritDoc} */
  242.     @Override
  243.     public List<ParameterDriver> getParametersDrivers() {
  244.         return tropoModel.getParametersDrivers();
  245.     }

  246.     /** {@inheritDoc} */
  247.     @Override
  248.     public void modify(final EstimatedMeasurement<RangeRate> estimated) {
  249.         final RangeRate       measurement = estimated.getObservedMeasurement();
  250.         final GroundStation   station     = measurement.getStation();
  251.         final SpacecraftState state       = estimated.getStates()[0];

  252.         final double[] oldValue = estimated.getEstimatedValue();

  253.         // update estimated derivatives with Jacobian of the measure wrt state
  254.         final TroposphericDSConverter converter = new TroposphericDSConverter(state, 6, Propagator.DEFAULT_LAW);
  255.         final FieldSpacecraftState<DerivativeStructure> dsState = converter.getState(tropoModel);
  256.         final DerivativeStructure[] dsParameters = converter.getParameters(dsState, tropoModel);
  257.         final DerivativeStructure dsDelay = rangeRateErrorTroposphericModel(station, dsState, dsParameters);
  258.         final double[] derivatives = dsDelay.getAllDerivatives();

  259.         double[][] djac = new double[1][6];
  260.         // This implementation will disappear when the implementations of TroposphericModel
  261.         // will directly be implementations of DiscreteTroposphericModel
  262.         if (tropoModel instanceof TroposphericModel) {
  263.             djac = rangeRateErrorJacobianState(station, state);
  264.         } else {
  265.             djac = rangeRateErrorJacobianState(derivatives, converter.getFreeStateParameters());
  266.         }
  267.         final double[][] stateDerivatives = estimated.getStateDerivatives(0);
  268.         for (int irow = 0; irow < stateDerivatives.length; ++irow) {
  269.             for (int jcol = 0; jcol < stateDerivatives[0].length; ++jcol) {
  270.                 stateDerivatives[irow][jcol] += djac[irow][jcol];
  271.             }
  272.         }
  273.         estimated.setStateDerivatives(0, stateDerivatives);

  274.         int index = 0;
  275.         for (final ParameterDriver driver : getParametersDrivers()) {
  276.             if (driver.isSelected()) {
  277.                 // update estimated derivatives with derivative of the modification wrt tropospheric parameters
  278.                 double parameterDerivative = estimated.getParameterDerivatives(driver)[0];
  279.                 final double[] dDelaydP    = rangeRateErrorParameterDerivative(derivatives, converter.getFreeStateParameters());
  280.                 parameterDerivative += dDelaydP[index];
  281.                 estimated.setParameterDerivatives(driver, parameterDerivative);
  282.                 index += 1;
  283.             }

  284.         }

  285.         for (final ParameterDriver driver : Arrays.asList(station.getClockOffsetDriver(),
  286.                                                           station.getEastOffsetDriver(),
  287.                                                           station.getNorthOffsetDriver(),
  288.                                                           station.getZenithOffsetDriver())) {
  289.             if (driver.isSelected()) {
  290.                 // update estimated derivatives with derivative of the modification wrt station parameters
  291.                 double parameterDerivative = estimated.getParameterDerivatives(driver)[0];
  292.                 parameterDerivative += rangeRateErrorParameterDerivative(station, driver, state);
  293.                 estimated.setParameterDerivatives(driver, parameterDerivative);
  294.             }
  295.         }

  296.         // update estimated value taking into account the tropospheric delay.
  297.         // The tropospheric delay is directly added to the range.
  298.         final double[] newValue = oldValue.clone();
  299.         newValue[0] = newValue[0] + dsDelay.getReal();
  300.         estimated.setEstimatedValue(newValue);

  301.     }

  302. }