MultiplexedMeasurement.java

  1. /* Copyright 2002-2024 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 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[][] mapping;

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

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

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

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

  101.     }

  102.     /** Get the underlying measurements.
  103.      * @return underlying measurements
  104.      */
  105.     public List<ObservedMeasurement<?>> getMeasurements() {
  106.         return observedMeasurements;
  107.     }

  108.     /** Get the underlying estimated measurements without derivatives.
  109.      * @return underlying estimated measurements without derivatives
  110.      * @since 12.0
  111.      */
  112.     public List<EstimatedMeasurementBase<?>> getEstimatedMeasurementsWithoutDerivatives() {
  113.         return estimatedMeasurementsWithoutDerivatives;
  114.     }

  115.     /** Get the underlying estimated measurements.
  116.      * @return underlying estimated measurements
  117.      */
  118.     public List<EstimatedMeasurement<?>> getEstimatedMeasurements() {
  119.         return estimatedMeasurements;
  120.     }

  121.     /** {@inheritDoc} */
  122.     @Override
  123.     protected EstimatedMeasurementBase<MultiplexedMeasurement> theoreticalEvaluationWithoutDerivatives(final int iteration,
  124.                                                                                                        final int evaluation,
  125.                                                                                                        final SpacecraftState[] states) {

  126.         final SpacecraftState[]              evaluationStates = new SpacecraftState[nbSat];
  127.         final List<TimeStampedPVCoordinates> participants     = new ArrayList<>();
  128.         final double[]                       value            = new double[dimension];

  129.         // loop over all multiplexed measurements
  130.         estimatedMeasurementsWithoutDerivatives.clear();
  131.         int index = 0;
  132.         for (int i = 0; i < observedMeasurements.size(); ++i) {

  133.             // filter states involved in the current measurement
  134.             final SpacecraftState[] filteredStates = new SpacecraftState[mapping[i].length];
  135.             for (int j = 0; j < mapping[i].length; ++j) {
  136.                 filteredStates[j] = states[mapping[i][j]];
  137.             }

  138.             // perform evaluation
  139.             final EstimatedMeasurementBase<?> eI = observedMeasurements.get(i).estimateWithoutDerivatives(iteration, evaluation, filteredStates);
  140.             estimatedMeasurementsWithoutDerivatives.add(eI);

  141.             // extract results
  142.             final double[] valueI = eI.getEstimatedValue();
  143.             System.arraycopy(valueI, 0, value, index, valueI.length);
  144.             index += valueI.length;

  145.             // extract states
  146.             final SpacecraftState[] statesI = eI.getStates();
  147.             for (int j = 0; j < mapping[i].length; ++j) {
  148.                 evaluationStates[mapping[i][j]] = statesI[j];
  149.             }

  150.         }

  151.         // create multiplexed estimation
  152.         final EstimatedMeasurementBase<MultiplexedMeasurement> multiplexed =
  153.                         new EstimatedMeasurementBase<>(this, iteration, evaluation,
  154.                                                        evaluationStates,
  155.                                                        participants.toArray(new TimeStampedPVCoordinates[0]));

  156.         // copy multiplexed value
  157.         multiplexed.setEstimatedValue(value);

  158.         return multiplexed;

  159.     }

  160.     /** {@inheritDoc} */
  161.     @Override
  162.     protected EstimatedMeasurement<MultiplexedMeasurement> theoreticalEvaluation(final int iteration, final int evaluation,
  163.                                                                                  final SpacecraftState[] states) {

  164.         final SpacecraftState[]              evaluationStates = new SpacecraftState[nbSat];
  165.         final List<TimeStampedPVCoordinates> participants     = new ArrayList<>();
  166.         final double[]                       value            = new double[dimension];

  167.         // loop over all multiplexed measurements
  168.         estimatedMeasurements.clear();
  169.         int index = 0;
  170.         for (int i = 0; i < observedMeasurements.size(); ++i) {

  171.             // filter states involved in the current measurement
  172.             final SpacecraftState[] filteredStates = new SpacecraftState[mapping[i].length];
  173.             for (int j = 0; j < mapping[i].length; ++j) {
  174.                 filteredStates[j] = states[mapping[i][j]];
  175.             }

  176.             // perform evaluation
  177.             final EstimatedMeasurement<?> eI = observedMeasurements.get(i).estimate(iteration, evaluation, filteredStates);
  178.             estimatedMeasurements.add(eI);

  179.             // extract results
  180.             final double[] valueI = eI.getEstimatedValue();
  181.             System.arraycopy(valueI, 0, value, index, valueI.length);
  182.             index += valueI.length;

  183.             // extract states
  184.             final SpacecraftState[] statesI = eI.getStates();
  185.             for (int j = 0; j < mapping[i].length; ++j) {
  186.                 evaluationStates[mapping[i][j]] = statesI[j];
  187.             }

  188.         }

  189.         // create multiplexed estimation
  190.         final EstimatedMeasurement<MultiplexedMeasurement> multiplexed =
  191.                         new EstimatedMeasurement<>(this, iteration, evaluation,
  192.                                                    evaluationStates,
  193.                                                    participants.toArray(new TimeStampedPVCoordinates[0]));

  194.         // copy multiplexed value
  195.         multiplexed.setEstimatedValue(value);

  196.         // combine derivatives
  197.         final int                            stateSize             = estimatedMeasurements.get(0).getStateSize();
  198.         final double[]                       zeroDerivative        = new double[stateSize];
  199.         final double[][][]                   stateDerivatives      = new double[nbSat][dimension][];
  200.         for (final double[][] m : stateDerivatives) {
  201.             Arrays.fill(m, zeroDerivative);
  202.         }

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

  206.             final EstimatedMeasurement<?> eI   = estimatedMeasurements.get(i);
  207.             final int                     idx  = index;
  208.             final int                     dimI = eI.getObservedMeasurement().getDimension();

  209.             // state derivatives
  210.             for (int j = 0; j < mapping[i].length; ++j) {
  211.                 System.arraycopy(eI.getStateDerivatives(j), 0,
  212.                                  stateDerivatives[mapping[i][j]], index,
  213.                                  dimI);
  214.             }

  215.             // parameters derivatives
  216.             eI.getDerivativesDrivers().forEach(driver -> {
  217.                 final ParameterDriversList.DelegatingDriver delegating = parametersDrivers.findByName(driver.getName());

  218.                 if (parametersDerivatives.get(delegating) == null) {
  219.                     final TimeSpanMap<double[]> derivativeSpanMap = new TimeSpanMap<double[]>(new double[dimension]);
  220.                     parametersDerivatives.put(delegating, derivativeSpanMap);
  221.                 }

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

  224.                     double[] derivatives = parametersDerivatives.get(delegating).get(span.getStart());
  225.                     if (derivatives == null) {
  226.                         derivatives = new double[dimension];
  227.                     }
  228.                     if (!parametersDerivatives.get(delegating).getSpan(span.getStart()).getStart().equals(span.getStart())) {
  229.                         if ((span.getStart()).equals(AbsoluteDate.PAST_INFINITY)) {
  230.                             parametersDerivatives.get(delegating).addValidBefore(derivatives, span.getEnd(), false);
  231.                         } else {
  232.                             parametersDerivatives.get(delegating).addValidAfter(derivatives, span.getStart(), false);
  233.                         }

  234.                     }

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

  236.                 }

  237.             });

  238.             index += dimI;

  239.         }

  240.         // set states derivatives
  241.         for (int i = 0; i < nbSat; ++i) {
  242.             multiplexed.setStateDerivatives(i, stateDerivatives[i]);
  243.         }

  244.         // set parameters derivatives
  245.         parametersDerivatives.
  246.             entrySet().
  247.             stream().
  248.             forEach(e -> multiplexed.setParameterDerivatives(e.getKey(), e.getValue()));

  249.         return multiplexed;

  250.     }

  251.     /** Multiplex measurements data.
  252.      * @param measurements measurements to multiplex
  253.      * @param extractor data extraction function
  254.      * @return multiplexed data
  255.      */
  256.     private static double[] multiplex(final List<ObservedMeasurement<?>> measurements,
  257.                                       final Function<ObservedMeasurement<?>, double[]> extractor) {

  258.         // gather individual parts
  259.         final List<double[]> parts = new ArrayList<> (measurements.size());
  260.         int n = 0;
  261.         for (final ObservedMeasurement<?> measurement : measurements) {
  262.             final double[] p = extractor.apply(measurement);
  263.             parts.add(p);
  264.             n += p.length;
  265.         }

  266.         // create multiplexed data
  267.         final double[] multiplexed = new double[n];
  268.         int index = 0;
  269.         for (final double[] p : parts) {
  270.             System.arraycopy(p, 0, multiplexed, index, p.length);
  271.             index += p.length;
  272.         }

  273.         return multiplexed;

  274.     }

  275.     /** Multiplex satellites data.
  276.      * @param measurements measurements to multiplex
  277.      * @return multiplexed satellites data
  278.      */
  279.     private static List<ObservableSatellite> multiplex(final List<ObservedMeasurement<?>> measurements) {

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

  281.         // gather all satellites, removing duplicates
  282.         for (final ObservedMeasurement<?> measurement : measurements) {
  283.             for (final ObservableSatellite satellite : measurement.getSatellites()) {
  284.                 boolean searching = true;
  285.                 for (int i = 0; i < satellites.size() && searching; ++i) {
  286.                     // check if we already know this satellite
  287.                     searching = satellite.getPropagatorIndex() != satellites.get(i).getPropagatorIndex();
  288.                 }
  289.                 if (searching) {
  290.                     // this is a new satellite, add it to the global list
  291.                     satellites.add(satellite);
  292.                 }
  293.             }
  294.         }

  295.         return satellites;

  296.     }

  297. }