1   /* Copyright 2022-2026 Romain Serra
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.signal;
18  
19  import org.hipparchus.geometry.euclidean.threed.Vector3D;
20  import org.hipparchus.optim.ConvergenceChecker;
21  import org.hipparchus.util.FastMath;
22  import org.orekit.frames.Frame;
23  import org.orekit.time.AbsoluteDate;
24  import org.orekit.utils.Constants;
25  import org.orekit.utils.PVCoordinatesProvider;
26  
27  /**
28   * Abstract class for computation of signal travel time in vacuum.
29   * @since 14.0
30   * @author Romain Serra
31   * @author Luc Maisonnobe
32   */
33  abstract class AbstractSignalTravelTime {
34  
35      /** Reciprocal for light speed. */
36      protected static final double C_RECIPROCAL = 1.0 / Constants.SPEED_OF_LIGHT;
37  
38      /** Maximum number of iterations. */
39      protected static final int DEFAULT_MAX_ITER = 10;
40  
41      /** Convergence checker. */
42      private final ConvergenceChecker<Double> convergenceChecker;
43  
44      /**
45       * Constructor.
46       * @param convergenceChecker convergence checker
47       */
48      protected AbstractSignalTravelTime(final ConvergenceChecker<Double> convergenceChecker) {
49          this.convergenceChecker = convergenceChecker;
50      }
51  
52      /**
53       * Get the default convergence checker.
54       * @return checker
55       */
56      static ConvergenceChecker<Double> getDefaultConvergenceChecker() {
57          return (iteration, previous, current) -> iteration != 0 && (iteration > DEFAULT_MAX_ITER ||
58                  FastMath.abs(previous - current) <= 2 * FastMath.ulp(current));
59      }
60  
61      /**
62       * Getter for the convergence checker.
63       * @return checker
64       */
65      public ConvergenceChecker<Double> getConvergenceChecker() {
66          return convergenceChecker;
67      }
68  
69      /** Compute propagation delay on a link leg (typically downlink or uplink).
70       * The max. iteration number and convergence checker can be tweaked to emulate no-delay a.k.a. instantaneous transmission.
71       * @param pvCoordinatesProvider adjustable emitter/receiver
72       * @param initialOffset guess for the time off set
73       * @param fixedPosition fixed receiver/emitter position
74       * @param guessDate guess for emission/reception date
75       * @param frame Inertial frame in which receiver/emitter is defined.
76       * @return <em>positive</em> delay between signal emission and signal reception dates
77       */
78      protected double compute(final PVCoordinatesProvider pvCoordinatesProvider, final double initialOffset,
79                               final Vector3D fixedPosition, final AbsoluteDate guessDate, final Frame frame) {
80          double delay = initialOffset;
81  
82          // search signal transit date, computing the signal travel in inertial frame
83          double previous = 0.;
84          int count = 0;
85          while (!convergenceChecker.converged(count, previous, delay)) {
86              previous = delay;
87              final double shift = computeShift(initialOffset, delay);
88              final Vector3D pos    = pvCoordinatesProvider.getPosition(guessDate.shiftedBy(shift), frame);
89              delay                 = fixedPosition.distance(pos) * C_RECIPROCAL;
90              count++;
91          }
92  
93          return delay;
94  
95      }
96  
97      /**
98       * Computes the time shift.
99       * @param offset time offset
100      * @param delay time delay
101      * @return time shift to use in computation
102      */
103     protected abstract double computeShift(double offset, double delay);
104 
105 }