RangeIonosphericDelayModifier.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.Range;
  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 range measurement with ionospheric delay.
  36.  * The effect of ionospheric correction on the range 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.  * @author Joris Olympio
  44.  * @since 8.0
  45.  */
  46. public class RangeIonosphericDelayModifier implements EstimationModifier<Range> {

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

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

  56.     /** Compute the measurement error due to ionosphere.
  57.      * @param station station
  58.      * @param state spacecraft state
  59.      * @return the measurement error due to ionosphere
  60.      */
  61.     private double rangeErrorIonosphericModel(final GroundStation station,
  62.                                               final SpacecraftState state) {
  63.         //
  64.         final Vector3D position = state.getPVCoordinates().getPosition();

  65.         // elevation
  66.         final double elevation = station.getBaseFrame().getElevation(position,
  67.                                                                      state.getFrame(),
  68.                                                                      state.getDate());

  69.         // only consider measures above the horizon
  70.         if (elevation > 0) {

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

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

  81.         return 0;
  82.     }

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

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

  103.         return finiteDifferencesJacobian;
  104.     }


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

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

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

  126.         return rangeErrorDerivative.value(driver);

  127.     }

  128.     /** {@inheritDoc} */
  129.     @Override
  130.     public List<ParameterDriver> getParametersDrivers() {
  131.         return Collections.emptyList();
  132.     }

  133.     @Override
  134.     public void modify(final EstimatedMeasurement<Range> estimated) {
  135.         final Range           measurement = estimated.getObservedMeasurement();
  136.         final GroundStation   station     = measurement.getStation();
  137.         final SpacecraftState state       = estimated.getStates()[0];

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

  139.         final double delay = rangeErrorIonosphericModel(station, state);

  140.         // update estimated value taking into account the ionospheric delay.
  141.         // The ionospheric delay is directly added to the range.
  142.         final double[] newValue = oldValue.clone();
  143.         newValue[0] = newValue[0] + delay;
  144.         estimated.setEstimatedValue(newValue);

  145.         // update estimated derivatives with Jacobian of the measure wrt state
  146.         final double[][] djac = rangeErrorJacobianState(station, 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] += djac[irow][jcol];
  151.             }
  152.         }
  153.         estimated.setStateDerivatives(0, stateDerivatives);

  154.         for (final ParameterDriver driver : Arrays.asList(station.getClockOffsetDriver(),
  155.                                                           station.getEastOffsetDriver(),
  156.                                                           station.getNorthOffsetDriver(),
  157.                                                           station.getZenithOffsetDriver())) {
  158.             if (driver.isSelected()) {
  159.                 // update estimated derivatives with derivative of the modification wrt station parameters
  160.                 double parameterDerivative = estimated.getParameterDerivatives(driver)[0];
  161.                 parameterDerivative += rangeErrorParameterDerivative(station, driver, state, delay);
  162.                 estimated.setParameterDerivatives(driver, parameterDerivative);
  163.             }
  164.         }

  165.     }

  166. }