1   /* Copyright 2022-2026 Thales Alenia Space
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.clocks;
18  
19  import org.hipparchus.CalculusFieldElement;
20  import org.orekit.errors.OrekitException;
21  import org.orekit.errors.OrekitMessages;
22  import org.orekit.time.AbsoluteDate;
23  import org.orekit.time.FieldAbsoluteDate;
24  import org.orekit.time.TimeStamped;
25  
26  import java.util.function.DoubleFunction;
27  
28  /**
29   * Container for time stamped clock offset.
30   * <p>
31   * Instances of this class are immutable
32   * </p>
33   *
34   * @author Luc Maisonobe
35   * @since 12.1
36   */
37  public class ClockOffset implements TimeStamped {
38  
39      /** Date. */
40      private final AbsoluteDate date;
41  
42      /** Clock bias. */
43      private final double bias;
44  
45      /** Clock rate. */
46      private final double rate;
47  
48      /** Clock acceleration. */
49      private final double acceleration;
50  
51      /**
52       * Simple constructor.
53       *
54       * @param date date
55       * @param bias clock bias
56       * @param rate clock rate (can be set to {@code Double.NaN} if unknown)
57       * @param acceleration clock acceleration (can be set to {@code Double.NaN}
58       *        if unknown)
59       */
60      public ClockOffset(final AbsoluteDate date, final double bias,
61                         final double rate, final double acceleration) {
62          this.date = date;
63          this.bias =         bias;
64          this.rate =         rate;
65          this.acceleration = acceleration;
66      }
67  
68      /**
69       * Simple constructor.
70       *
71       * @param date date
72       * @param terms the clock terms, up to 3 values for bias, drift, and acceleration
73       */
74      public ClockOffset(final AbsoluteDate date, final double[] terms) {
75          this.date = date;
76          if (terms.length >= 1) {
77              this.bias = terms[0];
78          } else {
79              this.bias = 0;
80          }
81          if (terms.length >= 2) {
82              this.rate = terms[1];
83          } else {
84              this.rate = 0;
85          }
86          if (terms.length == 3) {
87              this.acceleration = terms[2];
88          } else {
89              this.acceleration = 0;
90          }
91          if (terms.length > 3) {
92              throw new OrekitException(OrekitMessages.CANNOT_PARSE_DATA);
93          }
94      }
95  
96      /**
97       * Add another offset to the instance.
98       * <p>
99       * The instance is not modified, a new instance is created
100      * </p>
101      *
102      * @param other offset to add (date part will be ignored)
103      * @return instance + other, at instance date
104      * @since 14.0
105      */
106     public ClockOffset add(final ClockOffset other) {
107         return new ClockOffset(date,
108                                bias + other.bias,
109                                rate + other.rate,
110                                acceleration + other.acceleration);
111     }
112 
113     /**
114      * Subtract another offset from the instance.
115      * <p>
116      * The instance is not modified, a new instance is created
117      * </p>
118      *
119      * @param other offset to subtract (date part will be ignored)
120      * @return instance - other, at instance date
121      * @since 14.0
122      */
123     public ClockOffset subtract(final ClockOffset other) {
124         return new ClockOffset(date, bias - other.bias, rate - other.rate,
125                                acceleration - other.acceleration);
126     }
127 
128     /** {@inheritDoc} */
129     @Override
130     public AbsoluteDate getDate() {
131         return date;
132     }
133 
134     /** Get bias.
135      * @return bias
136      * @since 14.0
137      */
138     public double getBias() {
139         return bias;
140     }
141 
142     /** Get rate.
143      * @return rate ({@code Double.NaN} if unknown)
144      */
145     public double getRate() {
146         return rate;
147     }
148 
149     /** Get acceleration.
150      * @return acceleration ({@code Double.NaN} if unknown)
151      */
152     public double getAcceleration() {
153         return acceleration;
154     }
155 
156     /** Get the value of the clock offset at a given time.
157      * @param givenDate the date at which to evaluate the clock offset
158      * @return The value of the clock in seconds from the given date
159      */
160     public double getValue(final AbsoluteDate givenDate) {
161         final double dt = givenDate.durationFrom(date);
162         return dt * ((dt * getAcceleration()) + getRate()) + getBias();
163 
164     }
165 
166     /** Get a field version of the instance.
167      * @param <T> type of the field elements
168      * @param converter converter to field elements
169      * @return field version
170      * @since 14.0
171      */
172     public <T extends CalculusFieldElement<T>> FieldClockOffset<T> toField(final DoubleFunction<T> converter) {
173         final T fieldBias         = converter.apply(bias);
174         final T fieldRate         = converter.apply(rate);
175         final T fieldAcceleration = converter.apply(acceleration);
176         return new FieldClockOffset<>(new FieldAbsoluteDate<>(fieldBias.getField(), date),
177                                       fieldBias, fieldRate, fieldAcceleration);
178     }
179 
180 }