GLONASSDate.java

  1. /* Copyright 2002-2024 CS GROUP
  2.  * Licensed to CS GROUP (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.time;

  18. import java.io.Serializable;

  19. import org.hipparchus.util.FastMath;
  20. import org.orekit.annotation.DefaultDataContext;
  21. import org.orekit.data.DataContext;
  22. import org.orekit.propagation.analytical.gnss.data.GNSSConstants;
  23. import org.orekit.utils.Constants;

  24. /**
  25.  * Container for date in GLONASS form.
  26.  * @author Bryan Cazabonne
  27.  * @see AbsoluteDate
  28.  * @see "GLONASS Interface Control Document v1.0, 2016"
  29.  * @since 10.0
  30.  */
  31. public class GLONASSDate implements Serializable, TimeStamped {

  32.     /** Serializable UID. */
  33.     private static final long serialVersionUID = 20190131L;

  34.     /** Constant for date computation. */
  35.     private static final int C1 = 44195;

  36.     /** Constant for date computation. */
  37.     private static final int C2 = 45290;

  38.     /** The number of the current day in a four year interval N<sub>a</sub>. */
  39.     private final int na;

  40.     /** The number of the current four year interval N<sub>4</sub>. */
  41.     private final int n4;

  42.     /** Number of seconds since N<sub>a</sub>. */
  43.     private final double secInNa;

  44.     /** Current Julian date JD0. */
  45.     private double jd0;

  46.     /** Greenwich Mean Sidereal Time (rad). */
  47.     private double gmst;

  48.     /** Corresponding date. */
  49.     private final transient AbsoluteDate date;

  50.     /** Build an instance corresponding to a GLONASS date.
  51.      *
  52.      * <p>This method uses the {@link DataContext#getDefault() default data context}.
  53.      *
  54.      * @param na the number of the current day in a four year interval
  55.      * @param n4 the number of the current four year interval
  56.      * @param secInNa the number of seconds since na start
  57.      * @see #GLONASSDate(int, int, double, TimeScale)
  58.      */
  59.     @DefaultDataContext
  60.     public GLONASSDate(final int na, final int n4, final double secInNa) {
  61.         this(na, n4, secInNa, DataContext.getDefault().getTimeScales().getGLONASS());
  62.     }

  63.     /**
  64.      * Build an instance corresponding to a GLONASS date.
  65.      *
  66.      * @param na      the number of the current day in a four year interval
  67.      * @param n4      the number of the current four year interval
  68.      * @param secInNa the number of seconds since na start
  69.      * @param glonass time scale.
  70.      * @since 10.1
  71.      */
  72.     public GLONASSDate(final int na,
  73.                        final int n4,
  74.                        final double secInNa,
  75.                        final TimeScale glonass) {
  76.         this.na      = na;
  77.         this.n4      = n4;
  78.         this.secInNa = secInNa;
  79.         // Compute JD0
  80.         final int ratio = FastMath.round((float) (na - 3) / (25 + C1 + C2));
  81.         this.jd0  = 1461 * (n4 - 1) + na + 2450082.5 - ratio;
  82.         // GMST
  83.         this.gmst = computeGMST();
  84.         this.date = computeDate(glonass);
  85.     }

  86.     /** Build an instance from an absolute date.
  87.      *
  88.      * <p>This method uses the {@link DataContext#getDefault() default data context}.
  89.      *
  90.      * @param date absolute date to consider
  91.      * @see #GLONASSDate(AbsoluteDate, TimeScale)
  92.      */
  93.     @DefaultDataContext
  94.     public GLONASSDate(final AbsoluteDate date) {
  95.         this(date, DataContext.getDefault().getTimeScales().getGLONASS());
  96.     }

  97.     /**
  98.      * Build an instance from an absolute date.
  99.      *
  100.      * @param date    absolute date to consider
  101.      * @param glonass time scale.
  102.      * @since 10.1
  103.      */
  104.     public GLONASSDate(final AbsoluteDate date, final TimeScale glonass) {
  105.         final DateTimeComponents dateTime = date.getComponents(glonass);
  106.         // N4
  107.         final int year = dateTime.getDate().getYear();
  108.         this.n4 = ((int) (year - 1996) / 4) + 1;
  109.         // Na
  110.         final int start = 1996 + 4 * (n4 - 1);
  111.         final double duration = date.durationFrom(new AbsoluteDate(start, 1, 1, glonass));
  112.         this.na = (int) (duration / 86400) + 1;
  113.         this.secInNa = dateTime.getTime().getSecondsInLocalDay();
  114.         // Compute JD0
  115.         final int ratio = FastMath.round((float) (na - 3) / (25 + C1 + C2));
  116.         this.jd0 = 1461 * (n4 - 1) + na + 2450082.5 - ratio;
  117.         // GMST
  118.         this.gmst = computeGMST();
  119.         this.date = date;
  120.     }

  121.     @Override
  122.     public AbsoluteDate getDate() {
  123.         return date;
  124.     }

  125.     /** Get the number of seconds since N<sub>a</sub> start.
  126.      * @return number of seconds since N<sub>a</sub> start
  127.      */
  128.     public double getSecInDay() {
  129.         return secInNa;
  130.     }

  131.     /** Get the number of the current day in a four year interval.
  132.      * @return the number of the current day in a four year interval
  133.      */
  134.     public int getDayNumber() {
  135.         return na;
  136.     }

  137.     /** Get the number of the current four year interval.
  138.      * @return the number of the current four year interval
  139.      */
  140.     public int getIntervalNumber() {
  141.         return n4;
  142.     }

  143.     /** Get the current Julian date JD0.
  144.      * @return the current date JD0
  145.      */
  146.     public double getJD0() {
  147.         return jd0;
  148.     }

  149.     /** Get the Greenwich Mean Sidereal Time.
  150.      * @return the Greenwich Mean Sidereal Time (rad)
  151.      */
  152.     public double getGMST() {
  153.         return gmst;
  154.     }

  155.     /** Compute the Greenwich Mean Sidereal Time using the current Julian date JD0.
  156.      * @return the Greenwich Mean Sidereal Time (rad)
  157.      */
  158.     private double computeGMST() {
  159.         final double ref = 2451545.0;
  160.         // Earth's rotation angle in radians
  161.         final double era = 2. * GNSSConstants.GLONASS_PI *
  162.                         (0.7790572732640 + 1.00273781191135448 * (jd0 - ref));
  163.         // Time from Epoch 2000 (1st January, 00:00 UTC) till current Epoch in Julian centuries
  164.         final double time = (jd0 - ref) / Constants.JULIAN_CENTURY;
  165.         // Time to the power n
  166.         final double time2 = time * time;
  167.         final double time3 = time2 * time;
  168.         final double time4 = time2 * time2;
  169.         final double time5 = time2 * time3;
  170.         // GMST computation
  171.         final double gTime = era + 7.03270726e-8 + time * 2.23603658710194e-2 +
  172.                         time2 * 6.7465784654e-6 - time3 * 2.1332e-12 - time4 * 1.452308e-10 - time5 * 1.784e-13;
  173.         return gTime;
  174.     }

  175.     /** Compute the GLONASS date.
  176.      * @return the date
  177.      * @param glonass time scale.
  178.      */
  179.     private AbsoluteDate computeDate(final TimeScale glonass) {
  180.         // Compute the number of Julian day for the current date
  181.         final double jdn = jd0 + 0.5;
  182.         // Coefficients
  183.         final int a = (int) (jdn + 32044);
  184.         final int b = (4 * a + 3) / 146097;
  185.         final int c = a - (146097 * b) / 4;
  186.         final int d = (4 * c + 3) / 1461;
  187.         final int e = c - (1461 * d) / 4;
  188.         final int m = (5 * e + 2) / 153;
  189.         // Year, month and day
  190.         final int day   = e - (153 * m + 2) / 5 + 1;
  191.         final int month = m + 3 - 12 * (m / 10);
  192.         final int year  = 100 * b + d - 4800 + m / 10;
  193.         return new AbsoluteDate(new DateComponents(year, month, day),
  194.                                 new TimeComponents(secInNa),
  195.                                 glonass);
  196.     }

  197.     /** Replace the instance with a data transfer object for serialization.
  198.      * @return data transfer object that will be serialized
  199.      */
  200.     @DefaultDataContext
  201.     private Object writeReplace() {
  202.         return new DataTransferObject(na, n4, secInNa);
  203.     }

  204.     /** Internal class used only for serialization. */
  205.     @DefaultDataContext
  206.     private static class DataTransferObject implements Serializable {

  207.         /** Serializable UID. */
  208.         private static final long serialVersionUID = 20190131L;

  209.         /** The number of the current day in a four year interval N<sub>a</sub>. */
  210.         private final int na;

  211.         /** The number of the current four year interval N<sub>4</sub>. */
  212.         private final int n4;

  213.         /** Number of seconds since N<sub>a</sub>. */
  214.         private final double secInNa;

  215.         /** Simple constructor.
  216.          * @param na the number of the current day in a four year interval
  217.          * @param n4 the number of the current four year interval
  218.          * @param secInNa the number of seconds since na start
  219.          */
  220.         DataTransferObject(final int na, final int n4, final double secInNa) {
  221.             this.na      = na;
  222.             this.n4      = n4;
  223.             this.secInNa = secInNa;
  224.         }

  225.         /** Replace the deserialized data transfer object with a {@link GPSDate}.
  226.          * @return replacement {@link GPSDate}
  227.          */
  228.         private Object readResolve() {
  229.             return new GLONASSDate(na, n4, secInNa);
  230.         }

  231.     }

  232. }