1   /* Copyright 2002-2024 Luc Maisonobe
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.propagation.events.intervals;
18  
19  import org.hipparchus.util.FastMath;
20  import org.orekit.frames.TopocentricFrame;
21  import org.orekit.frames.Transform;
22  import org.orekit.orbits.Orbit;
23  import org.orekit.propagation.events.AdaptableInterval;
24  
25  /**
26   * Factory class for {@link AdaptableInterval} suitable for elevation detection on eccentric orbits.
27   * It requires {@link org.orekit.propagation.SpacecraftState} to be based on {@link Orbit} in order to work.
28   * @see AdaptableInterval
29   * @see org.orekit.propagation.events.ApsideDetector
30   * @see org.orekit.propagation.events.EventSlopeFilter
31   * @author Luc Maisonobe
32   * @since 12.1
33   */
34  public class ElevationDetectionAdaptableIntervalFactory {
35  
36      /** Default elevation abovde which interval should be switched to fine interval (-5°). */
37      public static final double DEFAULT_ELEVATION_SWITCH = FastMath.toRadians(-5.0);
38  
39      /**
40       * Private constructor.
41       */
42      private ElevationDetectionAdaptableIntervalFactory() {
43          // factory class
44      }
45  
46      /**
47       * Method providing a candidate {@link AdaptableInterval} for arbitrary elevation detection with forward propagation.
48       * It uses a Keplerian, eccentric approximation.
49       * @param topo topocentric frame centered at ground interest point
50       * @param elevationSwitch elevation above which interval will switch to {@code fineCheckInterval}
51       *                        (typically {@link #DEFAULT_ELEVATION_SWITCH} which is -5°)
52       * @param fineCheckInterval check interval to use when elevation is above {@code elevationSwitch}
53       * @return adaptable interval for detection of elevation with respect to {@code topo}
54       */
55      public static AdaptableInterval getAdaptableInterval(final TopocentricFrame topo,
56                                                           final double elevationSwitch,
57                                                           final double fineCheckInterval) {
58          return state -> {
59              final double elevation = topo.getElevation(state.getPosition(), state.getFrame(), state.getDate());
60              if (elevation <= elevationSwitch) {
61                  // we are far from visibility, estimate some large interval with huge margins
62  
63                  // rotation rate of the topocentric frame
64                  final Transform topoToInertial = topo.getTransformTo(state.getFrame(), state.getDate());
65                  final double topoAngularVelocity = topoToInertial.getAngular().getRotationRate().getNorm();
66  
67                  // max angular rate of spacecraft (i.e. rate at perigee)
68                  final double e     = state.getE();
69                  final double rp    = state.getA() * (1 - e);
70                  final double vp    = FastMath.sqrt(state.getMu() * (1 + e) / rp);
71                  final double rateP = vp / rp;
72  
73                  // upper boundary of elevation rate
74                  final double maxElevationRate = topoAngularVelocity + rateP;
75  
76                  return FastMath.max(fineCheckInterval, (elevationSwitch - elevation) / maxElevationRate);
77  
78              } else {
79                  // we are close to visibility, switch to fine check interval
80                  return fineCheckInterval;
81              }
82          };
83      }
84  
85  }