MultiplexedMeasurement.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.ArrayList;
  19. import java.util.Arrays;
  20. import java.util.IdentityHashMap;
  21. import java.util.List;
  22. import java.util.Map;
  23. import java.util.function.Function;

  24. import org.orekit.propagation.SpacecraftState;
  25. import org.orekit.time.AbsoluteDate;
  26. import org.orekit.utils.ParameterDriver;
  27. import org.orekit.utils.ParameterDriversList;
  28. import org.orekit.utils.TimeSpanMap;
  29. import org.orekit.utils.TimeStampedPVCoordinates;
  30. import org.orekit.utils.TimeSpanMap.Span;

  31. /** Class multiplexing several measurements as one.
  32.  * <p>
  33.  * Date comes from the first measurement, observed and estimated
  34.  * values result from gathering all underlying measurements values.
  35.  *
  36.  * @author Luc Maisonobe
  37.  * @since 10.1
  38.  */
  39. public class MultiplexedMeasurement extends AbstractMeasurement<MultiplexedMeasurement> {

  40.     /** Type of the measurement. */
  41.     public static final String MEASUREMENT_TYPE = "MultiplexedMeasurement";

  42.     /** Multiplexed measurements. */
  43.     private final List<ObservedMeasurement<?>> observedMeasurements;

  44.     /** Multiplexed measurements without derivatives.
  45.      */
  46.     private final List<EstimatedMeasurementBase<?>> estimatedMeasurementsWithoutDerivatives;

  47.     /** Multiplexed measurements. */
  48.     private final List<EstimatedMeasurement<?>> estimatedMeasurements;

  49.     /** Multiplexed parameters drivers. */
  50.     private final ParameterDriversList parametersDrivers;

  51.     /** Total dimension. */
  52.     private final int dimension;

  53.     /** Total number of satellites involved. */
  54.     private final int nbSat;

  55.     /** States mapping. */
  56.     private final int[][] multiplexedToUnderlying;

  57.     /** States mapping. */
  58.     private final int[][] underlyingToMultiplexed;

  59.     /** Simple constructor.
  60.      * @param measurements measurements to multiplex
  61.      * @since 10.1
  62.      */
  63.     public MultiplexedMeasurement(final List<ObservedMeasurement<?>> measurements) {
  64.         super(measurements.get(0).getDate(),
  65.               multiplex(measurements, ComparableMeasurement::getObservedValue),
  66.               multiplex(measurements, ObservedMeasurement::getTheoreticalStandardDeviation),
  67.               multiplex(measurements, ObservedMeasurement::getBaseWeight),
  68.               multiplex(measurements));

  69.         this.observedMeasurements                    = measurements;
  70.         this.estimatedMeasurementsWithoutDerivatives = new ArrayList<>();
  71.         this.estimatedMeasurements                   = new ArrayList<>();
  72.         this.parametersDrivers                       = new ParameterDriversList();

  73.         // gather parameters drivers
  74.         int dim = 0;
  75.         for (final ObservedMeasurement<?> m : measurements) {
  76.             for (final ParameterDriver driver : m.getParametersDrivers()) {
  77.                 parametersDrivers.add(driver);
  78.             }
  79.             dim += m.getDimension();
  80.         }
  81.         parametersDrivers.sort();
  82.         for (final ParameterDriver driver : parametersDrivers.getDrivers()) {
  83.             addParameterDriver(driver);
  84.         }
  85.         this.dimension = dim;

  86.         // set up states mappings for observed satellites
  87.         final List<ObservableSatellite> deduplicated = getSatellites();
  88.         this.nbSat   = deduplicated.size();
  89.         this.multiplexedToUnderlying = new int[measurements.size()][];
  90.         this.underlyingToMultiplexed = new int[measurements.size()][deduplicated.size()];
  91.         for (int i = 0; i < multiplexedToUnderlying.length; ++i) {
  92.             final List<ObservableSatellite> satellites = measurements.get(i).getSatellites();
  93.             multiplexedToUnderlying[i] = new int[satellites.size()];
  94.             for (int j = 0; j < multiplexedToUnderlying[i].length; ++j) {
  95.                 final int index = satellites.get(j).getPropagatorIndex();
  96.                 for (int k = 0; k < nbSat; ++k) {
  97.                     if (deduplicated.get(k).getPropagatorIndex() == index) {
  98.                         multiplexedToUnderlying[i][j] = k;
  99.                         underlyingToMultiplexed[i][k] = j;
  100.                         break;
  101.                     }
  102.                 }
  103.             }
  104.         }

  105.     }

  106.     /** Get the underlying measurements.
  107.      * @return underlying measurements
  108.      */
  109.     public List<ObservedMeasurement<?>> getMeasurements() {
  110.         return observedMeasurements;
  111.     }

  112.     /** Get the underlying estimated measurements without derivatives.
  113.      * @return underlying estimated measurements without derivatives
  114.      * @since 12.0
  115.      */
  116.     public List<EstimatedMeasurementBase<?>> getEstimatedMeasurementsWithoutDerivatives() {
  117.         return estimatedMeasurementsWithoutDerivatives;
  118.     }

  119.     /** Get the underlying estimated measurements.
  120.      * @return underlying estimated measurements
  121.      */
  122.     public List<EstimatedMeasurement<?>> getEstimatedMeasurements() {
  123.         return estimatedMeasurements;
  124.     }

  125.     /** Get the spacecraft state index in the underlying measurement.
  126.      * @param measurementIndex index of the underlying measurement
  127.      * @param multiplexedStateIndex index of the spacecraft state in the multiplexed array
  128.      * @return spacecraft state index in the underlying measurement
  129.      * @since 13.0
  130.      */
  131.     public int getUnderlyingStateIndex(final int measurementIndex, final int multiplexedStateIndex) {
  132.         return multiplexedToUnderlying[measurementIndex][multiplexedStateIndex];
  133.     }

  134.     /** Get the spacecraft state index in the multiplexed measurement.
  135.      * @param measurementIndex index of the underlying measurement
  136.      * @param underlyingStateIndex index of the spacecraft state in the underlying array
  137.      * @return spacecraft state index in the multiplexed measurement
  138.      * @since 13.0
  139.      */
  140.     public int getMultiplexedStateIndex(final int measurementIndex, final int underlyingStateIndex) {
  141.         return underlyingToMultiplexed[measurementIndex][underlyingStateIndex];
  142.     }

  143.     /** {@inheritDoc} */
  144.     @Override
  145.     protected EstimatedMeasurementBase<MultiplexedMeasurement> theoreticalEvaluationWithoutDerivatives(final int iteration,
  146.                                                                                                        final int evaluation,
  147.                                                                                                        final SpacecraftState[] states) {

  148.         final SpacecraftState[]              evaluationStates = new SpacecraftState[nbSat];
  149.         final double[]                       value            = new double[dimension];

  150.         // loop over all multiplexed measurements
  151.         estimatedMeasurementsWithoutDerivatives.clear();
  152.         int index = 0;
  153.         for (int i = 0; i < observedMeasurements.size(); ++i) {

  154.             // filter states involved in the current measurement
  155.             final SpacecraftState[] filteredStates = new SpacecraftState[multiplexedToUnderlying[i].length];
  156.             for (int j = 0; j < multiplexedToUnderlying[i].length; ++j) {
  157.                 filteredStates[j] = states[getUnderlyingStateIndex(i, j)];
  158.             }

  159.             // perform evaluation
  160.             final EstimatedMeasurementBase<?> eI = observedMeasurements.get(i).estimateWithoutDerivatives(iteration, evaluation, filteredStates);
  161.             estimatedMeasurementsWithoutDerivatives.add(eI);

  162.             // extract results
  163.             final double[] valueI = eI.getEstimatedValue();
  164.             System.arraycopy(valueI, 0, value, index, valueI.length);
  165.             index += valueI.length;

  166.             // extract states
  167.             final SpacecraftState[] statesI = eI.getStates();
  168.             for (int j = 0; j < multiplexedToUnderlying[i].length; ++j) {
  169.                 evaluationStates[multiplexedToUnderlying[i][j]] = statesI[j];
  170.             }

  171.         }

  172.         // create multiplexed estimation
  173.         final EstimatedMeasurementBase<MultiplexedMeasurement> multiplexed =
  174.                         new EstimatedMeasurementBase<>(this, iteration, evaluation,
  175.                                                        evaluationStates,
  176.                                                        new TimeStampedPVCoordinates[0]);

  177.         // copy multiplexed value
  178.         multiplexed.setEstimatedValue(value);

  179.         return multiplexed;

  180.     }

  181.     /** {@inheritDoc} */
  182.     @Override
  183.     protected EstimatedMeasurement<MultiplexedMeasurement> theoreticalEvaluation(final int iteration, final int evaluation,
  184.                                                                                  final SpacecraftState[] states) {

  185.         final SpacecraftState[]              evaluationStates = new SpacecraftState[nbSat];
  186.         final double[]                       value            = new double[dimension];

  187.         // loop over all multiplexed measurements
  188.         estimatedMeasurements.clear();
  189.         int index = 0;
  190.         for (int i = 0; i < observedMeasurements.size(); ++i) {

  191.             // filter states involved in the current measurement
  192.             final SpacecraftState[] filteredStates = new SpacecraftState[multiplexedToUnderlying[i].length];
  193.             for (int j = 0; j < multiplexedToUnderlying[i].length; ++j) {
  194.                 filteredStates[j] = states[multiplexedToUnderlying[i][j]];
  195.             }

  196.             // perform evaluation
  197.             final EstimatedMeasurement<?> eI = observedMeasurements.get(i).estimate(iteration, evaluation, filteredStates);
  198.             estimatedMeasurements.add(eI);

  199.             // extract results
  200.             final double[] valueI = eI.getEstimatedValue();
  201.             System.arraycopy(valueI, 0, value, index, valueI.length);
  202.             index += valueI.length;

  203.             // extract states
  204.             final SpacecraftState[] statesI = eI.getStates();
  205.             for (int j = 0; j < multiplexedToUnderlying[i].length; ++j) {
  206.                 evaluationStates[multiplexedToUnderlying[i][j]] = statesI[j];
  207.             }

  208.         }

  209.         // create multiplexed estimation
  210.         final EstimatedMeasurement<MultiplexedMeasurement> multiplexed =
  211.                         new EstimatedMeasurement<>(this, iteration, evaluation,
  212.                                                    evaluationStates,
  213.                                                    new TimeStampedPVCoordinates[0]);

  214.         // copy multiplexed value
  215.         multiplexed.setEstimatedValue(value);

  216.         // combine derivatives
  217.         final int                            stateSize             = estimatedMeasurements.get(0).getStateSize();
  218.         final double[]                       zeroDerivative        = new double[stateSize];
  219.         final double[][][]                   stateDerivatives      = new double[nbSat][dimension][];
  220.         for (final double[][] m : stateDerivatives) {
  221.             Arrays.fill(m, zeroDerivative);
  222.         }

  223.         final Map<ParameterDriver, TimeSpanMap<double[]>> parametersDerivatives = new IdentityHashMap<>();
  224.         index = 0;
  225.         for (int i = 0; i < observedMeasurements.size(); ++i) {

  226.             final EstimatedMeasurement<?> eI   = estimatedMeasurements.get(i);
  227.             final int                     idx  = index;
  228.             final int                     dimI = eI.getObservedMeasurement().getDimension();

  229.             // state derivatives
  230.             for (int j = 0; j < multiplexedToUnderlying[i].length; ++j) {
  231.                 System.arraycopy(eI.getStateDerivatives(j), 0,
  232.                                  stateDerivatives[multiplexedToUnderlying[i][j]], index,
  233.                                  dimI);
  234.             }

  235.             // parameters derivatives
  236.             eI.getDerivativesDrivers().forEach(driver -> {
  237.                 final ParameterDriversList.DelegatingDriver delegating = parametersDrivers.findByName(driver.getName());

  238.                 if (parametersDerivatives.get(delegating) == null) {
  239.                     final TimeSpanMap<double[]> derivativeSpanMap = new TimeSpanMap<>(new double[dimension]);
  240.                     parametersDerivatives.put(delegating, derivativeSpanMap);
  241.                 }

  242.                 final TimeSpanMap<Double> driverNameSpan = delegating.getValueSpanMap();
  243.                 for (Span<Double> span = driverNameSpan.getSpan(driverNameSpan.getFirstSpan().getEnd()); span != null; span = span.next()) {

  244.                     double[] derivatives = parametersDerivatives.get(delegating).get(span.getStart());
  245.                     if (derivatives == null) {
  246.                         derivatives = new double[dimension];
  247.                     }
  248.                     if (!parametersDerivatives.get(delegating).getSpan(span.getStart()).getStart().equals(span.getStart())) {
  249.                         if ((span.getStart()).equals(AbsoluteDate.PAST_INFINITY)) {
  250.                             parametersDerivatives.get(delegating).addValidBefore(derivatives, span.getEnd(), false);
  251.                         } else {
  252.                             parametersDerivatives.get(delegating).addValidAfter(derivatives, span.getStart(), false);
  253.                         }

  254.                     }

  255.                     System.arraycopy(eI.getParameterDerivatives(driver, span.getStart()), 0, derivatives, idx, dimI);

  256.                 }

  257.             });

  258.             index += dimI;

  259.         }

  260.         // set states derivatives
  261.         for (int i = 0; i < nbSat; ++i) {
  262.             multiplexed.setStateDerivatives(i, stateDerivatives[i]);
  263.         }

  264.         // set parameters derivatives
  265.         parametersDerivatives.
  266.             entrySet().
  267.             forEach(e -> multiplexed.setParameterDerivatives(e.getKey(), e.getValue()));

  268.         return multiplexed;

  269.     }

  270.     /** Multiplex measurements data.
  271.      * @param measurements measurements to multiplex
  272.      * @param extractor data extraction function
  273.      * @return multiplexed data
  274.      */
  275.     private static double[] multiplex(final List<ObservedMeasurement<?>> measurements,
  276.                                       final Function<ObservedMeasurement<?>, double[]> extractor) {

  277.         // gather individual parts
  278.         final List<double[]> parts = new ArrayList<> (measurements.size());
  279.         int n = 0;
  280.         for (final ObservedMeasurement<?> measurement : measurements) {
  281.             final double[] p = extractor.apply(measurement);
  282.             parts.add(p);
  283.             n += p.length;
  284.         }

  285.         // create multiplexed data
  286.         final double[] multiplexed = new double[n];
  287.         int index = 0;
  288.         for (final double[] p : parts) {
  289.             System.arraycopy(p, 0, multiplexed, index, p.length);
  290.             index += p.length;
  291.         }

  292.         return multiplexed;

  293.     }

  294.     /** Multiplex satellites data.
  295.      * @param measurements measurements to multiplex
  296.      * @return multiplexed satellites data
  297.      */
  298.     private static List<ObservableSatellite> multiplex(final List<ObservedMeasurement<?>> measurements) {

  299.         final List<ObservableSatellite> satellites = new ArrayList<>();

  300.         // gather all satellites, removing duplicates
  301.         for (final ObservedMeasurement<?> measurement : measurements) {
  302.             for (final ObservableSatellite satellite : measurement.getSatellites()) {
  303.                 boolean searching = true;
  304.                 for (int i = 0; i < satellites.size() && searching; ++i) {
  305.                     // check if we already know this satellite
  306.                     searching = satellite.getPropagatorIndex() != satellites.get(i).getPropagatorIndex();
  307.                 }
  308.                 if (searching) {
  309.                     // this is a new satellite, add it to the global list
  310.                     satellites.add(satellite);
  311.                 }
  312.             }
  313.         }

  314.         return satellites;

  315.     }

  316. }