SpacecraftToObservedBody.java

  1. /* Copyright 2013-2022 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.rugged.utils;

  18. import java.io.Serializable;
  19. import java.util.ArrayList;
  20. import java.util.List;
  21. import java.util.stream.Collectors;

  22. import org.hipparchus.util.FastMath;
  23. import org.orekit.frames.Frame;
  24. import org.orekit.frames.Transform;
  25. import org.orekit.rugged.errors.DumpManager;
  26. import org.orekit.rugged.errors.RuggedException;
  27. import org.orekit.rugged.errors.RuggedMessages;
  28. import org.orekit.time.AbsoluteDate;
  29. import org.orekit.utils.AngularDerivativesFilter;
  30. import org.orekit.utils.CartesianDerivativesFilter;
  31. import org.orekit.utils.ImmutableTimeStampedCache;
  32. import org.orekit.utils.TimeStampedAngularCoordinates;
  33. import org.orekit.utils.TimeStampedCache;
  34. import org.orekit.utils.TimeStampedPVCoordinates;

  35. /** Provider for observation transforms.
  36.  * @author Luc Maisonobe
  37.  * @author Guylaine Prat
  38.  */
  39. public class SpacecraftToObservedBody implements Serializable {

  40.     /** Serializable UID. */
  41.     private static final long serialVersionUID = 20140909L;

  42.     /** Inertial frame. */
  43.     private final Frame inertialFrame;

  44.     /** Body frame. */
  45.     private final Frame bodyFrame;

  46.     /** Start of search time span. */
  47.     private final AbsoluteDate minDate;

  48.     /** End of search time span. */
  49.     private final AbsoluteDate maxDate;

  50.     /** Step to use for inertial frame to body frame transforms cache computations. */
  51.     private final double tStep;

  52.     /** Tolerance in seconds allowed for {@code minDate} and {@code maxDate} overshooting. */
  53.     private final double overshootTolerance;

  54.     /** Transforms sample from observed body frame to inertial frame. */
  55.     private final List<Transform> bodyToInertial;

  56.     /** Transforms sample from inertial frame to observed body frame. */
  57.     private final List<Transform> inertialToBody;

  58.     /** Transforms sample from spacecraft frame to inertial frame. */
  59.     private final List<Transform> scToInertial;

  60.     /** Simple constructor.
  61.      * @param inertialFrame inertial frame
  62.      * @param bodyFrame observed body frame
  63.      * @param minDate start of search time span
  64.      * @param maxDate end of search time span
  65.      * @param tStep step to use for inertial frame to body frame transforms cache computations
  66.      * @param overshootTolerance tolerance in seconds allowed for {@code minDate} and {@code maxDate} overshooting
  67.      * slightly the position, velocity and quaternions ephemerides
  68.      * @param positionsVelocities satellite position and velocity
  69.      * @param pvInterpolationNumber number of points to use for position/velocity interpolation
  70.      * @param pvFilter filter for derivatives from the sample to use in position/velocity interpolation
  71.      * @param quaternions satellite quaternions
  72.      * @param aInterpolationNumber number of points to use for attitude interpolation
  73.      * @param aFilter filter for derivatives from the sample to use in attitude interpolation
  74.      */
  75.     public SpacecraftToObservedBody(final Frame inertialFrame, final Frame bodyFrame,
  76.                                     final AbsoluteDate minDate, final AbsoluteDate maxDate, final double tStep,
  77.                                     final double overshootTolerance,
  78.                                     final List<TimeStampedPVCoordinates> positionsVelocities, final int pvInterpolationNumber,
  79.                                     final CartesianDerivativesFilter pvFilter,
  80.                                     final List<TimeStampedAngularCoordinates> quaternions, final int aInterpolationNumber,
  81.                                     final AngularDerivativesFilter aFilter) {

  82.         this.inertialFrame      = inertialFrame;
  83.         this.bodyFrame          = bodyFrame;
  84.         this.minDate            = minDate;
  85.         this.maxDate            = maxDate;
  86.         this.overshootTolerance = overshootTolerance;

  87.         // safety checks
  88.         final AbsoluteDate minPVDate = positionsVelocities.get(0).getDate();
  89.         final AbsoluteDate maxPVDate = positionsVelocities.get(positionsVelocities.size() - 1).getDate();
  90.         if (minPVDate.durationFrom(minDate) > overshootTolerance) {
  91.             throw new RuggedException(RuggedMessages.OUT_OF_TIME_RANGE, minDate, minPVDate, maxPVDate);
  92.         }
  93.         if (maxDate.durationFrom(maxPVDate) > overshootTolerance) {
  94.             throw new RuggedException(RuggedMessages.OUT_OF_TIME_RANGE, maxDate, minPVDate, maxPVDate);
  95.         }

  96.         final AbsoluteDate minQDate  = quaternions.get(0).getDate();
  97.         final AbsoluteDate maxQDate  = quaternions.get(quaternions.size() - 1).getDate();
  98.         if (minQDate.durationFrom(minDate) > overshootTolerance) {
  99.             throw new RuggedException(RuggedMessages.OUT_OF_TIME_RANGE, minDate, minQDate, maxQDate);
  100.         }
  101.         if (maxDate.durationFrom(maxQDate) > overshootTolerance) {
  102.             throw new RuggedException(RuggedMessages.OUT_OF_TIME_RANGE, maxDate, minQDate, maxQDate);
  103.         }

  104.         // set up the cache for position-velocities
  105.         final TimeStampedCache<TimeStampedPVCoordinates> pvCache =
  106.                 new ImmutableTimeStampedCache<>(pvInterpolationNumber, positionsVelocities);

  107.         // set up the cache for attitudes
  108.         final TimeStampedCache<TimeStampedAngularCoordinates> aCache =
  109.                 new ImmutableTimeStampedCache<>(aInterpolationNumber, quaternions);

  110.         final int n = (int) FastMath.ceil(maxDate.durationFrom(minDate) / tStep);
  111.         this.tStep          = tStep;
  112.         this.bodyToInertial = new ArrayList<>(n);
  113.         this.inertialToBody = new ArrayList<>(n);
  114.         this.scToInertial   = new ArrayList<>(n);
  115.         for (AbsoluteDate date = minDate; bodyToInertial.size() < n; date = date.shiftedBy(tStep)) {

  116.             // interpolate position-velocity, allowing slight extrapolation near the boundaries
  117.             final AbsoluteDate pvInterpolationDate;
  118.             if (date.compareTo(pvCache.getEarliest().getDate()) < 0) {
  119.                 pvInterpolationDate = pvCache.getEarliest().getDate();
  120.             } else if (date.compareTo(pvCache.getLatest().getDate()) > 0) {
  121.                 pvInterpolationDate = pvCache.getLatest().getDate();
  122.             } else {
  123.                 pvInterpolationDate = date;
  124.             }
  125.             final TimeStampedPVCoordinates interpolatedPV =
  126.                     TimeStampedPVCoordinates.interpolate(pvInterpolationDate, pvFilter,
  127.                             pvCache.getNeighbors(pvInterpolationDate));
  128.             final TimeStampedPVCoordinates pv = interpolatedPV.shiftedBy(date.durationFrom(pvInterpolationDate));

  129.             // interpolate attitude, allowing slight extrapolation near the boundaries
  130.             final AbsoluteDate aInterpolationDate;
  131.             if (date.compareTo(aCache.getEarliest().getDate()) < 0) {
  132.                 aInterpolationDate = aCache.getEarliest().getDate();
  133.             } else if (date.compareTo(aCache.getLatest().getDate()) > 0) {
  134.                 aInterpolationDate = aCache.getLatest().getDate();
  135.             } else {
  136.                 aInterpolationDate = date;
  137.             }
  138.             final TimeStampedAngularCoordinates interpolatedQuaternion =
  139.                     TimeStampedAngularCoordinates.interpolate(aInterpolationDate, aFilter,
  140.                             aCache.getNeighbors(aInterpolationDate).collect(Collectors.toList()));
  141.             final TimeStampedAngularCoordinates quaternion = interpolatedQuaternion.shiftedBy(date.durationFrom(aInterpolationDate));

  142.             // store transform from spacecraft frame to inertial frame
  143.             scToInertial.add(new Transform(date,
  144.                     new Transform(date, quaternion.revert()),
  145.                     new Transform(date, pv)));

  146.             // store transform from body frame to inertial frame
  147.             final Transform b2i = bodyFrame.getTransformTo(inertialFrame, date);
  148.             bodyToInertial.add(b2i);
  149.             inertialToBody.add(b2i.getInverse());

  150.         }
  151.     }

  152.     /** Simple constructor.
  153.      * @param inertialFrame inertial frame
  154.      * @param bodyFrame observed body frame
  155.      * @param minDate start of search time span
  156.      * @param maxDate end of search time span
  157.      * @param tStep step to use for inertial frame to body frame transforms cache computations
  158.      * @param overshootTolerance tolerance in seconds allowed for {@code minDate} and {@code maxDate} overshooting
  159.      * slightly the position, velocity and quaternions ephemerides
  160.      * @param bodyToInertial transforms sample from observed body frame to inertial frame
  161.      * @param scToInertial transforms sample from spacecraft frame to inertial frame
  162.      */
  163.     public SpacecraftToObservedBody(final Frame inertialFrame, final Frame bodyFrame,
  164.                                     final AbsoluteDate minDate, final AbsoluteDate maxDate, final double tStep,
  165.                                     final double overshootTolerance,
  166.                                     final List<Transform> bodyToInertial, final List<Transform> scToInertial) {

  167.         this.inertialFrame      = inertialFrame;
  168.         this.bodyFrame          = bodyFrame;
  169.         this.minDate            = minDate;
  170.         this.maxDate            = maxDate;
  171.         this.tStep              = tStep;
  172.         this.overshootTolerance = overshootTolerance;
  173.         this.bodyToInertial     = bodyToInertial;
  174.         this.scToInertial       = scToInertial;

  175.         this.inertialToBody = new ArrayList<>(bodyToInertial.size());
  176.         for (final Transform b2i : bodyToInertial) {
  177.             inertialToBody.add(b2i.getInverse());
  178.         }

  179.     }

  180.     /** Get the inertial frame.
  181.      * @return inertial frame
  182.      */
  183.     public Frame getInertialFrame() {
  184.         return inertialFrame;
  185.     }

  186.     /** Get the body frame.
  187.      * @return body frame
  188.      */
  189.     public Frame getBodyFrame() {
  190.         return bodyFrame;
  191.     }

  192.     /** Get the start of search time span.
  193.      * @return start of search time span
  194.      */
  195.     public AbsoluteDate getMinDate() {
  196.         return minDate;
  197.     }

  198.     /** Get the end of search time span.
  199.      * @return end of search time span
  200.      */
  201.     public AbsoluteDate getMaxDate() {
  202.         return maxDate;
  203.     }

  204.     /** Get the step to use for inertial frame to body frame transforms cache computations.
  205.      * @return step to use for inertial frame to body frame transforms cache computations
  206.      */
  207.     public double getTStep() {
  208.         return tStep;
  209.     }

  210.     /** Get the tolerance in seconds allowed for {@link #getMinDate()} and {@link #getMaxDate()} overshooting.
  211.      * @return tolerance in seconds allowed for {@link #getMinDate()} and {@link #getMaxDate()} overshooting
  212.      */
  213.     public double getOvershootTolerance() {
  214.         return overshootTolerance;
  215.     }

  216.     /** Get transform from spacecraft to inertial frame.
  217.      * @param date date of the transform
  218.      * @return transform from spacecraft to inertial frame
  219.      */
  220.     public Transform getScToInertial(final AbsoluteDate date) {
  221.         return interpolate(date, scToInertial);
  222.     }

  223.     /** Get transform from inertial frame to observed body frame.
  224.      * @param date date of the transform
  225.      * @return transform from inertial frame to observed body frame
  226.      */
  227.     public Transform getInertialToBody(final AbsoluteDate date) {
  228.         return interpolate(date, inertialToBody);
  229.     }

  230.     /** Get transform from observed body frame to inertial frame.
  231.      * @param date date of the transform
  232.      * @return transform from observed body frame to inertial frame
  233.      */
  234.     public Transform getBodyToInertial(final AbsoluteDate date) {
  235.         return interpolate(date, bodyToInertial);
  236.     }

  237.     /** Interpolate transform.
  238.      * @param date date of the transform
  239.      * @param list transforms list to interpolate from
  240.      * @return interpolated transform
  241.      */
  242.     private Transform interpolate(final AbsoluteDate date, final List<Transform> list) {

  243.         // check date range
  244.         if (!isInRange(date)) {
  245.             throw new RuggedException(RuggedMessages.OUT_OF_TIME_RANGE, date, minDate, maxDate);
  246.         }

  247.         final double    s     = date.durationFrom(list.get(0).getDate()) / tStep;
  248.         final int       index = FastMath.max(0, FastMath.min(list.size() - 1, (int) FastMath.rint(s)));

  249.         DumpManager.dumpTransform(this, index, bodyToInertial.get(index), scToInertial.get(index));

  250.         final Transform close = list.get(index);
  251.         return close.shiftedBy(date.durationFrom(close.getDate()));

  252.     }

  253.     /** Check if a date is in the supported range.
  254.      * @param date date to check
  255.      * @return true if date is in the supported range
  256.      */
  257.     public boolean isInRange(final AbsoluteDate date) {
  258.         return minDate.durationFrom(date) <= overshootTolerance &&
  259.                date.durationFrom(maxDate) <= overshootTolerance;
  260.     }

  261. }