SpacecraftToObservedBody.java

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

  18. import org.hipparchus.util.FastMath;
  19. import java.io.Serializable;
  20. import java.util.ArrayList;
  21. import java.util.List;
  22. import java.util.stream.Collectors;

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

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

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

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

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

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

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

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

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

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

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

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

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

  88.             this.inertialFrame      = inertialFrame;
  89.             this.bodyFrame          = bodyFrame;
  90.             this.minDate            = minDate;
  91.             this.maxDate            = maxDate;
  92.             this.overshootTolerance = overshootTolerance;

  93.             // safety checks
  94.             final AbsoluteDate minPVDate = positionsVelocities.get(0).getDate();
  95.             final AbsoluteDate maxPVDate = positionsVelocities.get(positionsVelocities.size() - 1).getDate();
  96.             if (minPVDate.durationFrom(minDate) > overshootTolerance) {
  97.                 throw new RuggedException(RuggedMessages.OUT_OF_TIME_RANGE, minDate, minPVDate, maxPVDate);
  98.             }
  99.             if (maxDate.durationFrom(maxPVDate) > overshootTolerance) {
  100.                 throw new RuggedException(RuggedMessages.OUT_OF_TIME_RANGE, maxDate, minPVDate, maxPVDate);
  101.             }

  102.             final AbsoluteDate minQDate  = quaternions.get(0).getDate();
  103.             final AbsoluteDate maxQDate  = quaternions.get(quaternions.size() - 1).getDate();
  104.             if (minQDate.durationFrom(minDate) > overshootTolerance) {
  105.                 throw new RuggedException(RuggedMessages.OUT_OF_TIME_RANGE, minDate, minQDate, maxQDate);
  106.             }
  107.             if (maxDate.durationFrom(maxQDate) > overshootTolerance) {
  108.                 throw new RuggedException(RuggedMessages.OUT_OF_TIME_RANGE, maxDate, minQDate, maxQDate);
  109.             }

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

  113.             // set up the cache for attitudes
  114.             final TimeStampedCache<TimeStampedAngularCoordinates> aCache =
  115.                     new ImmutableTimeStampedCache<TimeStampedAngularCoordinates>(aInterpolationNumber, quaternions);

  116.             final int n = (int) FastMath.ceil(maxDate.durationFrom(minDate) / tStep);
  117.             this.tStep          = tStep;
  118.             this.bodyToInertial = new ArrayList<Transform>(n);
  119.             this.inertialToBody = new ArrayList<Transform>(n);
  120.             this.scToInertial   = new ArrayList<Transform>(n);
  121.             for (AbsoluteDate date = minDate; bodyToInertial.size() < n; date = date.shiftedBy(tStep)) {

  122.                 // interpolate position-velocity, allowing slight extrapolation near the boundaries
  123.                 final AbsoluteDate pvInterpolationDate;
  124.                 if (date.compareTo(pvCache.getEarliest().getDate()) < 0) {
  125.                     pvInterpolationDate = pvCache.getEarliest().getDate();
  126.                 } else if (date.compareTo(pvCache.getLatest().getDate()) > 0) {
  127.                     pvInterpolationDate = pvCache.getLatest().getDate();
  128.                 } else {
  129.                     pvInterpolationDate = date;
  130.                 }
  131.                 final TimeStampedPVCoordinates interpolatedPV =
  132.                         TimeStampedPVCoordinates.interpolate(pvInterpolationDate, pvFilter,
  133.                                                              pvCache.getNeighbors(pvInterpolationDate));
  134.                 final TimeStampedPVCoordinates pv = interpolatedPV.shiftedBy(date.durationFrom(pvInterpolationDate));

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

  148.                 // store transform from spacecraft frame to inertial frame
  149.                 scToInertial.add(new Transform(date,
  150.                                                new Transform(date, quaternion.revert()),
  151.                                                new Transform(date, pv)));

  152.                 // store transform from body frame to inertial frame
  153.                 final Transform b2i = bodyFrame.getTransformTo(inertialFrame, date);
  154.                 bodyToInertial.add(b2i);
  155.                 inertialToBody.add(b2i.getInverse());

  156.             }

  157.         } catch (OrekitException oe) {
  158.             throw new RuggedException(oe, oe.getSpecifier(), oe.getParts());
  159.         }
  160.     }

  161.     /** Simple constructor.
  162.      * @param inertialFrame inertial frame
  163.      * @param bodyFrame observed body frame
  164.      * @param minDate start of search time span
  165.      * @param maxDate end of search time span
  166.      * @param tStep step to use for inertial frame to body frame transforms cache computations
  167.      * @param overshootTolerance tolerance in seconds allowed for {@code minDate} and {@code maxDate} overshooting
  168.      * slightly the position, velocity and quaternions ephemerides
  169.      * @param bodyToInertial transforms sample from observed body frame to inertial frame
  170.      * @param scToInertial transforms sample from spacecraft frame to inertial frame
  171.      */
  172.     public SpacecraftToObservedBody(final Frame inertialFrame, final Frame bodyFrame,
  173.                                     final AbsoluteDate minDate, final AbsoluteDate maxDate, final double tStep,
  174.                                     final double overshootTolerance,
  175.                                     final List<Transform> bodyToInertial, final List<Transform> scToInertial) {

  176.         this.inertialFrame      = inertialFrame;
  177.         this.bodyFrame          = bodyFrame;
  178.         this.minDate            = minDate;
  179.         this.maxDate            = maxDate;
  180.         this.tStep              = tStep;
  181.         this.overshootTolerance = overshootTolerance;
  182.         this.bodyToInertial     = bodyToInertial;
  183.         this.scToInertial       = scToInertial;

  184.         this.inertialToBody = new ArrayList<Transform>(bodyToInertial.size());
  185.         for (final Transform b2i : bodyToInertial) {
  186.             inertialToBody.add(b2i.getInverse());
  187.         }

  188.     }

  189.     /** Get the inertial frame.
  190.      * @return inertial frame
  191.      */
  192.     public Frame getInertialFrame() {
  193.         return inertialFrame;
  194.     }

  195.     /** Get the body frame.
  196.      * @return body frame
  197.      */
  198.     public Frame getBodyFrame() {
  199.         return bodyFrame;
  200.     }

  201.     /** Get the start of search time span.
  202.      * @return start of search time span
  203.      */
  204.     public AbsoluteDate getMinDate() {
  205.         return minDate;
  206.     }

  207.     /** Get the end of search time span.
  208.      * @return end of search time span
  209.      */
  210.     public AbsoluteDate getMaxDate() {
  211.         return maxDate;
  212.     }

  213.     /** Get the step to use for inertial frame to body frame transforms cache computations.
  214.      * @return step to use for inertial frame to body frame transforms cache computations
  215.      */
  216.     public double getTStep() {
  217.         return tStep;
  218.     }

  219.     /** Get the tolerance in seconds allowed for {@link #getMinDate()} and {@link #getMaxDate()} overshooting.
  220.      * @return tolerance in seconds allowed for {@link #getMinDate()} and {@link #getMaxDate()} overshooting
  221.      */
  222.     public double getOvershootTolerance() {
  223.         return overshootTolerance;
  224.     }

  225.     /** Get transform from spacecraft to inertial frame.
  226.      * @param date date of the transform
  227.      * @return transform from spacecraft to inertial frame
  228.      * @exception RuggedException if frames cannot be computed at date
  229.      */
  230.     public Transform getScToInertial(final AbsoluteDate date)
  231.         throws RuggedException {
  232.         return interpolate(date, scToInertial);
  233.     }

  234.     /** Get transform from inertial frame to observed body frame.
  235.      * @param date date of the transform
  236.      * @return transform from inertial frame to observed body frame
  237.      * @exception RuggedException if frames cannot be computed at date
  238.      */
  239.     public Transform getInertialToBody(final AbsoluteDate date)
  240.         throws RuggedException {
  241.         return interpolate(date, inertialToBody);
  242.     }

  243.     /** Get transform from observed body frame to inertial frame.
  244.      * @param date date of the transform
  245.      * @return transform from observed body frame to inertial frame
  246.      * @exception RuggedException if frames cannot be computed at date
  247.      */
  248.     public Transform getBodyToInertial(final AbsoluteDate date)
  249.         throws RuggedException {
  250.         return interpolate(date, bodyToInertial);
  251.     }

  252.     /** Interpolate transform.
  253.      * @param date date of the transform
  254.      * @param list transforms list to interpolate from
  255.      * @return interpolated transform
  256.      * @exception RuggedException if frames cannot be computed at date
  257.      */
  258.     private Transform interpolate(final AbsoluteDate date, final List<Transform> list)
  259.         throws RuggedException {

  260.         // check date range
  261.         if (!isInRange(date)) {
  262.             throw new RuggedException(RuggedMessages.OUT_OF_TIME_RANGE, date, minDate, maxDate);
  263.         }

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

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

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

  269.     }

  270.     /** Check if a date is in the supported range.
  271.      * @param date date to check
  272.      * @return true if date is in the supported range
  273.      */
  274.     public boolean isInRange(final AbsoluteDate date) {
  275.         return (minDate.durationFrom(date) <= overshootTolerance) &&
  276.                (date.durationFrom(maxDate) <= overshootTolerance);
  277.     }

  278. }