EstimatedEarthFrameProvider.java

  1. /* Copyright 2002-2018 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.estimation.measurements;

  18. import java.io.Serializable;
  19. import java.util.Map;

  20. import org.hipparchus.RealFieldElement;
  21. import org.hipparchus.analysis.differentiation.DSFactory;
  22. import org.hipparchus.analysis.differentiation.DerivativeStructure;
  23. import org.hipparchus.geometry.euclidean.threed.FieldRotation;
  24. import org.hipparchus.geometry.euclidean.threed.FieldVector3D;
  25. import org.hipparchus.geometry.euclidean.threed.Rotation;
  26. import org.hipparchus.geometry.euclidean.threed.RotationConvention;
  27. import org.hipparchus.geometry.euclidean.threed.Vector3D;
  28. import org.hipparchus.util.FastMath;
  29. import org.orekit.errors.OrekitException;
  30. import org.orekit.errors.OrekitExceptionWrapper;
  31. import org.orekit.errors.OrekitInternalError;
  32. import org.orekit.errors.OrekitMessages;
  33. import org.orekit.frames.FieldTransform;
  34. import org.orekit.frames.Transform;
  35. import org.orekit.frames.TransformProvider;
  36. import org.orekit.time.AbsoluteDate;
  37. import org.orekit.time.FieldAbsoluteDate;
  38. import org.orekit.time.UT1Scale;
  39. import org.orekit.utils.IERSConventions;
  40. import org.orekit.utils.ParameterDriver;

  41. /** Class modeling an Earth frame whose Earth Orientation Parameters can be estimated.
  42.  * <p>
  43.  * This class adds parameters for an additional polar motion
  44.  * and an additional prime meridian orientation on top of an underlying regular Earth
  45.  * frame like {@link org.orekit.frames.FramesFactory#getITRF(IERSConventions, boolean) ITRF}.
  46.  * The polar motion and prime meridian orientation are applied <em>after</em> regular Earth
  47.  * orientation parameters, so the value of the estimated parameters will be correction to EOP,
  48.  * they will not be the complete EOP values by themselves. Basically, this means that for
  49.  * Earth, the following transforms are applied in order, between inertial frame and this frame:
  50.  * </p>
  51.  * <ol>
  52.  *   <li>precession/nutation, as theoretical model plus celestial pole EOP parameters</li>
  53.  *   <li>body rotation, as theoretical model plus prime meridian EOP parameters</li>
  54.  *   <li>polar motion, which is only from EOP parameters (no theoretical models)</li>
  55.  *   <li>additional body rotation, controlled by {@link #getPrimeMeridianOffsetDriver()} and {@link #getPrimeMeridianDriftDriver()}</li>
  56.  *   <li>additional polar motion, controlled by {@link #getPolarOffsetXDriver()}, {@link #getPolarDriftXDriver()},
  57.  *   {@link #getPolarOffsetYDriver()} and {@link #getPolarDriftYDriver()}</li>
  58.  * </ol>
  59.  * @author Luc Maisonobe
  60.  * @since 9.1
  61.  */
  62. public class EstimatedEarthFrameProvider implements TransformProvider {

  63.     /** Earth Angular Velocity, in rad/s, from TIRF model. */
  64.     public static final double EARTH_ANGULAR_VELOCITY = 7.292115146706979e-5;

  65.     /** Serializable UID. */
  66.     private static final long serialVersionUID = 20170922L;

  67.     /** Angular scaling factor.
  68.      * <p>
  69.      * We use a power of 2 to avoid numeric noise introduction
  70.      * in the multiplications/divisions sequences.
  71.      * </p>
  72.      */
  73.     private static final double ANGULAR_SCALE = FastMath.scalb(1.0, -22);

  74.     /** Underlying raw UT1. */
  75.     private final UT1Scale baseUT1;

  76.     /** Estimated UT1. */
  77.     private final transient UT1Scale estimatedUT1;

  78.     /** Driver for prime meridian offset. */
  79.     private final transient ParameterDriver primeMeridianOffsetDriver;

  80.     /** Driver for prime meridian drift. */
  81.     private final transient ParameterDriver primeMeridianDriftDriver;

  82.     /** Driver for pole offset along X. */
  83.     private final transient ParameterDriver polarOffsetXDriver;

  84.     /** Driver for pole drift along X. */
  85.     private final transient ParameterDriver polarDriftXDriver;

  86.     /** Driver for pole offset along Y. */
  87.     private final transient ParameterDriver polarOffsetYDriver;

  88.     /** Driver for pole drift along Y. */
  89.     private final transient ParameterDriver polarDriftYDriver;

  90.     /** Build an estimated Earth frame.
  91.      * <p>
  92.      * The initial values for the pole and prime meridian parametric linear models
  93.      * ({@link #getPrimeMeridianOffsetDriver()}, {@link #getPrimeMeridianDriftDriver()},
  94.      * {@link #getPolarOffsetXDriver()}, {@link #getPolarDriftXDriver()},
  95.      * {@link #getPolarOffsetXDriver()}, {@link #getPolarDriftXDriver()}) are set to 0.
  96.      * </p>
  97.      * @param baseUT1 underlying base UT1
  98.      * @exception OrekitException if scales are too close to zero (never happens)
  99.      * @since 9.1
  100.      */
  101.     public EstimatedEarthFrameProvider(final UT1Scale baseUT1)
  102.         throws OrekitException {

  103.         this.primeMeridianOffsetDriver = new ParameterDriver("prime-meridian-offset",
  104.                                                              0.0, ANGULAR_SCALE,
  105.                                                             -FastMath.PI, FastMath.PI);

  106.         this.primeMeridianDriftDriver = new ParameterDriver("prime-meridian-drift",
  107.                                                             0.0, ANGULAR_SCALE,
  108.                                                             Double.NEGATIVE_INFINITY, Double.POSITIVE_INFINITY);

  109.         this.polarOffsetXDriver = new ParameterDriver("polar-offset-X",
  110.                                                       0.0, ANGULAR_SCALE,
  111.                                                       -FastMath.PI, FastMath.PI);

  112.         this.polarDriftXDriver = new ParameterDriver("polar-drift-X",
  113.                                                      0.0, ANGULAR_SCALE,
  114.                                                      Double.NEGATIVE_INFINITY, Double.POSITIVE_INFINITY);

  115.         this.polarOffsetYDriver = new ParameterDriver("polar-offset-Y",
  116.                                                       0.0, ANGULAR_SCALE,
  117.                                                       -FastMath.PI, FastMath.PI);

  118.         this.polarDriftYDriver = new ParameterDriver("polar-drift-Y",
  119.                                                      0.0, ANGULAR_SCALE,
  120.                                                      Double.NEGATIVE_INFINITY, Double.POSITIVE_INFINITY);

  121.         this.baseUT1      = baseUT1;
  122.         this.estimatedUT1 = new EstimatedUT1Scale();

  123.     }

  124.     /** Get a driver allowing to add a prime meridian rotation.
  125.      * <p>
  126.      * The parameter is an angle in radians. In order to convert this
  127.      * value to a DUT1 in seconds, the value must be divided by
  128.      * {@link #EARTH_ANGULAR_VELOCITY} (nominal Angular Velocity of Earth).
  129.      * </p>
  130.      * @return driver for prime meridian rotation
  131.      */
  132.     public ParameterDriver getPrimeMeridianOffsetDriver() {
  133.         return primeMeridianOffsetDriver;
  134.     }

  135.     /** Get a driver allowing to add a prime meridian rotation rate.
  136.      * <p>
  137.      * The parameter is an angle rate in radians per second. In order to convert this
  138.      * value to a LOD in seconds, the value must be multiplied by -86400 and divided by
  139.      * {@link #EARTH_ANGULAR_VELOCITY} (nominal Angular Velocity of Earth).
  140.      * </p>
  141.      * @return driver for prime meridian rotation rate
  142.      */
  143.     public ParameterDriver getPrimeMeridianDriftDriver() {
  144.         return primeMeridianDriftDriver;
  145.     }

  146.     /** Get a driver allowing to add a polar offset along X.
  147.      * <p>
  148.      * The parameter is an angle in radians
  149.      * </p>
  150.      * @return driver for polar offset along X
  151.      */
  152.     public ParameterDriver getPolarOffsetXDriver() {
  153.         return polarOffsetXDriver;
  154.     }

  155.     /** Get a driver allowing to add a polar drift along X.
  156.      * <p>
  157.      * The parameter is an angle rate in radians per second
  158.      * </p>
  159.      * @return driver for polar drift along X
  160.      */
  161.     public ParameterDriver getPolarDriftXDriver() {
  162.         return polarDriftXDriver;
  163.     }

  164.     /** Get a driver allowing to add a polar offset along Y.
  165.      * <p>
  166.      * The parameter is an angle in radians
  167.      * </p>
  168.      * @return driver for polar offset along Y
  169.      */
  170.     public ParameterDriver getPolarOffsetYDriver() {
  171.         return polarOffsetYDriver;
  172.     }

  173.     /** Get a driver allowing to add a polar drift along Y.
  174.      * <p>
  175.      * The parameter is an angle rate in radians per second
  176.      * </p>
  177.      * @return driver for polar drift along Y
  178.      */
  179.     public ParameterDriver getPolarDriftYDriver() {
  180.         return polarDriftYDriver;
  181.     }

  182.     /** Get the estimated UT1 time scale.
  183.      * @return estimated UT1 time scale
  184.      */
  185.     public UT1Scale getEstimatedUT1() {
  186.         return estimatedUT1;
  187.     }

  188.     /** {@inheritDoc} */
  189.     @Override
  190.     public Transform getTransform(final AbsoluteDate date)
  191.         throws OrekitException {

  192.         // take parametric prime meridian shift into account
  193.         final double theta    = linearModel(date, primeMeridianOffsetDriver, primeMeridianDriftDriver);
  194.         final double thetaDot = parametricModel(primeMeridianDriftDriver);
  195.         final Transform meridianShift =
  196.                         new Transform(date,
  197.                                       new Rotation(Vector3D.PLUS_K, theta, RotationConvention.FRAME_TRANSFORM),
  198.                                       new Vector3D(0, 0, thetaDot));

  199.         // take parametric pole shift into account
  200.         final double xpNeg     = -linearModel(date, polarOffsetXDriver, polarDriftXDriver);
  201.         final double ypNeg     = -linearModel(date, polarOffsetYDriver, polarDriftYDriver);
  202.         final double xpNegDot  = -parametricModel(polarDriftXDriver);
  203.         final double ypNegDot  = -parametricModel(polarDriftYDriver);
  204.         final Transform poleShift =
  205.                         new Transform(date,
  206.                                       new Transform(date,
  207.                                                     new Rotation(Vector3D.PLUS_J, xpNeg, RotationConvention.FRAME_TRANSFORM),
  208.                                                     new Vector3D(0.0, xpNegDot, 0.0)),
  209.                                       new Transform(date,
  210.                                                     new Rotation(Vector3D.PLUS_I, ypNeg, RotationConvention.FRAME_TRANSFORM),
  211.                                                     new Vector3D(ypNegDot, 0.0, 0.0)));

  212.         return new Transform(date, meridianShift, poleShift);

  213.     }

  214.     /** {@inheritDoc} */
  215.     @Override
  216.     public <T extends RealFieldElement<T>> FieldTransform<T> getTransform(final FieldAbsoluteDate<T> date)
  217.         throws OrekitException {

  218.         final T zero = date.getField().getZero();

  219.         // prime meridian shift parameters
  220.         final T theta    = linearModel(date, primeMeridianOffsetDriver, primeMeridianDriftDriver);
  221.         final T thetaDot = zero.add(parametricModel(primeMeridianDriftDriver));

  222.         // pole shift parameters
  223.         final T xpNeg    = linearModel(date, polarOffsetXDriver, polarDriftXDriver).negate();
  224.         final T ypNeg    = linearModel(date, polarOffsetYDriver, polarDriftYDriver).negate();
  225.         final T xpNegDot = zero.subtract(parametricModel(polarDriftXDriver));
  226.         final T ypNegDot = zero.subtract(parametricModel(polarDriftYDriver));

  227.         return getTransform(date, theta, thetaDot, xpNeg, xpNegDot, ypNeg, ypNegDot);

  228.     }

  229.     /** Get the transform with derivatives.
  230.      * @param date date of the transform
  231.      * @param factory factory for the derivatives
  232.      * @param indices indices of the estimated parameters in derivatives computations
  233.      * @return computed transform with derivatives
  234.      * @exception OrekitException if some frame transforms cannot be computed
  235.      */
  236.     public FieldTransform<DerivativeStructure> getTransform(final FieldAbsoluteDate<DerivativeStructure> date,
  237.                                                             final DSFactory factory,
  238.                                                             final Map<String, Integer> indices)
  239.         throws OrekitException {

  240.         // prime meridian shift parameters
  241.         final DerivativeStructure theta    = linearModel(factory, date,
  242.                                                          primeMeridianOffsetDriver, primeMeridianDriftDriver,
  243.                                                          indices);
  244.         final DerivativeStructure thetaDot = parametricModel(factory, primeMeridianDriftDriver, indices);

  245.         // pole shift parameters
  246.         final DerivativeStructure xpNeg    = linearModel(factory, date,
  247.                                                          polarOffsetXDriver, polarDriftXDriver, indices).negate();
  248.         final DerivativeStructure ypNeg    = linearModel(factory, date,
  249.                                                          polarOffsetYDriver, polarDriftYDriver, indices).negate();
  250.         final DerivativeStructure xpNegDot = parametricModel(factory, polarDriftXDriver, indices).negate();
  251.         final DerivativeStructure ypNegDot = parametricModel(factory, polarDriftYDriver, indices).negate();

  252.         return getTransform(date, theta, thetaDot, xpNeg, xpNegDot, ypNeg, ypNegDot);

  253.     }

  254.     /** Get the transform with derivatives.
  255.      * @param date date of the transform
  256.      * @param theta angle of the prime meridian
  257.      * @param thetaDot angular rate of the prime meridian
  258.      * @param xpNeg opposite of the angle of the pole motion along X
  259.      * @param xpNegDot opposite of the angular rate of the pole motion along X
  260.      * @param ypNeg opposite of the angle of the pole motion along Y
  261.      * @param ypNegDot opposite of the angular rate of the pole motion along Y
  262.      * @param <T> type of the field elements
  263.      * @return computed transform with derivatives
  264.      * @exception OrekitException if some frame transforms cannot be computed
  265.      */
  266.     private <T extends RealFieldElement<T>> FieldTransform<T> getTransform(final FieldAbsoluteDate<T> date,
  267.                                                                            final T theta, final T thetaDot,
  268.                                                                            final T xpNeg, final T xpNegDot,
  269.                                                                            final T ypNeg, final T ypNegDot)
  270.         throws OrekitException {

  271.         final T                zero  = date.getField().getZero();
  272.         final FieldVector3D<T> plusI = FieldVector3D.getPlusI(date.getField());
  273.         final FieldVector3D<T> plusJ = FieldVector3D.getPlusJ(date.getField());
  274.         final FieldVector3D<T> plusK = FieldVector3D.getPlusK(date.getField());

  275.         // take parametric prime meridian shift into account
  276.         final FieldTransform<T> meridianShift =
  277.                         new FieldTransform<>(date,
  278.                                              new FieldRotation<>(plusK, theta, RotationConvention.FRAME_TRANSFORM),
  279.                                              new FieldVector3D<>(zero, zero, thetaDot));

  280.         // take parametric pole shift into account
  281.         final FieldTransform<T> poleShift =
  282.                         new FieldTransform<>(date,
  283.                                       new FieldTransform<>(date,
  284.                                                            new FieldRotation<>(plusJ, xpNeg, RotationConvention.FRAME_TRANSFORM),
  285.                                                            new FieldVector3D<>(zero, xpNegDot, zero)),
  286.                                       new FieldTransform<>(date,
  287.                                                            new FieldRotation<>(plusI, ypNeg, RotationConvention.FRAME_TRANSFORM),
  288.                                                            new FieldVector3D<>(ypNegDot, zero, zero)));

  289.         return new FieldTransform<>(date, meridianShift, poleShift);

  290.     }

  291.     /** Evaluate a parametric linear model.
  292.      * @param date current date
  293.      * @param offsetDriver driver for the offset parameter
  294.      * @param driftDriver driver for the drift parameter
  295.      * @return current value of the linear model
  296.      * @exception OrekitException if reference date has not been set for the
  297.      * offset driver
  298.      */
  299.     private double linearModel(final AbsoluteDate date,
  300.                                final ParameterDriver offsetDriver, final ParameterDriver driftDriver)
  301.         throws OrekitException {
  302.         if (offsetDriver.getReferenceDate() == null) {
  303.             throw new OrekitException(OrekitMessages.NO_REFERENCE_DATE_FOR_PARAMETER,
  304.                                       offsetDriver.getName());
  305.         }
  306.         final double dt     = date.durationFrom(offsetDriver.getReferenceDate());
  307.         final double offset = parametricModel(offsetDriver);
  308.         final double drift  = parametricModel(driftDriver);
  309.         return dt * drift + offset;
  310.     }

  311.     /** Evaluate a parametric linear model.
  312.      * @param date current date
  313.      * @param offsetDriver driver for the offset parameter
  314.      * @param driftDriver driver for the drift parameter
  315.      * @return current value of the linear model
  316.      * @exception OrekitException if reference date has not been set for the
  317.      * offset driver
  318.      * @param <T> type of the filed elements
  319.      */
  320.     private <T extends RealFieldElement<T>> T linearModel(final FieldAbsoluteDate<T> date,
  321.                                                           final ParameterDriver offsetDriver,
  322.                                                           final ParameterDriver driftDriver)
  323.         throws OrekitException {
  324.         if (offsetDriver.getReferenceDate() == null) {
  325.             throw new OrekitException(OrekitMessages.NO_REFERENCE_DATE_FOR_PARAMETER,
  326.                                       offsetDriver.getName());
  327.         }
  328.         final T dt          = date.durationFrom(offsetDriver.getReferenceDate());
  329.         final double offset = parametricModel(offsetDriver);
  330.         final double drift  = parametricModel(driftDriver);
  331.         return dt.multiply(drift).add(offset);
  332.     }

  333.     /** Evaluate a parametric linear model.
  334.      * @param factory factory for the derivatives
  335.      * @param date current date
  336.      * @param offsetDriver driver for the offset parameter
  337.      * @param driftDriver driver for the drift parameter
  338.      * @param indices indices of the estimated parameters in derivatives computations
  339.      * @return current value of the linear model
  340.      * @exception OrekitException if reference date has not been set for the
  341.      * offset driver
  342.      */
  343.     private DerivativeStructure linearModel(final DSFactory factory, final FieldAbsoluteDate<DerivativeStructure> date,
  344.                                             final ParameterDriver offsetDriver, final ParameterDriver driftDriver,
  345.                                             final Map<String, Integer> indices)
  346.         throws OrekitException {
  347.         if (offsetDriver.getReferenceDate() == null) {
  348.             throw new OrekitException(OrekitMessages.NO_REFERENCE_DATE_FOR_PARAMETER,
  349.                                       offsetDriver.getName());
  350.         }
  351.         final DerivativeStructure dt     = date.durationFrom(offsetDriver.getReferenceDate());
  352.         final DerivativeStructure offset = parametricModel(factory, offsetDriver, indices);
  353.         final DerivativeStructure drift  = parametricModel(factory, driftDriver, indices);
  354.         return dt.multiply(drift).add(offset);
  355.     }

  356.     /** Evaluate a parametric model.
  357.      * @param driver driver managing the parameter
  358.      * @return value of the parametric model
  359.      */
  360.     private double parametricModel(final ParameterDriver driver) {
  361.         return driver.getValue();
  362.     }

  363.     /** Evaluate a parametric model.
  364.      * @param factory factory for the derivatives
  365.      * @param driver driver managing the parameter
  366.      * @param indices indices of the estimated parameters in derivatives computations
  367.      * @return value of the parametric model
  368.      */
  369.     private DerivativeStructure parametricModel(final DSFactory factory, final ParameterDriver driver,
  370.                                                 final Map<String, Integer> indices) {
  371.         final Integer index = indices.get(driver.getName());
  372.         return (index == null) ?
  373.                factory.constant(driver.getValue()) :
  374.                factory.variable(index, driver.getValue());
  375.     }

  376.     /** Replace the instance with a data transfer object for serialization.
  377.      * <p>
  378.      * This intermediate class serializes the files supported names, the ephemeris type
  379.      * and the body name.
  380.      * </p>
  381.      * @return data transfer object that will be serialized
  382.      */
  383.     private Object writeReplace() {
  384.         return new DataTransferObject(baseUT1,
  385.                                       primeMeridianOffsetDriver.getValue(),
  386.                                       primeMeridianDriftDriver.getValue(),
  387.                                       polarOffsetXDriver.getValue(),
  388.                                       polarDriftXDriver.getValue(),
  389.                                       polarOffsetYDriver.getValue(),
  390.                                       polarDriftYDriver.getValue());
  391.     }

  392.     /** Local time scale for estimated UT1. */
  393.     private class EstimatedUT1Scale extends UT1Scale {

  394.         /** Serializable UID. */
  395.         private static final long serialVersionUID = 20170922L;

  396.         /** Simple constructor.
  397.          */
  398.         EstimatedUT1Scale() {
  399.             super(baseUT1.getEOPHistory(), baseUT1.getUTCScale());
  400.         }

  401.         /** {@inheritDoc} */
  402.         @Override
  403.         public <T extends RealFieldElement<T>> T offsetFromTAI(final FieldAbsoluteDate<T> date) {
  404.             try {
  405.                 final T dut1 = linearModel(date, primeMeridianOffsetDriver, primeMeridianDriftDriver).divide(EARTH_ANGULAR_VELOCITY);
  406.                 return baseUT1.offsetFromTAI(date).add(dut1);
  407.             } catch (OrekitException oe) {
  408.                 throw new OrekitExceptionWrapper(oe);
  409.             }
  410.         }

  411.         /** {@inheritDoc} */
  412.         @Override
  413.         public double offsetFromTAI(final AbsoluteDate date) throws OrekitExceptionWrapper {
  414.             try {
  415.                 final double dut1 = linearModel(date, primeMeridianOffsetDriver, primeMeridianDriftDriver) / EARTH_ANGULAR_VELOCITY;
  416.                 return baseUT1.offsetFromTAI(date) + dut1;
  417.             } catch (OrekitException oe) {
  418.                 throw new OrekitExceptionWrapper(oe);
  419.             }
  420.         }

  421.         /** {@inheritDoc} */
  422.         @Override
  423.         public String getName() {
  424.             return baseUT1.getName() + "/estimated";
  425.         }

  426.     }

  427.     /** Internal class used only for serialization. */
  428.     private static class DataTransferObject implements Serializable {

  429.         /** Serializable UID. */
  430.         private static final long serialVersionUID = 20171124L;

  431.         /** Underlying raw UT1. */
  432.         private final UT1Scale baseUT1;

  433.         /** Current prime meridian offset. */
  434.         private final double primeMeridianOffset;

  435.         /** Current prime meridian drift. */
  436.         private final double primeMeridianDrift;

  437.         /** Current pole offset along X. */
  438.         private final double polarOffsetX;

  439.         /** Current pole drift along X. */
  440.         private final double polarDriftX;

  441.         /** Current pole offset along Y. */
  442.         private final double polarOffsetY;

  443.         /** Current pole drift along Y. */
  444.         private final double polarDriftY;

  445.         /** Simple constructor.
  446.          * @param baseUT1 underlying raw UT1
  447.          * @param primeMeridianOffset current prime meridian offset
  448.          * @param primeMeridianDrift current prime meridian drift
  449.          * @param polarOffsetX current pole offset along X
  450.          * @param polarDriftX current pole drift along X
  451.          * @param polarOffsetY current pole offset along Y
  452.          * @param polarDriftY current pole drift along Y
  453.          */
  454.         DataTransferObject(final  UT1Scale baseUT1,
  455.                            final double primeMeridianOffset, final double primeMeridianDrift,
  456.                            final double polarOffsetX,        final double polarDriftX,
  457.                            final double polarOffsetY,        final double polarDriftY) {
  458.             this.baseUT1             = baseUT1;
  459.             this.primeMeridianOffset = primeMeridianOffset;
  460.             this.primeMeridianDrift  = primeMeridianDrift;
  461.             this.polarOffsetX        = polarOffsetX;
  462.             this.polarDriftX         = polarDriftX;
  463.             this.polarOffsetY        = polarOffsetY;
  464.             this.polarDriftY         = polarDriftY;
  465.         }

  466.         /** Replace the deserialized data transfer object with a {@link EstimatedEarthFrameProvider}.
  467.          * @return replacement {@link EstimatedEarthFrameProvider}
  468.          */
  469.         private Object readResolve() {
  470.             try {
  471.                 final EstimatedEarthFrameProvider provider = new EstimatedEarthFrameProvider(baseUT1);
  472.                 provider.getPrimeMeridianOffsetDriver().setValue(primeMeridianOffset);
  473.                 provider.getPrimeMeridianDriftDriver().setValue(primeMeridianDrift);
  474.                 provider.getPolarOffsetXDriver().setValue(polarOffsetX);
  475.                 provider.getPolarDriftXDriver().setValue(polarDriftX);
  476.                 provider.getPolarOffsetYDriver().setValue(polarOffsetY);
  477.                 provider.getPolarDriftYDriver().setValue(polarDriftY);
  478.                 return provider;
  479.             } catch (OrekitException oe) {
  480.                 // this should never happen as values already come from previous drivers
  481.                 throw new OrekitInternalError(oe);
  482.             }
  483.         }

  484.     }

  485. }