BistaticRangeRate.java

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

  18. import java.util.Arrays;
  19. import java.util.Collections;
  20. import java.util.HashMap;
  21. import java.util.Map;

  22. import org.hipparchus.analysis.differentiation.Gradient;
  23. import org.hipparchus.analysis.differentiation.GradientField;
  24. import org.hipparchus.geometry.euclidean.threed.FieldVector3D;
  25. import org.orekit.frames.FieldTransform;
  26. import org.orekit.propagation.SpacecraftState;
  27. import org.orekit.time.AbsoluteDate;
  28. import org.orekit.time.FieldAbsoluteDate;
  29. import org.orekit.utils.ParameterDriver;
  30. import org.orekit.utils.TimeStampedFieldPVCoordinates;
  31. import org.orekit.utils.TimeStampedPVCoordinates;

  32. /** Class modeling a bistatic range rate measurement using
  33.  *  an emitter ground station and a receiver ground station.
  34.  * <p>
  35.  * The measurement is considered to be a signal:
  36.  * <ul>
  37.  * <li>Emitted from the emitter ground station</li>
  38.  * <li>Reflected on the spacecraft</li>
  39.  * <li>Received on the receiver ground station</li>
  40.  * </ul>
  41.  * The date of the measurement corresponds to the reception on ground of the reflected signal.
  42.  * The quantity measured at the receiver is the bistatic radial velocity as the sum of the radial
  43.  * velocities with respect to the two stations.
  44.  * <p>
  45.  * The motion of the stations and the spacecraft during the signal flight time are taken into account.
  46.  * </p><p>
  47.  * The Doppler measurement can be obtained by multiplying the velocity by (fe/c), where
  48.  * fe is the emission frequency.
  49.  * </p>
  50.  *
  51.  * @author Pascal Parraud
  52.  * @since 11.2
  53.  */
  54. public class BistaticRangeRate extends AbstractMeasurement<BistaticRangeRate> {

  55.     /** Type of the measurement. */
  56.     public static final String MEASUREMENT_TYPE = "BistaticRangeRate";

  57.     /** Emitter ground station. */
  58.     private final GroundStation emitter;

  59.     /** Receiver ground station. */
  60.     private final GroundStation receiver;

  61.     /** Simple constructor.
  62.      * @param emitter emitter ground station
  63.      * @param receiver receiver ground station
  64.      * @param date date of the measurement
  65.      * @param rangeRate observed value, m/s
  66.      * @param sigma theoretical standard deviation
  67.      * @param baseWeight base weight
  68.      * @param satellite satellite related to this measurement
  69.      */
  70.     public BistaticRangeRate(final GroundStation emitter, final GroundStation receiver,
  71.                              final AbsoluteDate date, final double rangeRate, final double sigma,
  72.                              final double baseWeight, final ObservableSatellite satellite) {
  73.         super(date, rangeRate, sigma, baseWeight, Collections.singletonList(satellite));
  74.         // add parameter drivers for the emitter, clock offset is not used
  75.         addParameterDriver(emitter.getEastOffsetDriver());
  76.         addParameterDriver(emitter.getNorthOffsetDriver());
  77.         addParameterDriver(emitter.getZenithOffsetDriver());
  78.         addParameterDriver(emitter.getPrimeMeridianOffsetDriver());
  79.         addParameterDriver(emitter.getPrimeMeridianDriftDriver());
  80.         addParameterDriver(emitter.getPolarOffsetXDriver());
  81.         addParameterDriver(emitter.getPolarDriftXDriver());
  82.         addParameterDriver(emitter.getPolarOffsetYDriver());
  83.         addParameterDriver(emitter.getPolarDriftYDriver());
  84.         // add parameter drivers for the receiver
  85.         addParameterDriver(receiver.getClockOffsetDriver());
  86.         addParameterDriver(receiver.getEastOffsetDriver());
  87.         addParameterDriver(receiver.getNorthOffsetDriver());
  88.         addParameterDriver(receiver.getZenithOffsetDriver());
  89.         addParameterDriver(receiver.getPrimeMeridianOffsetDriver());
  90.         addParameterDriver(receiver.getPrimeMeridianDriftDriver());
  91.         addParameterDriver(receiver.getPolarOffsetXDriver());
  92.         addParameterDriver(receiver.getPolarDriftXDriver());
  93.         addParameterDriver(receiver.getPolarOffsetYDriver());
  94.         addParameterDriver(receiver.getPolarDriftYDriver());
  95.         this.emitter  = emitter;
  96.         this.receiver = receiver;
  97.     }

  98.     /** Get the emitter ground station.
  99.      * @return emitter ground station
  100.      */
  101.     public GroundStation getEmitterStation() {
  102.         return emitter;
  103.     }

  104.     /** Get the receiver ground station.
  105.      * @return receiver ground station
  106.      */
  107.     public GroundStation getReceiverStation() {
  108.         return receiver;
  109.     }

  110.     /** {@inheritDoc} */
  111.     @Override
  112.     protected EstimatedMeasurement<BistaticRangeRate> theoreticalEvaluation(final int iteration,
  113.                                                                             final int evaluation,
  114.                                                                             final SpacecraftState[] states) {

  115.         final SpacecraftState state = states[0];

  116.         // Bistatic range rate derivatives are computed with respect to:
  117.         // - Spacecraft state in inertial frame
  118.         // - Emitter station parameters
  119.         // - Receiver station parameters
  120.         // --------------------------
  121.         //  - 0..2 - Position of the spacecraft in inertial frame
  122.         //  - 3..5 - Velocity of the spacecraft in inertial frame
  123.         //  - 6..n - stations' parameters (stations' offsets, pole, prime meridian...)
  124.         int nbParams = 6;
  125.         final Map<String, Integer> indices = new HashMap<String, Integer>();
  126.         for (ParameterDriver driver : getParametersDrivers()) {
  127.             // we have to check for duplicate keys because emitter and receiver stations share
  128.             // pole and prime meridian parameters names that must be considered
  129.             // as one set only (they are combined together by the estimation engine)
  130.             if (driver.isSelected() && !indices.containsKey(driver.getName())) {
  131.                 indices.put(driver.getName(), nbParams++);
  132.             }
  133.         }
  134.         final FieldVector3D<Gradient> zero = FieldVector3D.getZero(GradientField.getField(nbParams));

  135.         // coordinates of the spacecraft as a gradient
  136.         final TimeStampedFieldPVCoordinates<Gradient> pvaG = getCoordinates(state, 0, nbParams);

  137.         // transform between receiver station frame and inertial frame
  138.         // at the real date of measurement, i.e. taking station clock offset into account
  139.         final FieldTransform<Gradient> receiverToInertial =
  140.                         receiver.getOffsetToInertial(state.getFrame(), getDate(), nbParams, indices);
  141.         final FieldAbsoluteDate<Gradient> measurementDateG = receiverToInertial.getFieldDate();

  142.         // Receiver PV in inertial frame at the end of the downlink leg
  143.         final TimeStampedFieldPVCoordinates<Gradient> receiverPV =
  144.                         receiverToInertial.transformPVCoordinates(new TimeStampedFieldPVCoordinates<>(measurementDateG,
  145.                                                                                                       zero, zero, zero));

  146.         // Compute propagation times
  147.         // (if state has already been set up to pre-compensate propagation delay,
  148.         //  we will have delta == tauD and transitState will be the same as state)

  149.         // Downlink delay
  150.         final Gradient tauD       = signalTimeOfFlight(pvaG, receiverPV.getPosition(), measurementDateG);
  151.         final Gradient delta      = measurementDateG.durationFrom(state.getDate());
  152.         final Gradient deltaMTauD = delta.subtract(tauD);

  153.         // Transit state
  154.         final SpacecraftState transitState = state.shiftedBy(deltaMTauD.getValue());

  155.         // Transit PV
  156.         final TimeStampedFieldPVCoordinates<Gradient> transitPV = pvaG.shiftedBy(deltaMTauD);

  157.         // Downlink range-rate
  158.         final EstimatedMeasurement<BistaticRangeRate> evalDownlink =
  159.                         oneWayTheoreticalEvaluation(iteration, evaluation, true,
  160.                                                     receiverPV, transitPV, transitState, indices);

  161.         // transform between emitter station frame and inertial frame at the transit date
  162.         // clock offset from receiver is already compensated
  163.         final FieldTransform<Gradient> emitterToInertial =
  164.                         emitter.getOffsetToInertial(state.getFrame(), transitPV.getDate(), nbParams, indices);

  165.         // emitter PV in inertial frame at the end of the uplink leg
  166.         final TimeStampedFieldPVCoordinates<Gradient> emitterPV =
  167.                         emitterToInertial.transformPVCoordinates(new TimeStampedFieldPVCoordinates<>(transitPV.getDate(),
  168.                                                                                                      zero, zero, zero));

  169.         // Uplink delay
  170.         final Gradient tauU = signalTimeOfFlight(emitterPV, transitPV.getPosition(), transitPV.getDate());

  171.         // emitter position in inertial frame at the end of the uplink leg
  172.         final TimeStampedFieldPVCoordinates<Gradient> emitterUplink = emitterPV.shiftedBy(tauU.negate());

  173.         // Uplink range-rate
  174.         final EstimatedMeasurement<BistaticRangeRate> evalUplink =
  175.                         oneWayTheoreticalEvaluation(iteration, evaluation, false,
  176.                                                     emitterUplink, transitPV, transitState, indices);

  177.         // combine uplink and downlink values
  178.         final EstimatedMeasurement<BistaticRangeRate> estimated =
  179.                         new EstimatedMeasurement<>(this, iteration, evaluation,
  180.                                                    evalDownlink.getStates(),
  181.                                                    new TimeStampedPVCoordinates[] {
  182.                                                        evalUplink.getParticipants()[0],
  183.                                                        evalDownlink.getParticipants()[0],
  184.                                                        evalDownlink.getParticipants()[1]
  185.                                                    });
  186.         estimated.setEstimatedValue(evalDownlink.getEstimatedValue()[0] + evalUplink.getEstimatedValue()[0]);

  187.         // combine uplink and downlink partial derivatives with respect to state
  188.         final double[][] sd1 = evalDownlink.getStateDerivatives(0);
  189.         final double[][] sd2 = evalUplink.getStateDerivatives(0);
  190.         final double[][] sd  = new double[sd1.length][sd1[0].length];
  191.         for (int i = 0; i < sd.length; ++i) {
  192.             for (int j = 0; j < sd[0].length; ++j) {
  193.                 sd[i][j] = sd1[i][j] + sd2[i][j];
  194.             }
  195.         }
  196.         estimated.setStateDerivatives(0, sd);

  197.         // combine uplink and downlink partial derivatives with respect to parameters
  198.         evalDownlink.getDerivativesDrivers().forEach(driver -> {
  199.             final double[] pd1 = evalDownlink.getParameterDerivatives(driver);
  200.             final double[] pd2 = evalUplink.getParameterDerivatives(driver);
  201.             final double[] pd  = new double[pd1.length];
  202.             for (int i = 0; i < pd.length; ++i) {
  203.                 pd[i] = pd1[i] + pd2[i];
  204.             }
  205.             estimated.setParameterDerivatives(driver, pd);
  206.         });

  207.         return estimated;

  208.     }


  209.     /** Evaluate range rate measurement in one-way.
  210.      * @param iteration iteration number
  211.      * @param evaluation evaluations counter
  212.      * @param downlink indicator for downlink leg
  213.      * @param stationPV station coordinates when signal is at station
  214.      * @param transitPV spacecraft coordinates at onboard signal transit
  215.      * @param transitState orbital state at onboard signal transit
  216.      * @param indices indices of the estimated parameters in derivatives computations
  217.      * @return theoretical value for the current leg
  218.      */
  219.     private EstimatedMeasurement<BistaticRangeRate> oneWayTheoreticalEvaluation(final int iteration, final int evaluation, final boolean downlink,
  220.                                                                                 final TimeStampedFieldPVCoordinates<Gradient> stationPV,
  221.                                                                                 final TimeStampedFieldPVCoordinates<Gradient> transitPV,
  222.                                                                                 final SpacecraftState transitState,
  223.                                                                                 final Map<String, Integer> indices) {

  224.         // prepare the evaluation
  225.         final EstimatedMeasurement<BistaticRangeRate> estimated =
  226.             new EstimatedMeasurement<BistaticRangeRate>(this, iteration, evaluation,
  227.                                                         new SpacecraftState[] {
  228.                                                             transitState
  229.                                                         }, new TimeStampedPVCoordinates[] {
  230.                                                             (downlink ? transitPV : stationPV).toTimeStampedPVCoordinates(),
  231.                                                             (downlink ? stationPV : transitPV).toTimeStampedPVCoordinates()
  232.                                                         });

  233.         // range rate value
  234.         final FieldVector3D<Gradient> stationPosition  = stationPV.getPosition();
  235.         final FieldVector3D<Gradient> relativePosition = stationPosition.subtract(transitPV.getPosition());

  236.         final FieldVector3D<Gradient> stationVelocity  = stationPV.getVelocity();
  237.         final FieldVector3D<Gradient> relativeVelocity = stationVelocity.subtract(transitPV.getVelocity());

  238.         // radial direction
  239.         final FieldVector3D<Gradient> lineOfSight      = relativePosition.normalize();

  240.         // range rate
  241.         final Gradient rangeRate = FieldVector3D.dotProduct(relativeVelocity, lineOfSight);

  242.         estimated.setEstimatedValue(rangeRate.getValue());

  243.         // compute partial derivatives of (rr) with respect to spacecraft state Cartesian coordinates
  244.         final double[] derivatives = rangeRate.getGradient();
  245.         estimated.setStateDerivatives(0, Arrays.copyOfRange(derivatives, 0, 6));

  246.         // set partial derivatives with respect to parameters
  247.         for (final ParameterDriver driver : getParametersDrivers()) {
  248.             final Integer index = indices.get(driver.getName());
  249.             if (index != null) {
  250.                 estimated.setParameterDerivatives(driver, derivatives[index]);
  251.             }
  252.         }

  253.         return estimated;

  254.     }
  255. }