ViennaOneModel.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.models.earth;

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

  20. import org.hipparchus.Field;
  21. import org.hipparchus.RealFieldElement;
  22. import org.hipparchus.util.FastMath;
  23. import org.hipparchus.util.MathArrays;
  24. import org.orekit.time.AbsoluteDate;
  25. import org.orekit.time.DateTimeComponents;
  26. import org.orekit.time.FieldAbsoluteDate;
  27. import org.orekit.time.TimeScalesFactory;
  28. import org.orekit.utils.ParameterDriver;

  29. /** The Vienna1 tropospheric delay model for radio techniques.
  30.  * The Vienna model data are given with a time interval of 6 hours
  31.  * as well as on a global 2.5° * 2.0° grid.
  32.  *
  33.  * This version considered the height correction for the hydrostatic part
  34.  * developed by Niell, 1996.
  35.  *
  36.  * @see Boehm, J., Werl, B., and Schuh, H., (2006),
  37.  *      "Troposhere mapping functions for GPS and very long baseline
  38.  *      interferometry from European Centre for Medium-Range Weather
  39.  *      Forecasts operational analysis data," J. Geophy. Res., Vol. 111,
  40.  *      B02406, doi:10.1029/2005JB003629
  41.  *
  42.  * @author Bryan Cazabonne
  43.  */
  44. public class ViennaOneModel implements DiscreteTroposphericModel {

  45.     /** Serializable UID. */
  46.     private static final long serialVersionUID = 2584920506094034855L;

  47.     /** The a coefficient for the computation of the wet and hydrostatic mapping functions.*/
  48.     private final double[] coefficientsA;

  49.     /** Values of hydrostatic and wet delays as provided by the Vienna model. */
  50.     private final double[] zenithDelay;

  51.     /** Geodetic site latitude, radians.*/
  52.     private final double latitude;

  53.     /** Build a new instance.
  54.      * @param coefficientA The a coefficients for the computation of the wet and hydrostatic mapping functions.
  55.      * @param zenithDelay Values of hydrostatic and wet delays
  56.      * @param latitude geodetic latitude of the station, in radians
  57.      */
  58.     public ViennaOneModel(final double[] coefficientA, final double[] zenithDelay,
  59.                           final double latitude) {
  60.         this.coefficientsA = coefficientA.clone();
  61.         this.zenithDelay   = zenithDelay.clone();
  62.         this.latitude      = latitude;
  63.     }

  64.     /** {@inheritDoc} */
  65.     @Override
  66.     public double pathDelay(final double elevation, final double height,
  67.                             final double[] parameters, final AbsoluteDate date) {
  68.         // zenith delay
  69.         final double[] delays = computeZenithDelay(height, parameters, date);
  70.         // mapping function
  71.         final double[] mappingFunction = mappingFactors(elevation, height, parameters, date);
  72.         // Tropospheric path delay
  73.         return delays[0] * mappingFunction[0] + delays[1] * mappingFunction[1];
  74.     }

  75.     /** {@inheritDoc} */
  76.     @Override
  77.     public <T extends RealFieldElement<T>> T pathDelay(final T elevation, final T height,
  78.                                                        final T[] parameters, final FieldAbsoluteDate<T> date) {
  79.         // zenith delay
  80.         final T[] delays = computeZenithDelay(height, parameters, date);
  81.         // mapping function
  82.         final T[] mappingFunction = mappingFactors(elevation, height, parameters, date);
  83.         // Tropospheric path delay
  84.         return delays[0].multiply(mappingFunction[0]).add(delays[1].multiply(mappingFunction[1]));
  85.     }

  86.     /** {@inheritDoc} */
  87.     @Override
  88.     public double[] computeZenithDelay(final double height, final double[] parameters, final AbsoluteDate date) {
  89.         return zenithDelay;
  90.     }

  91.     /** {@inheritDoc} */
  92.     @Override
  93.     public <T extends RealFieldElement<T>> T[] computeZenithDelay(final T height, final T[] parameters,
  94.                                                                   final FieldAbsoluteDate<T> date) {
  95.         final Field<T> field = height.getField();
  96.         final T zero = field.getZero();
  97.         final T[] delays = MathArrays.buildArray(field, 2);
  98.         delays[0] = zero.add(zenithDelay[0]);
  99.         delays[1] = zero.add(zenithDelay[1]);
  100.         return delays;
  101.     }

  102.     /** {@inheritDoc} */
  103.     @Override
  104.     public double[] mappingFactors(final double elevation, final double height,
  105.                                    final double[] parameters, final AbsoluteDate date) {
  106.         // Day of year computation
  107.         final DateTimeComponents dtc = date.getComponents(TimeScalesFactory.getUTC());
  108.         final int dofyear = dtc.getDate().getDayOfYear();

  109.         // General constants | Hydrostatic part
  110.         final double bh  = 0.0029;
  111.         final double c0h = 0.062;
  112.         final double c10h;
  113.         final double c11h;
  114.         final double psi;

  115.         // sin(latitude) > 0 -> northern hemisphere
  116.         if (FastMath.sin(latitude) > 0) {
  117.             c10h = 0.001;
  118.             c11h = 0.005;
  119.             psi  = 0;
  120.         } else {
  121.             c10h = 0.002;
  122.             c11h = 0.007;
  123.             psi  = FastMath.PI;
  124.         }

  125.         // Temporal factor
  126.         double t0 = 28;
  127.         if (latitude < 0) {
  128.             // southern hemisphere: t0 = 28 + an integer half of year
  129.             t0 += 183;
  130.         }
  131.         // Compute hydrostatique coefficient c
  132.         final double coef = ((dofyear - t0) / 365) * 2 * FastMath.PI + psi;
  133.         final double ch = c0h + ((FastMath.cos(coef) + 1) * (c11h / 2) + c10h) * (1 - FastMath.cos(latitude));

  134.         // General constants | Wet part
  135.         final double bw = 0.00146;
  136.         final double cw = 0.04391;

  137.         final double[] function = new double[2];
  138.         function[0] = computeFunction(coefficientsA[0], bh, ch, elevation);
  139.         function[1] = computeFunction(coefficientsA[1], bw, cw, elevation);

  140.         // Apply height correction
  141.         final double correction = computeHeightCorrection(elevation, height);
  142.         function[0] = function[0] + correction;

  143.         return function;
  144.     }

  145.     /** {@inheritDoc} */
  146.     @Override
  147.     public <T extends RealFieldElement<T>> T[] mappingFactors(final T elevation, final T height,
  148.                                                               final T[] parameters, final FieldAbsoluteDate<T> date) {
  149.         final Field<T> field = date.getField();
  150.         final T zero = field.getZero();

  151.         // Day of year computation
  152.         final DateTimeComponents dtc = date.getComponents(TimeScalesFactory.getUTC());
  153.         final int dofyear = dtc.getDate().getDayOfYear();

  154.         // General constants | Hydrostatic part
  155.         final T bh  = zero.add(0.0029);
  156.         final T c0h = zero.add(0.062);
  157.         final T c10h;
  158.         final T c11h;
  159.         final T psi;

  160.         // sin(latitude) > 0 -> northern hemisphere
  161.         if (FastMath.sin(latitude) > 0) {
  162.             c10h = zero.add(0.001);
  163.             c11h = zero.add(0.005);
  164.             psi  = zero;
  165.         } else {
  166.             c10h = zero.add(0.002);
  167.             c11h = zero.add(0.007);
  168.             psi  = zero.add(FastMath.PI);
  169.         }

  170.         // Compute hydrostatique coefficient c
  171.         // Temporal factor
  172.         double t0 = 28;
  173.         if (latitude < 0) {
  174.             // southern hemisphere: t0 = 28 + an integer half of year
  175.             t0 += 183;
  176.         }
  177.         final T coef = psi.add(((dofyear - t0) / 365) * 2 * FastMath.PI);
  178.         final T ch = c11h.divide(2.0).multiply(FastMath.cos(coef).add(1.0)).add(c10h).multiply(1 - FastMath.cos(latitude)).add(c0h);

  179.         // General constants | Wet part
  180.         final T bw = zero.add(0.00146);
  181.         final T cw = zero.add(0.04391);

  182.         final T[] function = MathArrays.buildArray(field, 2);
  183.         function[0] = computeFunction(zero.add(coefficientsA[0]), bh, ch, elevation);
  184.         function[1] = computeFunction(zero.add(coefficientsA[1]), bw, cw, elevation);

  185.         // Apply height correction
  186.         final T correction = computeHeightCorrection(elevation, height, field);
  187.         function[0] = function[0].add(correction);

  188.         return function;
  189.     }

  190.     /** {@inheritDoc} */
  191.     @Override
  192.     public List<ParameterDriver> getParametersDrivers() {
  193.         return Collections.emptyList();
  194.     }

  195.     /** Compute the mapping function related to the coefficient values and the elevation.
  196.      * @param a a coefficient
  197.      * @param b b coefficient
  198.      * @param c c coefficient
  199.      * @param elevation the elevation of the satellite, in radians.
  200.      * @return the value of the function at a given elevation
  201.      */
  202.     private double computeFunction(final double a, final double b, final double c, final double elevation) {
  203.         final double sinE = FastMath.sin(elevation);
  204.         // Numerator
  205.         final double numMP = 1 + a / (1 + b / (1 + c));
  206.         // Denominator
  207.         final double denMP = sinE + a / (sinE + b / (sinE + c));

  208.         final double felevation = numMP / denMP;

  209.         return felevation;
  210.     }

  211.     /** Compute the mapping function related to the coefficient values and the elevation.
  212.      * @param <T> type of the elements
  213.      * @param a a coefficient
  214.      * @param b b coefficient
  215.      * @param c c coefficient
  216.      * @param elevation the elevation of the satellite, in radians.
  217.      * @return the value of the function at a given elevation
  218.      */
  219.     private <T extends RealFieldElement<T>> T computeFunction(final T a, final T b, final T c, final T elevation) {
  220.         final T sinE = FastMath.sin(elevation);
  221.         // Numerator
  222.         final T numMP = a.divide(b.divide(c.add(1.0)).add(1.0)).add(1.0);
  223.         // Denominator
  224.         final T denMP = a.divide(b.divide(c.add(sinE)).add(sinE)).add(sinE);

  225.         final T felevation = numMP.divide(denMP);

  226.         return felevation;
  227.     }

  228.     /** This method computes the height correction for the hydrostatic
  229.      *  component of the mapping function.
  230.      *  The formulas are given by Neill's paper, 1996:
  231.      *<p>
  232.      *      Niell A. E. (1996)
  233.      *      "Global mapping functions for the atmosphere delay of radio wavelengths,”
  234.      *      J. Geophys. Res., 101(B2), pp.  3227–3246, doi:  10.1029/95JB03048.
  235.      *</p>
  236.      * @param elevation the elevation of the satellite, in radians.
  237.      * @param height the height of the station in m above sea level.
  238.      * @return the height correction, in m
  239.      */
  240.     private double computeHeightCorrection(final double elevation, final double height) {
  241.         final double fixedHeight = FastMath.max(0.0, height);
  242.         final double sinE = FastMath.sin(elevation);
  243.         // Ref: Eq. 4
  244.         final double function = computeFunction(2.53e-5, 5.49e-3, 1.14e-3, elevation);
  245.         // Ref: Eq. 6
  246.         final double dmdh = (1 / sinE) - function;
  247.         // Ref: Eq. 7
  248.         final double correction = dmdh * (fixedHeight / 1000);
  249.         return correction;
  250.     }

  251.     /** This method computes the height correction for the hydrostatic
  252.      *  component of the mapping function.
  253.      *  The formulas are given by Neill's paper, 1996:
  254.      *<p>
  255.      *      Niell A. E. (1996)
  256.      *      "Global mapping functions for the atmosphere delay of radio wavelengths,”
  257.      *      J. Geophys. Res., 101(B2), pp.  3227–3246, doi:  10.1029/95JB03048.
  258.      *</p>
  259.      * @param <T> type of the elements
  260.      * @param elevation the elevation of the satellite, in radians.
  261.      * @param height the height of the station in m above sea level.
  262.      * @param field field to which the elements belong
  263.      * @return the height correction, in m
  264.      */
  265.     private <T extends RealFieldElement<T>> T computeHeightCorrection(final T elevation, final T height, final Field<T> field) {
  266.         final T zero = field.getZero();
  267.         final T fixedHeight = FastMath.max(zero, height);
  268.         final T sinE = FastMath.sin(elevation);
  269.         // Ref: Eq. 4
  270.         final T function = computeFunction(zero.add(2.53e-5), zero.add(5.49e-3), zero.add(1.14e-3), elevation);
  271.         // Ref: Eq. 6
  272.         final T dmdh = sinE.reciprocal().subtract(function);
  273.         // Ref: Eq. 7
  274.         final T correction = dmdh.multiply(fixedHeight.divide(1000.0));
  275.         return correction;
  276.     }

  277. }