TurnAroundRangeIonosphericDelayModifier.java

  1. /* Copyright 2002-2018 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.Collections;
  20. import java.util.List;

  21. import org.hipparchus.geometry.euclidean.threed.Vector3D;
  22. import org.orekit.errors.OrekitException;
  23. import org.orekit.errors.OrekitExceptionWrapper;
  24. import org.orekit.estimation.measurements.EstimatedMeasurement;
  25. import org.orekit.estimation.measurements.EstimationModifier;
  26. import org.orekit.estimation.measurements.GroundStation;
  27. import org.orekit.estimation.measurements.TurnAroundRange;
  28. import org.orekit.models.earth.IonosphericModel;
  29. import org.orekit.orbits.OrbitType;
  30. import org.orekit.orbits.PositionAngle;
  31. import org.orekit.propagation.Propagator;
  32. import org.orekit.propagation.SpacecraftState;
  33. import org.orekit.utils.Differentiation;
  34. import org.orekit.utils.ParameterDriver;
  35. import org.orekit.utils.ParameterFunction;
  36. import org.orekit.utils.StateFunction;

  37. /** Class modifying theoretical TurnAroundRange measurement with ionospheric delay.
  38.  * The effect of ionospheric correction on the TurnAroundRange is directly computed
  39.  * through the computation of the ionospheric delay.
  40.  *
  41.  * The ionospheric delay depends on the frequency of the signal (GNSS, VLBI, ...).
  42.  * For optical measurements (e.g. SLR), the ray is not affected by ionosphere charged particles.
  43.  *
  44.  * @author Maxime Journot
  45.  * @since 9.0
  46.  */
  47. public class TurnAroundRangeIonosphericDelayModifier implements EstimationModifier<TurnAroundRange> {

  48.     /** Ionospheric delay model. */
  49.     private final IonosphericModel ionoModel;

  50.     /** Constructor.
  51.      *
  52.      * @param model  Ionospheric delay model appropriate for the current TurnAroundRange measurement method.
  53.      */
  54.     public TurnAroundRangeIonosphericDelayModifier(final IonosphericModel model) {
  55.         ionoModel = model;
  56.     }

  57.     /** Compute the measurement error due to ionosphere.
  58.      * @param station station
  59.      * @param state spacecraft state
  60.      * @return the measurement error due to ionosphere
  61.      * @throws OrekitException  if frames transformations cannot be computed
  62.      */
  63.     private double rangeErrorIonosphericModel(final GroundStation station,
  64.                                               final SpacecraftState state)
  65.         throws OrekitException {

  66.         // State position
  67.         final Vector3D position = state.getPVCoordinates().getPosition();

  68.         // Elevation of the satellite seen from the station
  69.         final double elevation = station.getBaseFrame().getElevation(position,
  70.                                                                      state.getFrame(),
  71.                                                                      state.getDate());

  72.         // Only consider measures above the horizon
  73.         if (elevation > 0) {

  74.             // Compute azimuth
  75.             final double azimuth = station.getBaseFrame().getAzimuth(position,
  76.                                                                      state.getFrame(),
  77.                                                                      state.getDate());

  78.             // Delay in meters
  79.             final double delay = ionoModel.pathDelay(state.getDate(),
  80.                                                      station.getBaseFrame().getPoint(),
  81.                                                      elevation, azimuth);
  82.             return delay;
  83.         }

  84.         return 0;
  85.     }

  86.     /** Compute the Jacobian of the delay term wrt state.
  87.      *
  88.      * @param station station
  89.      * @param refstate reference spacecraft state
  90.      *
  91.      * @return Jacobian of the delay wrt state
  92.      * @throws OrekitException  if frames transformations cannot be computed
  93.      */
  94.     private double[][] rangeErrorJacobianState(final GroundStation station,
  95.                                                final SpacecraftState refstate)
  96.         throws OrekitException {
  97.         final double[][] finiteDifferencesJacobian =
  98.                         Differentiation.differentiate(new StateFunction() {
  99.                             public double[] value(final SpacecraftState state) throws OrekitException {
  100.                                 try {
  101.                                     // evaluate target's elevation with a changed target position
  102.                                     final double value = rangeErrorIonosphericModel(station, state);

  103.                                     return new double[] {
  104.                                         value
  105.                                     };

  106.                                 } catch (OrekitException oe) {
  107.                                     throw new OrekitExceptionWrapper(oe);
  108.                                 }
  109.                             }
  110.                         }, 1, Propagator.DEFAULT_LAW, OrbitType.CARTESIAN,
  111.                         PositionAngle.TRUE, 15.0, 3).value(refstate);

  112.         return finiteDifferencesJacobian;
  113.     }


  114.     /** Compute the derivative of the delay term wrt parameters.
  115.      *
  116.      * @param station ground station
  117.      * @param driver driver for the station offset parameter
  118.      * @param state spacecraft state
  119.      * @return derivative of the delay wrt station offset parameter
  120.      * @throws OrekitException  if frames transformations cannot be computed
  121.      */
  122.     private double rangeErrorParameterDerivative(final GroundStation station,
  123.                                                  final ParameterDriver driver,
  124.                                                  final SpacecraftState state)
  125.         throws OrekitException {

  126.         final ParameterFunction rangeError = new ParameterFunction() {
  127.             /** {@inheritDoc} */
  128.             @Override
  129.             public double value(final ParameterDriver parameterDriver) throws OrekitException {
  130.                 return rangeErrorIonosphericModel(station, state);
  131.             }
  132.         };

  133.         final ParameterFunction rangeErrorDerivative =
  134.                         Differentiation.differentiate(rangeError, driver, 3, 10.0);

  135.         return rangeErrorDerivative.value(driver);

  136.     }

  137.     /** {@inheritDoc} */
  138.     @Override
  139.     public List<ParameterDriver> getParametersDrivers() {
  140.         return Collections.emptyList();
  141.     }

  142.     @Override
  143.     public void modify(final EstimatedMeasurement<TurnAroundRange> estimated)
  144.         throws OrekitException {
  145.         final TurnAroundRange measurement   = estimated.getObservedMeasurement();
  146.         final GroundStation   masterStation = measurement.getMasterStation();
  147.         final GroundStation   slaveStation  = measurement.getSlaveStation();
  148.         final SpacecraftState state         = estimated.getStates()[0];

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

  150.         // Update estimated value taking into account the ionospheric delay.
  151.         // The ionospheric delay is directly added to the TurnAroundRange.
  152.         final double masterDelay = rangeErrorIonosphericModel(masterStation, state);
  153.         final double slaveDelay = rangeErrorIonosphericModel(slaveStation, state);
  154.         final double[] newValue = oldValue.clone();
  155.         newValue[0] = newValue[0] + masterDelay + slaveDelay;
  156.         estimated.setEstimatedValue(newValue);

  157.         // Update estimated derivatives with Jacobian of the measure wrt state
  158.         final double[][] masterDjac = rangeErrorJacobianState(masterStation, state);
  159.         final double[][] slaveDjac = rangeErrorJacobianState(slaveStation, state);
  160.         final double[][] stateDerivatives = estimated.getStateDerivatives(0);
  161.         for (int irow = 0; irow < stateDerivatives.length; ++irow) {
  162.             for (int jcol = 0; jcol < stateDerivatives[0].length; ++jcol) {
  163.                 stateDerivatives[irow][jcol] += masterDjac[irow][jcol] + slaveDjac[irow][jcol];
  164.             }
  165.         }
  166.         estimated.setStateDerivatives(0, stateDerivatives);

  167.         // Update derivatives with respect to master station position
  168.         for (final ParameterDriver driver : Arrays.asList(masterStation.getEastOffsetDriver(),
  169.                                                           masterStation.getNorthOffsetDriver(),
  170.                                                           masterStation.getZenithOffsetDriver())) {
  171.             if (driver.isSelected()) {
  172.                 double parameterDerivative = estimated.getParameterDerivatives(driver)[0];
  173.                 parameterDerivative += rangeErrorParameterDerivative(masterStation, driver, state);
  174.                 estimated.setParameterDerivatives(driver, parameterDerivative);
  175.             }
  176.         }

  177.         // Update derivatives with respect to slave station position
  178.         for (final ParameterDriver driver : Arrays.asList(slaveStation.getEastOffsetDriver(),
  179.                                                           slaveStation.getNorthOffsetDriver(),
  180.                                                           slaveStation.getZenithOffsetDriver())) {
  181.             if (driver.isSelected()) {
  182.                 double parameterDerivative = estimated.getParameterDerivatives(driver)[0];
  183.                 parameterDerivative += rangeErrorParameterDerivative(slaveStation, driver, state);
  184.                 estimated.setParameterDerivatives(driver, parameterDerivative);
  185.             }
  186.         }
  187.     }

  188. }