InterSatDirectViewDetector.java

  1. /* Copyright 2002-2019 CS Systèmes d'Information
  2.  * Licensed to CS Systèmes d'Information (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;

  18. import org.hipparchus.geometry.euclidean.threed.Vector3D;
  19. import org.hipparchus.util.FastMath;
  20. import org.orekit.bodies.OneAxisEllipsoid;
  21. import org.orekit.frames.Frame;
  22. import org.orekit.propagation.PropagatorsParallelizer;
  23. import org.orekit.propagation.SpacecraftState;
  24. import org.orekit.propagation.events.handlers.ContinueOnEvent;
  25. import org.orekit.propagation.events.handlers.EventHandler;
  26. import org.orekit.time.AbsoluteDate;
  27. import org.orekit.utils.PVCoordinatesProvider;


  28. /** Detector for inter-satellites direct view (i.e. no masking by central body limb).
  29.  * <p>
  30.  * As this detector needs two satellites, it embeds one {@link
  31.  * PVCoordinatesProvider coordinates provider} for the slave satellite
  32.  * and is registered as an event detector in the propagator of the master
  33.  * satellite. The slave satellite provider will therefore be driven by this
  34.  * detector (and hence by the propagator in which this detector is registered).
  35.  * </p>
  36.  * <p>
  37.  * In order to avoid infinite recursion, care must be taken to have the slave
  38.  * satellite provider being <em>completely independent</em> from anything else.
  39.  * In particular, if the provider is a propagator, it should <em>not</em> be run
  40.  * together in a {@link PropagatorsParallelizer propagators parallelizer} with
  41.  * the propagator this detector is registered in. It is fine however to configure
  42.  * two separate propagators PsA and PsB with similar settings for the slave satellite
  43.  * and one propagator Pm for the master satellite and then use Psa in this detector
  44.  * registered within Pm while Pm and Psb are run in the context of a {@link
  45.  * PropagatorsParallelizer propagators parallelizer}.
  46.  * </p>
  47.  * <p>
  48.  * For efficiency reason during the event search loop, it is recommended to have
  49.  * the slave provider be an analytical propagator or an ephemeris. A numerical propagator
  50.  * as a slave propagator works but is expected to be computationally costly.
  51.  * </p>
  52.  * <p>
  53.  * The {@code g} function of this detector is positive when satellites can see
  54.  * each other directly and negative when the central body limb is in between and
  55.  * blocks the direct view.
  56.  * </p>
  57.  * <p>
  58.  * This detector only checks masking by central body limb, it does not take into
  59.  * account satellites antenna patterns. If these patterns must be considered, then
  60.  * this detector can be {@link BooleanDetector#andCombine(EventDetector...) and combined}
  61.  * with  the {@link BooleanDetector#notCombine(EventDetector) logical not} of
  62.  * {@link FieldOfViewDetector field of view detectors}.
  63.  * </p>
  64.  * @author Luc Maisonobe
  65.  * @since 9.3
  66.  */
  67. public class InterSatDirectViewDetector extends AbstractDetector<InterSatDirectViewDetector> {

  68.     /** Serializable UID. */
  69.     private static final long serialVersionUID = 20181130L;

  70.     /** Central body. */
  71.     private final OneAxisEllipsoid body;

  72.     /** Equatorial radius squared. */
  73.     private final double ae2;

  74.     /** 1 minus flatness squared. */
  75.     private final double g2;

  76.     /** Coordinates provider for the slave satellite. */
  77.     private final transient PVCoordinatesProvider slave;

  78.     /** simple constructor.
  79.      *
  80.      * @param body central body
  81.      * @param slave provider for the slave satellite
  82.      */
  83.     public InterSatDirectViewDetector(final OneAxisEllipsoid body, final PVCoordinatesProvider slave) {
  84.         this(body, slave, DEFAULT_MAXCHECK, DEFAULT_THRESHOLD, DEFAULT_MAX_ITER,
  85.              new ContinueOnEvent<>());
  86.     }

  87.     /** Private constructor.
  88.      * @param body central body
  89.      * @param slave provider for the slave satellite
  90.      * @param maxCheck  maximum checking interval (s)
  91.      * @param threshold convergence threshold (s)
  92.      * @param maxIter   maximum number of iterations in the event time search
  93.      * @param handler   event handler to call at event occurrences
  94.      */
  95.     private InterSatDirectViewDetector(final OneAxisEllipsoid body,
  96.                                        final PVCoordinatesProvider slave,
  97.                                        final double maxCheck,
  98.                                        final double threshold,
  99.                                        final int maxIter,
  100.                                        final EventHandler<? super InterSatDirectViewDetector> handler) {
  101.         super(maxCheck, threshold, maxIter, handler);
  102.         this.body  = body;
  103.         this.ae2   = body.getEquatorialRadius() * body.getEquatorialRadius();
  104.         this.g2    = (1.0 - body.getFlattening()) * (1.0 - body.getFlattening());
  105.         this.slave = slave;
  106.     }

  107.     /** Get the central body.
  108.      * @return central body
  109.      */
  110.     public OneAxisEllipsoid getCentralBody() {
  111.         return body;
  112.     }

  113.     /** Get the provider for the slave satellite.
  114.      * @return provider for the slave satellite
  115.      */
  116.     public PVCoordinatesProvider getSlave() {
  117.         return slave;
  118.     }

  119.     /** {@inheritDoc} */
  120.     @Override
  121.     protected InterSatDirectViewDetector create(final double newMaxCheck,
  122.                                                 final double newThreshold,
  123.                                                 final int newMaxIter,
  124.                                                 final EventHandler<? super InterSatDirectViewDetector> newHandler) {
  125.         return new InterSatDirectViewDetector(body, slave, newMaxCheck, newThreshold, newMaxIter, newHandler);
  126.     }

  127.     /** {@inheritDoc}
  128.      * <p>
  129.      * The {@code g} function of this detector is positive when satellites can see
  130.      * each other directly and negative when the central body limb is in between and
  131.      * blocks the direct view.
  132.      * </p>
  133.      */
  134.     @Override
  135.     public double g(final SpacecraftState state) {

  136.         // get the line between master and slave in body frame
  137.         final AbsoluteDate date    = state.getDate();
  138.         final Frame        frame   = body.getBodyFrame();
  139.         final Vector3D     pMaster = state.getPVCoordinates(frame).getPosition();
  140.         final Vector3D     pSlave  = slave.getPVCoordinates(date, frame).getPosition();

  141.         // points along the master/slave lines are defined as
  142.         // xk = x + k * dx, yk = y + k * dy, zk = z + k * dz
  143.         // so k is 0 at master and 1 at slave
  144.         final double x  = pMaster.getX();
  145.         final double y  = pMaster.getY();
  146.         final double z  = pMaster.getZ();
  147.         final double dx = pSlave.getX() - x;
  148.         final double dy = pSlave.getY() - y;
  149.         final double dz = pSlave.getZ() - z;

  150.         // intersection between line and central body surface
  151.         // is a root of a 2nd degree polynomial :
  152.         // a k^2 - 2 b k + c = 0
  153.         final double a =   g2 * (dx * dx + dy * dy) + dz * dz;
  154.         final double b = -(g2 * (x * dx + y * dy) + z * dz);
  155.         final double c =   g2 * (x * x + y * y - ae2) + z * z;
  156.         final double s = b * b - a * c;
  157.         if (s < 0) {
  158.             // the quadratic has no solution, the line between master and slave
  159.             // doesn't crosses central body limb, direct view is possible
  160.             // return a positive value, preserving continuity across zero crossing
  161.             return -s;
  162.         }

  163.         // the quadratic has two solutions (degenerated to one if s = 0)
  164.         // direct view is blocked when one of these solutions is between 0 and 1
  165.         final double k1 = (b < 0) ? (b - FastMath.sqrt(s)) / a : c / (b + FastMath.sqrt(s));
  166.         final double k2 = c / (a * k1);
  167.         if (FastMath.max(k1, k2) < 0.0 || FastMath.min(k1, k2) > 1.0) {
  168.             // the intersections are either behind master or farther away than slave
  169.             // along the line, direct view is possible
  170.             // return a positive value, preserving continuity across zero crossing
  171.             return s;
  172.         } else {
  173.             // part of the central body is between master and slave
  174.             // this includes unrealistic cases where master, slave or both are inside the central body ;-)
  175.             // in all these cases, direct view is blocked
  176.             // return a negative value, preserving continuity across zero crossing
  177.             return -s;
  178.         }

  179.     }

  180. }