BistaticRange.java

  1. /* Copyright 2002-2025 Mark Rutten
  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.  * Mark Rutten 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.Constants;
  28. import org.orekit.utils.ParameterDriver;
  29. import org.orekit.utils.TimeSpanMap.Span;
  30. import org.orekit.utils.TimeStampedFieldPVCoordinates;
  31. import org.orekit.utils.TimeStampedPVCoordinates;

  32. /**
  33.  * Class modeling a bistatic range measurement using
  34.  * an emitter ground station and a receiver ground station.
  35.  * <p>
  36.  * The measurement is considered to be a signal:
  37.  * <ul>
  38.  * <li>Emitted from the emitter ground station</li>
  39.  * <li>Reflected on the spacecraft</li>
  40.  * <li>Received on the receiver ground station</li>
  41.  * </ul>
  42.  * The date of the measurement corresponds to the reception on ground of the reflected signal.
  43.  * <p>
  44.  * The motion of the stations and the spacecraft during the signal flight time are taken into account.
  45.  * </p>
  46.  *
  47.  * @author Mark Rutten
  48.  * @since 11.2
  49.  */
  50. public class BistaticRange extends GroundReceiverMeasurement<BistaticRange> {

  51.     /** Type of the measurement. */
  52.     public static final String MEASUREMENT_TYPE = "BistaticRange";

  53.     /**
  54.      * Ground station from which transmission is made.
  55.      */
  56.     private final GroundStation emitter;

  57.     /**
  58.      * Simple constructor.
  59.      *
  60.      * @param emitter     ground station from which transmission is performed
  61.      * @param receiver    ground station from which measurement is performed
  62.      * @param date        date of the measurement
  63.      * @param range       observed value
  64.      * @param sigma       theoretical standard deviation
  65.      * @param baseWeight  base weight
  66.      * @param satellite   satellite related to this measurement
  67.      * @since 11.2
  68.      */
  69.     public BistaticRange(final GroundStation emitter, final GroundStation receiver, final AbsoluteDate date,
  70.                          final double range, final double sigma, final double baseWeight,
  71.                          final ObservableSatellite satellite) {
  72.         super(receiver, true, date, range, sigma, baseWeight, satellite);

  73.         addParameterDriver(emitter.getClockOffsetDriver());
  74.         addParameterDriver(emitter.getEastOffsetDriver());
  75.         addParameterDriver(emitter.getNorthOffsetDriver());
  76.         addParameterDriver(emitter.getZenithOffsetDriver());
  77.         addParameterDriver(emitter.getPrimeMeridianOffsetDriver());
  78.         addParameterDriver(emitter.getPrimeMeridianDriftDriver());
  79.         addParameterDriver(emitter.getPolarOffsetXDriver());
  80.         addParameterDriver(emitter.getPolarDriftXDriver());
  81.         addParameterDriver(emitter.getPolarOffsetYDriver());
  82.         addParameterDriver(emitter.getPolarDriftYDriver());

  83.         this.emitter = emitter;

  84.     }

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

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

  97.     /**
  98.      * {@inheritDoc}
  99.      */
  100.     @Override
  101.     protected EstimatedMeasurementBase<BistaticRange> theoreticalEvaluationWithoutDerivatives(final int iteration,
  102.                                                                                               final int evaluation,
  103.                                                                                               final SpacecraftState[] states) {

  104.         final GroundReceiverCommonParametersWithoutDerivatives common = computeCommonParametersWithout(states[0]);
  105.         final TimeStampedPVCoordinates transitPV = common.getTransitPV();
  106.         final AbsoluteDate transitDate = transitPV.getDate();

  107.         // Approximate emitter location at transit time
  108.         final Transform emitterToInertial =
  109.                 getEmitterStation().getOffsetToInertial(common.getState().getFrame(), transitDate, true);
  110.         final TimeStampedPVCoordinates emitterApprox =
  111.                 emitterToInertial.transformPVCoordinates(new TimeStampedPVCoordinates(transitDate,
  112.                                                                                       Vector3D.ZERO, Vector3D.ZERO, Vector3D.ZERO));

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

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

  118.         // Prepare the evaluation
  119.         final EstimatedMeasurementBase<BistaticRange> estimated =
  120.                         new EstimatedMeasurementBase<>(this,
  121.                                                        iteration, evaluation,
  122.                                                        new SpacecraftState[] {
  123.                                                            common.getTransitState()
  124.                                                        },
  125.                                                        new TimeStampedPVCoordinates[] {
  126.                                                            common.getStationDownlink(),
  127.                                                            transitPV,
  128.                                                            emitterPV
  129.                                                        });

  130.         // Clock offsets
  131.         final double dte = getEmitterStation().getClockOffsetDriver().getValue(common.getState().getDate());
  132.         final double dtr = getReceiverStation().getClockOffsetDriver().getValue(common.getState().getDate());

  133.         // Range value
  134.         final double tau = common.getTauD() + tauU + dtr - dte;
  135.         final double range = tau * Constants.SPEED_OF_LIGHT;

  136.         estimated.setEstimatedValue(range);

  137.         return estimated;
  138.     }

  139.     /**
  140.      * {@inheritDoc}
  141.      */
  142.     @Override
  143.     protected EstimatedMeasurement<BistaticRange> theoreticalEvaluation(final int iteration,
  144.                                                                         final int evaluation,
  145.                                                                         final SpacecraftState[] states) {
  146.         final SpacecraftState state = states[0];

  147.         // Bistatic range 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(),
  168.                                                                   transitPV.getDate(), state.getFrame());

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

  171.         // Prepare the evaluation
  172.         final EstimatedMeasurement<BistaticRange> 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.         // Clock offsets
  183.         final Gradient dte = getEmitterStation().getClockOffsetDriver().getValue(nbParams, common.getIndices(), state.getDate());
  184.         final Gradient dtr = getReceiverStation().getClockOffsetDriver().getValue(nbParams, common.getIndices(), state.getDate());

  185.         // Range value
  186.         final Gradient tau = common.getTauD().add(tauU).add(dtr).subtract(dte);
  187.         final Gradient range = tau.multiply(Constants.SPEED_OF_LIGHT);

  188.         estimated.setEstimatedValue(range.getValue());

  189.         // Range first order derivatives with respect to state
  190.         final double[] derivatives = range.getGradient();
  191.         estimated.setStateDerivatives(0, Arrays.copyOfRange(derivatives, 0, 6));

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

  201.         return estimated;
  202.     }

  203. }