AskneNordiusModel.java

  1. /* Copyright 2022-2025 Thales Alenia Space
  2.  * Licensed to CS Communication & Systèmes (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.troposphere;

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

  20. import org.hipparchus.CalculusFieldElement;
  21. import org.orekit.bodies.FieldGeodeticPoint;
  22. import org.orekit.bodies.GeodeticPoint;
  23. import org.orekit.models.earth.weather.FieldPressureTemperatureHumidity;
  24. import org.orekit.models.earth.weather.PressureTemperatureHumidity;
  25. import org.orekit.models.earth.weather.PressureTemperatureHumidityProvider;
  26. import org.orekit.time.AbsoluteDate;
  27. import org.orekit.time.FieldAbsoluteDate;
  28. import org.orekit.utils.Constants;
  29. import org.orekit.utils.FieldTrackingCoordinates;
  30. import org.orekit.utils.ParameterDriver;
  31. import org.orekit.utils.TrackingCoordinates;

  32. /** The Askne Nordius model.
  33.  * <p>
  34.  * The hydrostatic part is equivalent to Saastamoinen, whereas the wet part takes
  35.  * into account {@link PressureTemperatureHumidity#getTm() mean temperature weighted
  36.  * with water vapor pressure} and {@link PressureTemperatureHumidity#getLambda() water
  37.  * vapor decrease factor}.
  38.  * </p>
  39.  * @author Luc Maisonobe
  40.  * @see "J. Askne and H. Nordius, Estimation of tropospheric delay for microwaves
  41.  *      from surface weather data, Radio Science, volume 22, number 3, pages 379-386,
  42.  *      May-June 1987"
  43.  * @see "Landskron D (2017) Modeling tropospheric delays for space geodetic
  44.  *      techniques. Dissertation, Department of Geodesy and Geoinformation, TU Wien, Supervisor: J. Böhm.
  45.  *      http://repositum.tuwien.ac.at/urn:nbn:at:at-ubtuw:1-100249"
  46.  * @since 12.1
  47.  */
  48. public class AskneNordiusModel implements TroposphericModel {

  49.     /** Lowest acceptable elevation angle [rad]. */
  50.     public static final double LOW_ELEVATION_THRESHOLD = 0.05;

  51.     /** Base delay coefficient (from Saastamoninen model). */
  52.     private static final double L0 = 2.2768e-5;

  53.     /** Askne-Nordius coefficient k'₂. */
  54.     private static final double K_PRIME_2 = 16.5203;

  55.     /** Askne-Nordius coefficient k₃. */
  56.     private static final double K_3 = 377600;

  57.     /** Gas constant for dry components. */
  58.     private static final double RD = 287.0464;

  59.     /** Unit consversion factor. */
  60.     private static final double FACTOR = 1.0e-6;

  61.     /** Mapping function. */
  62.     private final TroposphereMappingFunction mappingFunction;

  63.     /** Provider for pressure, temperature and humidity.
  64.      * @since 13.0
  65.      */
  66.     private final PressureTemperatureHumidityProvider pthProvider;

  67.     /** Create a new Askne Nordius model.
  68.      * @param mappingFunction mapping function
  69.      * @param pthProvider provider for pressure, temperature and humidity
  70.      */
  71.     public AskneNordiusModel(final TroposphereMappingFunction mappingFunction,
  72.                              final PressureTemperatureHumidityProvider pthProvider) {
  73.         this.mappingFunction = mappingFunction;
  74.         this.pthProvider     = pthProvider;
  75.     }

  76.     /** {@inheritDoc} */
  77.     @Override
  78.     public TroposphericDelay pathDelay(final TrackingCoordinates trackingCoordinates, final GeodeticPoint point,
  79.                                        final double[] parameters, final AbsoluteDate date) {

  80.         final double[] mf = mappingFunction.mappingFactors(trackingCoordinates, point, date);

  81.         // compute weather parameters
  82.         final PressureTemperatureHumidity weather = pthProvider.getWeatherParameters(point, date);

  83.         // compute the path delay
  84.         final double zh     = L0 * weather.getPressure();
  85.         final double zw     = FACTOR * (K_PRIME_2 + K_3 / weather.getTm()) *
  86.                               RD * weather.getWaterVaporPressure() /
  87.                               (Constants.G0_STANDARD_GRAVITY * (weather.getLambda() + 1.0));
  88.         final double sh     = zh * mf[0];
  89.         final double sw     = zw * mf[1];
  90.         return new TroposphericDelay(zh, zw, sh, sw);

  91.     }

  92.     /** {@inheritDoc} */
  93.     @Override
  94.     public <T extends CalculusFieldElement<T>> FieldTroposphericDelay<T> pathDelay(final FieldTrackingCoordinates<T> trackingCoordinates,
  95.                                                                                    final FieldGeodeticPoint<T> point,
  96.                                                                                    final T[] parameters, final FieldAbsoluteDate<T> date) {

  97.         final T[] mf = mappingFunction.mappingFactors(trackingCoordinates, point, date);

  98.         // compute weather parameters
  99.         final FieldPressureTemperatureHumidity<T> weather = pthProvider.getWeatherParameters(point, date);

  100.         // compute the path delay
  101.         final T zh     = weather.getPressure().multiply(L0);
  102.         final T zw     = weather.getTm().reciprocal().multiply(K_3).add(K_PRIME_2).
  103.                          multiply(weather.getWaterVaporPressure().multiply(RD)).
  104.                          divide(weather.getLambda().add(1.0).multiply(Constants.G0_STANDARD_GRAVITY)).
  105.                          multiply(FACTOR);
  106.         final T sh     = zh.multiply(mf[0]);
  107.         final T sw     = zw.multiply(mf[1]);
  108.         return new FieldTroposphericDelay<>(zh, zw, sh, sw);

  109.     }

  110.     /** {@inheritDoc} */
  111.     @Override
  112.     public List<ParameterDriver> getParametersDrivers() {
  113.         return Collections.emptyList();
  114.     }

  115. }