RangeTroposphericDelayModifier.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.Range;
  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 measurement with tropospheric delay.
  41.  * The effect of tropospheric correction on the range is directly computed
  42.  * through the computation of the tropospheric delay.
  43.  *
  44.  * In general, for GNSS, VLBI, ... there is hardly any frequency dependence in the delay.
  45.  * For SLR techniques however, the frequency dependence is sensitive.
  46.  *
  47.  * @author Maxime Journot
  48.  * @author Joris Olympio
  49.  * @since 8.0
  50.  */
  51. public class RangeTroposphericDelayModifier implements EstimationModifier<Range> {

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

  54.     /** Constructor.
  55.      *
  56.      * @param model  Tropospheric delay model appropriate for the current range measurement method.
  57.      */
  58.     public RangeTroposphericDelayModifier(final DiscreteTroposphericModel model) {
  59.         tropoModel = model;
  60.     }

  61.     /** Get the station height above mean sea level.
  62.      *
  63.      * @param station  ground station (or measuring station)
  64.      * @return the measuring station height above sea level, m
  65.      */
  66.     private double getStationHeightAMSL(final GroundStation station) {
  67.         // FIXME heigth should be computed with respect to geoid WGS84+GUND = EGM2008 for example
  68.         final double height = station.getBaseFrame().getPoint().getAltitude();
  69.         return height;
  70.     }

  71.     /** Get the station height above mean sea level.
  72.     * @param <T> type of the elements
  73.     * @param field field of the elements
  74.     * @param station  ground station (or measuring station)
  75.     * @return the measuring station height above sea level, m
  76.     */
  77.     private <T extends RealFieldElement<T>> T getStationHeightAMSL(final Field<T> field, final GroundStation station) {
  78.         // FIXME heigth should be computed with respect to geoid WGS84+GUND = EGM2008 for example
  79.         final T height = station.getBaseFrame().getPoint(field).getAltitude();
  80.         return height;
  81.     }

  82.     /** Compute the measurement error due to Troposphere.
  83.      * @param station station
  84.      * @param state spacecraft state
  85.      * @return the measurement error due to Troposphere
  86.      */
  87.     private double rangeErrorTroposphericModel(final GroundStation station, final SpacecraftState state) {
  88.         //
  89.         final Vector3D position = state.getPVCoordinates().getPosition();

  90.         // elevation
  91.         final double elevation = station.getBaseFrame().getElevation(position,
  92.                                                                      state.getFrame(),
  93.                                                                      state.getDate());

  94.         // only consider measures above the horizon
  95.         if (elevation > 0) {
  96.             // altitude AMSL in meters
  97.             final double height = getStationHeightAMSL(station);

  98.             // delay in meters
  99.             final double delay = tropoModel.pathDelay(elevation, height, tropoModel.getParameters(), state.getDate());

  100.             return delay;
  101.         }

  102.         return 0;
  103.     }

  104.     /** Compute the measurement error due to Troposphere.
  105.      * @param <T> type of the element
  106.      * @param station station
  107.      * @param state spacecraft state
  108.      * @param parameters tropospheric model parameters
  109.      * @return the measurement error due to Troposphere
  110.      */
  111.     private <T extends RealFieldElement<T>> T rangeErrorTroposphericModel(final GroundStation station,
  112.                                                                           final FieldSpacecraftState<T> state,
  113.                                                                           final T[] parameters) {

  114.         // Field
  115.         final Field<T> field = state.getDate().getField();
  116.         final T zero         = field.getZero();

  117.         // satellite elevation
  118.         final FieldVector3D<T> position     = state.getPVCoordinates().getPosition();
  119.         final T elevation                   = station.getBaseFrame().getElevation(position,
  120.                                                                                   state.getFrame(),
  121.                                                                                   state.getDate());


  122.         // only consider measures above the horizon
  123.         if (elevation.getReal() > 0) {
  124.             // altitude AMSL in meters
  125.             final T height = getStationHeightAMSL(field, station);

  126.             // delay in meters
  127.             final T delay = tropoModel.pathDelay(elevation, height, parameters, state.getDate());

  128.             return delay;
  129.         }

  130.         return zero;
  131.     }

  132.     /** Compute the Jacobian of the delay term wrt state using
  133.     * automatic differentiation.
  134.     *
  135.     * @param derivatives tropospheric delay derivatives
  136.     * @param freeStateParameters dimension of the state.
  137.     *
  138.     * @return Jacobian of the delay wrt state
  139.     */
  140.     private double[][] rangeErrorJacobianState(final double[] derivatives, final int freeStateParameters) {
  141.         final double[][] finiteDifferencesJacobian = new double[1][6];
  142.         for (int i = 0; i < freeStateParameters; i++) {
  143.             // First element is the value of the delay
  144.             finiteDifferencesJacobian[0][i] = derivatives[i + 1];
  145.         }
  146.         return finiteDifferencesJacobian;
  147.     }

  148.     /** Compute the Jacobian of the delay term wrt state.
  149.     *
  150.     * @param station station
  151.     * @param refstate reference spacecraft state
  152.     *
  153.     * @return Jacobian of the delay wrt state
  154.     */
  155.     private double[][] rangeErrorJacobianState(final GroundStation station, final SpacecraftState refstate) {
  156.         final double[][] finiteDifferencesJacobian =
  157.                        Differentiation.differentiate(new StateFunction() {
  158.                            public double[] value(final SpacecraftState state) {
  159.                                // evaluate target's elevation with a changed target position
  160.                                final double value = rangeErrorTroposphericModel(station, state);

  161.                                return new double[] {value };
  162.                            }
  163.                        }, 1, Propagator.DEFAULT_LAW, OrbitType.CARTESIAN,
  164.                        PositionAngle.TRUE, 15.0, 3).value(refstate);

  165.         return finiteDifferencesJacobian;
  166.     }

  167.     /** Compute the derivative of the delay term wrt parameters.
  168.      *
  169.      * @param station ground station
  170.      * @param driver driver for the station offset parameter
  171.      * @param state spacecraft state
  172.      * @return derivative of the delay wrt station offset parameter
  173.      */
  174.     private double rangeErrorParameterDerivative(final GroundStation station,
  175.                                                  final ParameterDriver driver,
  176.                                                  final SpacecraftState state) {

  177.         final ParameterFunction rangeError = new ParameterFunction() {
  178.             /** {@inheritDoc} */
  179.             @Override
  180.             public double value(final ParameterDriver parameterDriver) {
  181.                 return rangeErrorTroposphericModel(station, state);
  182.             }
  183.         };

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

  186.         return rangeErrorDerivative.value(driver);

  187.     }

  188.     /** Compute the derivative of the delay term wrt parameters using
  189.     * automatic differentiation.
  190.     *
  191.     * @param derivatives tropospheric delay derivatives
  192.     * @param freeStateParameters dimension of the state.
  193.     * @return derivative of the delay wrt tropospheric model parameters
  194.     */
  195.     private double[] rangeErrorParameterDerivative(final double[] derivatives, final int freeStateParameters) {
  196.         // 0                               -> value of the delay
  197.         // 1 ... freeStateParameters       -> derivatives of the delay wrt state
  198.         // freeStateParameters + 1 ... n   -> derivatives of the delay wrt tropospheric parameters
  199.         final int dim = derivatives.length - 1 - freeStateParameters;
  200.         final double[] rangeError = new double[dim];

  201.         for (int i = 0; i < dim; i++) {
  202.             rangeError[i] = derivatives[1 + freeStateParameters + i];
  203.         }

  204.         return rangeError;
  205.     }

  206.     /** {@inheritDoc} */
  207.     @Override
  208.     public List<ParameterDriver> getParametersDrivers() {
  209.         return tropoModel.getParametersDrivers();
  210.     }

  211.     /** {@inheritDoc} */
  212.     @Override
  213.     public void modify(final EstimatedMeasurement<Range> estimated) {
  214.         final Range           measurement = estimated.getObservedMeasurement();
  215.         final GroundStation   station     = measurement.getStation();
  216.         final SpacecraftState state       = estimated.getStates()[0];

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

  218.         // update estimated derivatives with Jacobian of the measure wrt state
  219.         final TroposphericDSConverter converter = new TroposphericDSConverter(state, 6, Propagator.DEFAULT_LAW);
  220.         final FieldSpacecraftState<DerivativeStructure> dsState = converter.getState(tropoModel);
  221.         final DerivativeStructure[] dsParameters = converter.getParameters(dsState, tropoModel);
  222.         final DerivativeStructure dsDelay = rangeErrorTroposphericModel(station, dsState, dsParameters);
  223.         final double[] derivatives = dsDelay.getAllDerivatives();

  224.         double[][] djac = new double[1][6];
  225.         // This implementation will disappear when the implementations of TroposphericModel
  226.         // will directly be implementations of DiscreteTroposphericModel
  227.         if (tropoModel instanceof TroposphericModel) {
  228.             djac = rangeErrorJacobianState(station, state);
  229.         } else {
  230.             djac = rangeErrorJacobianState(derivatives, converter.getFreeStateParameters());
  231.         }

  232.         final double[][] stateDerivatives = estimated.getStateDerivatives(0);
  233.         for (int irow = 0; irow < stateDerivatives.length; ++irow) {
  234.             for (int jcol = 0; jcol < stateDerivatives[0].length; ++jcol) {
  235.                 stateDerivatives[irow][jcol] += djac[irow][jcol];
  236.             }
  237.         }
  238.         estimated.setStateDerivatives(0, stateDerivatives);

  239.         int index = 0;
  240.         for (final ParameterDriver driver : getParametersDrivers()) {
  241.             if (driver.isSelected()) {
  242.                 // update estimated derivatives with derivative of the modification wrt tropospheric parameters
  243.                 double parameterDerivative = estimated.getParameterDerivatives(driver)[0];
  244.                 final double[] dDelaydP    = rangeErrorParameterDerivative(derivatives, converter.getFreeStateParameters());
  245.                 parameterDerivative += dDelaydP[index];
  246.                 estimated.setParameterDerivatives(driver, parameterDerivative);
  247.                 index = index + 1;
  248.             }

  249.         }

  250.         for (final ParameterDriver driver : Arrays.asList(station.getClockOffsetDriver(),
  251.                                                           station.getEastOffsetDriver(),
  252.                                                           station.getNorthOffsetDriver(),
  253.                                                           station.getZenithOffsetDriver())) {
  254.             if (driver.isSelected()) {
  255.                 // update estimated derivatives with derivative of the modification wrt station parameters
  256.                 double parameterDerivative = estimated.getParameterDerivatives(driver)[0];
  257.                 parameterDerivative += rangeErrorParameterDerivative(station, driver, state);
  258.                 estimated.setParameterDerivatives(driver, parameterDerivative);
  259.             }
  260.         }

  261.         // update estimated value taking into account the tropospheric delay.
  262.         // The tropospheric delay is directly added to the range.
  263.         final double[] newValue = oldValue.clone();
  264.         newValue[0] = newValue[0] + dsDelay.getReal();
  265.         estimated.setEstimatedValue(newValue);

  266.     }

  267. }