BistaticRangeRate.java

  1. /* Copyright 2002-2025 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 org.hipparchus.analysis.differentiation.Gradient;
  20. import org.hipparchus.geometry.euclidean.threed.FieldVector3D;
  21. import org.hipparchus.geometry.euclidean.threed.Vector3D;
  22. import org.orekit.frames.FieldTransform;
  23. import org.orekit.frames.Transform;
  24. import org.orekit.propagation.SpacecraftState;
  25. import org.orekit.time.AbsoluteDate;
  26. import org.orekit.time.FieldAbsoluteDate;
  27. import org.orekit.utils.ParameterDriver;
  28. import org.orekit.utils.TimeSpanMap.Span;
  29. import org.orekit.utils.TimeStampedFieldPVCoordinates;
  30. import org.orekit.utils.TimeStampedPVCoordinates;

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

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

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

  58.     /** Simple constructor.
  59.      * @param emitter emitter ground station
  60.      * @param receiver receiver ground station
  61.      * @param date date of the measurement
  62.      * @param rangeRate observed value, m/s
  63.      * @param sigma theoretical standard deviation
  64.      * @param baseWeight base weight
  65.      * @param satellite satellite related to this measurement
  66.      */
  67.     public BistaticRangeRate(final GroundStation emitter, final GroundStation receiver,
  68.                              final AbsoluteDate date, final double rangeRate, final double sigma,
  69.                              final double baseWeight, final ObservableSatellite satellite) {
  70.         super(receiver, true, date, rangeRate, sigma, baseWeight, satellite);

  71.         // add parameter drivers for the emitter, clock offset is not used
  72.         addParameterDriver(emitter.getEastOffsetDriver());
  73.         addParameterDriver(emitter.getNorthOffsetDriver());
  74.         addParameterDriver(emitter.getZenithOffsetDriver());
  75.         addParameterDriver(emitter.getPrimeMeridianOffsetDriver());
  76.         addParameterDriver(emitter.getPrimeMeridianDriftDriver());
  77.         addParameterDriver(emitter.getPolarOffsetXDriver());
  78.         addParameterDriver(emitter.getPolarDriftXDriver());
  79.         addParameterDriver(emitter.getPolarOffsetYDriver());
  80.         addParameterDriver(emitter.getPolarDriftYDriver());

  81.         this.emitter  = emitter;

  82.     }

  83.     /** Get the emitter ground station.
  84.      * @return emitter ground station
  85.      */
  86.     public GroundStation getEmitterStation() {
  87.         return emitter;
  88.     }

  89.     /** Get the receiver ground station.
  90.      * @return receiver ground station
  91.      */
  92.     public GroundStation getReceiverStation() {
  93.         return getStation();
  94.     }

  95.     /** {@inheritDoc} */
  96.     @Override
  97.     protected EstimatedMeasurementBase<BistaticRangeRate> theoreticalEvaluationWithoutDerivatives(final int iteration,
  98.                                                                                                   final int evaluation,
  99.                                                                                                   final SpacecraftState[] states) {
  100.         final GroundReceiverCommonParametersWithoutDerivatives common = computeCommonParametersWithout(states[0]);
  101.         final TimeStampedPVCoordinates transitPV = common.getTransitPV();
  102.         final AbsoluteDate transitDate = transitPV.getDate();

  103.         // Approximate emitter location at transit time
  104.         final Transform emitterToInertial =
  105.                 getEmitterStation().getOffsetToInertial(common.getState().getFrame(), transitDate, true);
  106.         final TimeStampedPVCoordinates emitterApprox =
  107.                 emitterToInertial.transformPVCoordinates(new TimeStampedPVCoordinates(transitDate,
  108.                         Vector3D.ZERO, Vector3D.ZERO, Vector3D.ZERO));

  109.         // Uplink time of flight from emitter station to transit state
  110.         final double tauU = signalTimeOfFlightAdjustableEmitter(emitterApprox, transitPV.getPosition(), transitDate,
  111.                                                                 common.getState().getFrame());

  112.         // Secondary station PV in inertial frame at rebound date on secondary station
  113.         final TimeStampedPVCoordinates emitterPV = emitterApprox.shiftedBy(-tauU);

  114.         // Prepare the evaluation
  115.         final EstimatedMeasurementBase<BistaticRangeRate> estimated =
  116.                 new EstimatedMeasurementBase<>(this,
  117.                         iteration, evaluation,
  118.                         new SpacecraftState[] {
  119.                             common.getTransitState()
  120.                         },
  121.                         new TimeStampedPVCoordinates[] {
  122.                             common.getStationDownlink(),
  123.                             transitPV,
  124.                             emitterPV
  125.                         });

  126.         // Range-rate components
  127.         final Vector3D receiverDirection = common.getStationDownlink().getPosition()
  128.                 .subtract(transitPV.getPosition()).normalize();
  129.         final Vector3D emitterDirection = emitterPV.getPosition()
  130.                 .subtract(transitPV.getPosition()).normalize();

  131.         final Vector3D receiverVelocity = common.getStationDownlink().getVelocity()
  132.                 .subtract(transitPV.getVelocity());
  133.         final Vector3D emitterVelocity = emitterPV.getVelocity()
  134.                 .subtract(transitPV.getVelocity());

  135.         // range rate
  136.         final double rangeRate = Vector3D.dotProduct(receiverDirection, receiverVelocity) +
  137.                  Vector3D.dotProduct(emitterDirection, emitterVelocity);
  138.         estimated.setEstimatedValue(rangeRate);

  139.         return estimated;

  140.     }

  141.     /** {@inheritDoc} */
  142.     @Override
  143.     protected EstimatedMeasurement<BistaticRangeRate> theoreticalEvaluation(final int iteration,
  144.                                                                             final int evaluation,
  145.                                                                             final SpacecraftState[] states) {

  146.         final SpacecraftState state = states[0];

  147.         // Bistatic range-rate derivatives are computed with respect to spacecraft state in inertial frame
  148.         // and station parameters
  149.         // ----------------------
  150.         //
  151.         // Parameters:
  152.         //  - 0..2 - Position of the spacecraft in inertial frame
  153.         //  - 3..5 - Velocity of the spacecraft in inertial frame
  154.         //  - 6..n - measurements parameters (clock offset, station offsets, pole, prime meridian, sat clock offset...)
  155.         final GroundReceiverCommonParametersWithDerivatives common = computeCommonParametersWithDerivatives(state);
  156.         final int nbParams = common.getTauD().getFreeParameters();
  157.         final TimeStampedFieldPVCoordinates<Gradient> transitPV = common.getTransitPV();
  158.         final FieldAbsoluteDate<Gradient> transitDate = transitPV.getDate();

  159.         // Approximate emitter location (at transit time)
  160.         final FieldVector3D<Gradient> zero = FieldVector3D.getZero(common.getTauD().getField());
  161.         final FieldTransform<Gradient> emitterToInertial =
  162.                 getEmitterStation().getOffsetToInertial(state.getFrame(), transitDate, nbParams, common.getIndices());
  163.         final TimeStampedFieldPVCoordinates<Gradient> emitterApprox =
  164.                 emitterToInertial.transformPVCoordinates(new TimeStampedFieldPVCoordinates<>(transitDate,
  165.                         zero, zero, zero));

  166.         // Uplink time of flight from emiiter to transit state
  167.         final Gradient tauU = signalTimeOfFlightAdjustableEmitter(emitterApprox, transitPV.getPosition(), transitPV.getDate(),
  168.                                                                   state.getFrame());

  169.         // Emitter coordinates at transmit time
  170.         final TimeStampedFieldPVCoordinates<Gradient> emitterPV = emitterApprox.shiftedBy(tauU.negate());

  171.         // Prepare the evaluation
  172.         final EstimatedMeasurement<BistaticRangeRate> estimated = new EstimatedMeasurement<>(this,
  173.                 iteration, evaluation,
  174.                 new SpacecraftState[] {
  175.                         common.getTransitState()
  176.                 },
  177.                 new TimeStampedPVCoordinates[] {
  178.                         common.getStationDownlink().toTimeStampedPVCoordinates(),
  179.                         common.getTransitPV().toTimeStampedPVCoordinates(),
  180.                         emitterPV.toTimeStampedPVCoordinates()
  181.                 });

  182.         // Range-rate components
  183.         final FieldVector3D<Gradient> receiverDirection = common.getStationDownlink().getPosition()
  184.                 .subtract(transitPV.getPosition()).normalize();
  185.         final FieldVector3D<Gradient> emitterDirection = emitterPV.getPosition()
  186.                 .subtract(transitPV.getPosition()).normalize();

  187.         final FieldVector3D<Gradient> receiverVelocity = common.getStationDownlink().getVelocity()
  188.                 .subtract(transitPV.getVelocity());
  189.         final FieldVector3D<Gradient> emitterVelocity = emitterPV.getVelocity()
  190.                 .subtract(transitPV.getVelocity());

  191.         // range rate
  192.         final Gradient rangeRate = FieldVector3D.dotProduct(receiverDirection, receiverVelocity)
  193.                 .add(FieldVector3D.dotProduct(emitterDirection, emitterVelocity));
  194.         estimated.setEstimatedValue(rangeRate.getValue());

  195.         // Range first order derivatives with respect to state
  196.         final double[] derivatives = rangeRate.getGradient();
  197.         estimated.setStateDerivatives(0, Arrays.copyOfRange(derivatives, 0, 6));

  198.         // Set first order derivatives with respect to parameters
  199.         for (final ParameterDriver driver : getParametersDrivers()) {
  200.             for (Span<String> span = driver.getNamesSpanMap().getFirstSpan(); span != null; span = span.next()) {
  201.                 final Integer index = common.getIndices().get(span.getData());
  202.                 if (index != null) {
  203.                     estimated.setParameterDerivatives(driver, span.getStart(), derivatives[index]);
  204.                 }
  205.             }
  206.         }

  207.         return estimated;

  208.     }

  209. }