AbstractOnBoardMeasurement.java

  1. /* Copyright 2022-2025 Luc Maisonobe
  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.gnss;

  18. import org.hipparchus.analysis.differentiation.Gradient;
  19. import org.hipparchus.analysis.differentiation.GradientField;
  20. import org.orekit.estimation.measurements.AbstractMeasurement;
  21. import org.orekit.estimation.measurements.ObservableSatellite;
  22. import org.orekit.estimation.measurements.ObservedMeasurement;
  23. import org.orekit.estimation.measurements.QuadraticClockModel;
  24. import org.orekit.estimation.measurements.QuadraticFieldClockModel;
  25. import org.orekit.frames.Frame;
  26. import org.orekit.propagation.SpacecraftState;
  27. import org.orekit.time.AbsoluteDate;
  28. import org.orekit.time.ClockOffset;
  29. import org.orekit.time.FieldAbsoluteDate;
  30. import org.orekit.time.FieldClockOffset;
  31. import org.orekit.utils.FieldPVCoordinatesProvider;
  32. import org.orekit.utils.PVCoordinatesProvider;
  33. import org.orekit.utils.ParameterDriver;
  34. import org.orekit.utils.TimeSpanMap.Span;
  35. import org.orekit.utils.TimeStampedFieldPVCoordinates;
  36. import org.orekit.utils.TimeStampedPVCoordinates;

  37. import java.util.HashMap;
  38. import java.util.List;
  39. import java.util.Map;

  40. /** Base class modeling a measurement where receiver is a satellite.
  41.  * @param <T> type of the measurement
  42.  * @author Luc Maisonobe
  43.  * @since 12.1
  44.  */
  45. public abstract class AbstractOnBoardMeasurement<T extends ObservedMeasurement<T>> extends AbstractMeasurement<T> {

  46.     /** Constructor.
  47.      * @param date date of the measurement
  48.      * @param observed observed value
  49.      * @param sigma theoretical standard deviation
  50.      * @param baseWeight base weight
  51.      * @param satellites satellites related to this measurement
  52.      */
  53.     public AbstractOnBoardMeasurement(final AbsoluteDate date, final double observed,
  54.                                       final double sigma, final double baseWeight,
  55.                                       final List<ObservableSatellite> satellites) {
  56.         // Call to super constructor
  57.         super(date, observed, sigma, baseWeight, satellites);

  58.         // Add parameter drivers
  59.         satellites.forEach(s -> {
  60.             addParameterDriver(s.getClockOffsetDriver());
  61.             addParameterDriver(s.getClockDriftDriver());
  62.             addParameterDriver(s.getClockAccelerationDriver());
  63.         });

  64.     }

  65.     /** Get emitting satellite clock provider.
  66.      * @return emitting satellite clock provider
  67.      */
  68.     protected abstract QuadraticClockModel getRemoteClock();

  69.     /** Get emitting satellite position/velocity provider.
  70.      * @param states states of all spacecraft involved in the measurement
  71.      * @return emitting satellite position/velocity provider
  72.      */
  73.     protected abstract PVCoordinatesProvider getRemotePV(SpacecraftState[] states);

  74.     /** Get emitting satellite position/velocity provider.
  75.      * @param states states of all spacecraft involved in the measurement
  76.      * @param freeParameters total number of free parameters in the gradient
  77.      * @return emitting satellite position/velocity provider
  78.      */
  79.     protected abstract FieldPVCoordinatesProvider<Gradient> getRemotePV(SpacecraftState[] states,
  80.                                                                         int freeParameters);

  81.     /** Get emitting satellite clock provider.
  82.      * @param freeParameters total number of free parameters in the gradient
  83.      * @param indices indices of the differentiation parameters in derivatives computations,
  84.      * must be span name and not driver name
  85.      * @return emitting satellite clock provider
  86.      */
  87.     protected QuadraticFieldClockModel<Gradient> getRemoteClock(final int freeParameters,
  88.                                                                 final Map<String, Integer> indices) {
  89.         return getRemoteClock().toGradientModel(freeParameters, indices, getDate());
  90.     }

  91.     /** Compute common estimation parameters.
  92.      * @param states states of all spacecraft involved in the measurement
  93.      * @param clockOffsetAlreadyApplied if true, the specified {@code date} is as read
  94.      * by the receiver clock (i.e. clock offset <em>not</em> compensated), if false,
  95.      * the specified {@code date} was already compensated and is a physical absolute date
  96.      * @return common parameters
  97.      */
  98.     protected OnBoardCommonParametersWithoutDerivatives computeCommonParametersWithout(final SpacecraftState[] states,
  99.                                                                                        final boolean clockOffsetAlreadyApplied) {

  100.         // local and remote satellites
  101.         final Frame                    frame            = states[0].getFrame();
  102.         final TimeStampedPVCoordinates pvaLocal         = states[0].getPVCoordinates(frame);
  103.         final ClockOffset              localClock       = getSatellites().
  104.                                                           get(0).
  105.                                                           getQuadraticClockModel().
  106.             getOffset(getDate());
  107.         final double                   localClockOffset = localClock.getOffset();
  108.         final double                   localClockRate   = localClock.getRate();
  109.         final PVCoordinatesProvider    remotePV         = getRemotePV(states);

  110.         // take clock offset into account
  111.         final AbsoluteDate arrivalDate = clockOffsetAlreadyApplied ? getDate() : getDate().shiftedBy(-localClockOffset);

  112.         // Downlink delay
  113.         final double deltaT = arrivalDate.durationFrom(states[0]);
  114.         final TimeStampedPVCoordinates pvaDownlink = pvaLocal.shiftedBy(deltaT);
  115.         final double tauD = signalTimeOfFlightAdjustableEmitter(remotePV, arrivalDate, pvaDownlink.getPosition(),
  116.                                                                 arrivalDate, frame);

  117.         // Remote satellite at signal emission
  118.         final AbsoluteDate        emissionDate      = arrivalDate.shiftedBy(-tauD);
  119.         final ClockOffset         remoteClock       = getRemoteClock().getOffset(emissionDate);
  120.         final double              remoteClockOffset = remoteClock.getOffset();
  121.         final double              remoteClockRate   = remoteClock.getRate();
  122.         return new OnBoardCommonParametersWithoutDerivatives(states[0],
  123.                                                              localClockOffset, localClockRate,
  124.                                                              remoteClockOffset, remoteClockRate,
  125.                                                              tauD, pvaDownlink,
  126.                                                              remotePV.getPVCoordinates(emissionDate, frame));

  127.     }

  128.     /** Compute common estimation parameters.
  129.      * @param states states of all spacecraft involved in the measurement
  130.      * @param clockOffsetAlreadyApplied if true, the specified {@code date} is as read
  131.      * by the receiver clock (i.e. clock offset <em>not</em> compensated), if false,
  132.      * the specified {@code date} was already compensated and is a physical absolute date
  133.      * @return common parameters
  134.      */
  135.     protected OnBoardCommonParametersWithDerivatives computeCommonParametersWith(final SpacecraftState[] states,
  136.                                                                                  final boolean clockOffsetAlreadyApplied) {

  137.         final Frame frame = states[0].getFrame();

  138.         // measurement derivatives are computed with respect to spacecraft state in inertial frame
  139.         // Parameters:
  140.         //  - 6k..6k+2 - Position of spacecraft k (counting k from 0 to nbSat-1) in inertial frame
  141.         //  - 6k+3..6k+5 - Velocity of spacecraft k (counting k from 0 to nbSat-1) in inertial frame
  142.         //  - 6nbSat..n - measurements parameters (clock offset, etc)
  143.         int nbEstimatedParams = 6 * states.length;
  144.         final Map<String, Integer> parameterIndices = new HashMap<>();
  145.         for (ParameterDriver measurementDriver : getParametersDrivers()) {
  146.             if (measurementDriver.isSelected()) {
  147.                 for (Span<String> span = measurementDriver.getNamesSpanMap().getFirstSpan(); span != null; span = span.next()) {
  148.                     parameterIndices.put(span.getData(), nbEstimatedParams++);
  149.                 }
  150.             }
  151.         }
  152.         final FieldAbsoluteDate<Gradient> gDate = new FieldAbsoluteDate<>(GradientField.getField(nbEstimatedParams),
  153.                                                                           getDate());

  154.         // local and remote satellites
  155.         final TimeStampedFieldPVCoordinates<Gradient> pvaLocal         = getCoordinates(states[0], 0, nbEstimatedParams);
  156.         final QuadraticFieldClockModel<Gradient>      localClock       = getSatellites().get(0).getQuadraticClockModel().
  157.                                                                          toGradientModel(nbEstimatedParams, parameterIndices, getDate());
  158.         final FieldClockOffset<Gradient>              localClockOffset = localClock.getOffset(gDate);
  159.         final FieldPVCoordinatesProvider<Gradient>    remotePV         = getRemotePV(states, nbEstimatedParams);

  160.         // take clock offset into account
  161.         final FieldAbsoluteDate<Gradient> arrivalDate = clockOffsetAlreadyApplied ?
  162.                                                         gDate : gDate.shiftedBy(localClockOffset.getOffset().negate());

  163.         // Downlink delay
  164.         final Gradient deltaT = arrivalDate.durationFrom(states[0].getDate());
  165.         final TimeStampedFieldPVCoordinates<Gradient> pvaDownlink = pvaLocal.shiftedBy(deltaT);
  166.         final Gradient tauD = signalTimeOfFlightAdjustableEmitter(remotePV, arrivalDate,
  167.                                                                   pvaDownlink.getPosition(), arrivalDate,
  168.                                                                   frame);

  169.         // Remote satellite at signal emission
  170.         final FieldAbsoluteDate<Gradient>        emissionDate      = arrivalDate.shiftedBy(tauD.negate());
  171.         final QuadraticFieldClockModel<Gradient> remoteClock       = getRemoteClock(nbEstimatedParams, parameterIndices);
  172.         final FieldClockOffset<Gradient>         remoteClockOffset = remoteClock.getOffset(emissionDate);
  173.         return new OnBoardCommonParametersWithDerivatives(states[0], parameterIndices,
  174.                                                           localClockOffset.getOffset(), localClockOffset.getRate(),
  175.                                                           remoteClockOffset.getOffset(), remoteClockOffset.getRate(),
  176.                                                           tauD, pvaDownlink,
  177.                                                           remotePV.getPVCoordinates(emissionDate, frame));

  178.     }

  179. }