TurnAroundRangeIonosphericDelayModifier.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.Collections;
  20. import java.util.List;

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

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

  46.     /** Ionospheric delay model. */
  47.     private final IonosphericModel ionoModel;

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

  55.     /** Compute the measurement error due to ionosphere.
  56.      * @param station station
  57.      * @param state spacecraft state
  58.      * @return the measurement error due to ionosphere
  59.      */
  60.     private double rangeErrorIonosphericModel(final GroundStation station,
  61.                                               final SpacecraftState state) {

  62.         // State position
  63.         final Vector3D position = state.getPVCoordinates().getPosition();

  64.         // Elevation of the satellite seen from the station
  65.         final double elevation = station.getBaseFrame().getElevation(position,
  66.                                                                      state.getFrame(),
  67.                                                                      state.getDate());

  68.         // Only consider measures above the horizon
  69.         if (elevation > 0) {

  70.             // Compute azimuth
  71.             final double azimuth = station.getBaseFrame().getAzimuth(position,
  72.                                                                      state.getFrame(),
  73.                                                                      state.getDate());

  74.             // Delay in meters
  75.             final double delay = ionoModel.pathDelay(state.getDate(),
  76.                                                      station.getBaseFrame().getPoint(),
  77.                                                      elevation, azimuth);
  78.             return delay;
  79.         }

  80.         return 0;
  81.     }

  82.     /** Compute the Jacobian of the delay term wrt state.
  83.      *
  84.      * @param station station
  85.      * @param refstate reference spacecraft state
  86.      *
  87.      * @return Jacobian of the delay wrt state
  88.      */
  89.     private double[][] rangeErrorJacobianState(final GroundStation station,
  90.                                                final SpacecraftState refstate) {
  91.         final double[][] finiteDifferencesJacobian =
  92.                         Differentiation.differentiate(new StateFunction() {
  93.                             public double[] value(final SpacecraftState state) {
  94.                                 // evaluate target's elevation with a changed target position
  95.                                 final double value = rangeErrorIonosphericModel(station, state);

  96.                                 return new double[] {
  97.                                     value
  98.                                 };
  99.                             }
  100.                         }, 1, Propagator.DEFAULT_LAW, OrbitType.CARTESIAN,
  101.                         PositionAngle.TRUE, 15.0, 3).value(refstate);

  102.         return finiteDifferencesJacobian;
  103.     }


  104.     /** Compute the derivative of the delay term wrt parameters.
  105.      *
  106.      * @param station ground station
  107.      * @param driver driver for the station offset parameter
  108.      * @param state spacecraft state
  109.      * @return derivative of the delay wrt station offset parameter
  110.      */
  111.     private double rangeErrorParameterDerivative(final GroundStation station,
  112.                                                  final ParameterDriver driver,
  113.                                                  final SpacecraftState state) {

  114.         final ParameterFunction rangeError = new ParameterFunction() {
  115.             /** {@inheritDoc} */
  116.             @Override
  117.             public double value(final ParameterDriver parameterDriver) {
  118.                 return rangeErrorIonosphericModel(station, state);
  119.             }
  120.         };

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

  123.         return rangeErrorDerivative.value(driver);

  124.     }

  125.     /** {@inheritDoc} */
  126.     @Override
  127.     public List<ParameterDriver> getParametersDrivers() {
  128.         return Collections.emptyList();
  129.     }

  130.     @Override
  131.     public void modify(final EstimatedMeasurement<TurnAroundRange> estimated) {
  132.         final TurnAroundRange measurement   = estimated.getObservedMeasurement();
  133.         final GroundStation   masterStation = measurement.getMasterStation();
  134.         final GroundStation   slaveStation  = measurement.getSlaveStation();
  135.         final SpacecraftState state         = estimated.getStates()[0];

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

  137.         // Update estimated value taking into account the ionospheric delay.
  138.         // The ionospheric delay is directly added to the TurnAroundRange.
  139.         final double masterDelay = rangeErrorIonosphericModel(masterStation, state);
  140.         final double slaveDelay = rangeErrorIonosphericModel(slaveStation, state);
  141.         final double[] newValue = oldValue.clone();
  142.         newValue[0] = newValue[0] + masterDelay + slaveDelay;
  143.         estimated.setEstimatedValue(newValue);

  144.         // Update estimated derivatives with Jacobian of the measure wrt state
  145.         final double[][] masterDjac = rangeErrorJacobianState(masterStation, state);
  146.         final double[][] slaveDjac = rangeErrorJacobianState(slaveStation, state);
  147.         final double[][] stateDerivatives = estimated.getStateDerivatives(0);
  148.         for (int irow = 0; irow < stateDerivatives.length; ++irow) {
  149.             for (int jcol = 0; jcol < stateDerivatives[0].length; ++jcol) {
  150.                 stateDerivatives[irow][jcol] += masterDjac[irow][jcol] + slaveDjac[irow][jcol];
  151.             }
  152.         }
  153.         estimated.setStateDerivatives(0, stateDerivatives);

  154.         // Update derivatives with respect to master station position
  155.         for (final ParameterDriver driver : Arrays.asList(masterStation.getClockOffsetDriver(),
  156.                                                           masterStation.getEastOffsetDriver(),
  157.                                                           masterStation.getNorthOffsetDriver(),
  158.                                                           masterStation.getZenithOffsetDriver())) {
  159.             if (driver.isSelected()) {
  160.                 double parameterDerivative = estimated.getParameterDerivatives(driver)[0];
  161.                 parameterDerivative += rangeErrorParameterDerivative(masterStation, driver, state);
  162.                 estimated.setParameterDerivatives(driver, parameterDerivative);
  163.             }
  164.         }

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

  176. }