1   /* Copyright 2002-2021 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  
19  import java.util.Collections;
20  
21  import org.hipparchus.exception.LocalizedCoreFormats;
22  import org.hipparchus.geometry.euclidean.threed.Vector3D;
23  import org.hipparchus.util.FastMath;
24  import org.orekit.errors.OrekitException;
25  import org.orekit.propagation.SpacecraftState;
26  import org.orekit.time.AbsoluteDate;
27  import org.orekit.utils.TimeStampedPVCoordinates;
28  
29  /** Class modeling a position-velocity measurement.
30   * <p>
31   * For position-only measurement see {@link Position}.
32   * </p>
33   * @see Position
34   * @author Luc Maisonobe
35   * @since 8.0
36   */
37  public class PV extends AbstractMeasurement<PV> {
38  
39      /** Identity matrix, for states derivatives. */
40      private static final double[][] IDENTITY = new double[][] {
41          {
42              1, 0, 0, 0, 0, 0
43          }, {
44              0, 1, 0, 0, 0, 0
45          }, {
46              0, 0, 1, 0, 0, 0
47          }, {
48              0, 0, 0, 1, 0, 0
49          }, {
50              0, 0, 0, 0, 1, 0
51          }, {
52              0, 0, 0, 0, 0, 1
53          }
54      };
55  
56      /** Covariance matrix of the PV measurement (size 6x6). */
57      private final double[][] covarianceMatrix;
58  
59      /** Constructor with two double for the standard deviations.
60       * <p>The first double is the position's standard deviation, common to the 3 position's components.
61       * The second double is the position's standard deviation, common to the 3 position's components.</p>
62       * <p>
63       * The measurement must be in the orbit propagation frame.
64       * </p>
65       * @param date date of the measurement
66       * @param position position
67       * @param velocity velocity
68       * @param sigmaPosition theoretical standard deviation on position components
69       * @param sigmaVelocity theoretical standard deviation on velocity components
70       * @param baseWeight base weight
71       * @param satellite satellite related to this measurement
72       * @since 9.3
73       */
74      public PV(final AbsoluteDate date, final Vector3D position, final Vector3D velocity,
75                final double sigmaPosition, final double sigmaVelocity, final double baseWeight,
76                final ObservableSatellite satellite) {
77          this(date, position, velocity,
78               new double[] {
79                   sigmaPosition,
80                   sigmaPosition,
81                   sigmaPosition,
82                   sigmaVelocity,
83                   sigmaVelocity,
84                   sigmaVelocity
85               }, baseWeight, satellite);
86      }
87  
88      /** Constructor with two vectors for the standard deviations.
89       * <p>One 3-sized vectors for position standard deviations.
90       * One 3-sized vectors for velocity standard deviations.
91       * The 3-sized vectors are the square root of the diagonal elements of the covariance matrix.</p>
92       * <p>The measurement must be in the orbit propagation frame.</p>
93       * @param date date of the measurement
94       * @param position position
95       * @param velocity velocity
96       * @param sigmaPosition 3-sized vector of the standard deviations of the position
97       * @param sigmaVelocity 3-sized vector of the standard deviations of the velocity
98       * @param baseWeight base weight
99       * @param satellite satellite related to this measurement
100      * @since 9.3
101      */
102     public PV(final AbsoluteDate date, final Vector3D position, final Vector3D velocity,
103               final double[] sigmaPosition, final double[] sigmaVelocity,
104               final double baseWeight, final ObservableSatellite satellite) {
105         this(date, position, velocity,
106              buildPvCovarianceMatrix(sigmaPosition, sigmaVelocity),
107              baseWeight, satellite);
108     }
109 
110     /** Constructor with one vector for the standard deviations.
111      * <p>The 6-sized vector is the square root of the diagonal elements of the covariance matrix.</p>
112      * <p>The measurement must be in the orbit propagation frame.</p>
113      * @param date date of the measurement
114      * @param position position
115      * @param velocity velocity
116      * @param sigmaPV 6-sized vector of the standard deviations
117      * @param baseWeight base weight
118      * @param satellite satellite related to this measurement
119      * @since 9.3
120      */
121     public PV(final AbsoluteDate date, final Vector3D position, final Vector3D velocity,
122               final double[] sigmaPV, final double baseWeight, final ObservableSatellite satellite) {
123         this(date, position, velocity, buildPvCovarianceMatrix(sigmaPV), baseWeight, satellite);
124     }
125 
126     /**
127      * Constructor with 2 smaller covariance matrices.
128      * <p>One 3x3 covariance matrix for position and one 3x3 covariance matrix for velocity.
129      * The fact that the covariance matrices are symmetric and positive definite is not checked.</p>
130      * <p>The measurement must be in the orbit propagation frame.</p>
131      * @param date date of the measurement
132      * @param position position
133      * @param velocity velocity
134      * @param positionCovarianceMatrix 3x3 covariance matrix of the position
135      * @param velocityCovarianceMatrix 3x3 covariance matrix of the velocity
136      * @param baseWeight base weight
137      * @param satellite satellite related to this measurement
138      * @since 9.3
139      */
140     public PV(final AbsoluteDate date, final Vector3D position, final Vector3D velocity,
141               final double[][] positionCovarianceMatrix, final double[][] velocityCovarianceMatrix,
142               final double baseWeight, final ObservableSatellite satellite) {
143         this(date, position, velocity,
144              buildPvCovarianceMatrix(positionCovarianceMatrix, velocityCovarianceMatrix),
145              baseWeight, satellite);
146     }
147 
148     /** Constructor with full covariance matrix and all inputs.
149      * <p>The fact that the covariance matrix is symmetric and positive definite is not checked.</p>
150      * <p>The measurement must be in the orbit propagation frame.</p>
151      * @param date date of the measurement
152      * @param position position
153      * @param velocity velocity
154      * @param covarianceMatrix 6x6 covariance matrix of the PV measurement
155      * @param baseWeight base weight
156      * @param satellite satellite related to this measurement
157      * @since 9.3
158      */
159     public PV(final AbsoluteDate date, final Vector3D position, final Vector3D velocity,
160               final double[][] covarianceMatrix, final double baseWeight, final ObservableSatellite satellite) {
161         super(date,
162               new double[] {
163                   position.getX(), position.getY(), position.getZ(),
164                   velocity.getX(), velocity.getY(), velocity.getZ()
165               }, extractSigmas(covarianceMatrix),
166               new double[] {
167                   baseWeight, baseWeight, baseWeight,
168                   baseWeight, baseWeight, baseWeight
169               }, Collections.singletonList(satellite));
170         this.covarianceMatrix = covarianceMatrix.clone();
171     }
172 
173     /** Get the position.
174      * @return position
175      */
176     public Vector3D getPosition() {
177         final double[] pv = getObservedValue();
178         return new Vector3D(pv[0], pv[1], pv[2]);
179     }
180 
181     /** Get the velocity.
182      * @return velocity
183      */
184     public Vector3D getVelocity() {
185         final double[] pv = getObservedValue();
186         return new Vector3D(pv[3], pv[4], pv[5]);
187     }
188 
189     /** Get the covariance matrix.
190      * @return the covariance matrix
191      */
192     public double[][] getCovarianceMatrix() {
193         return covarianceMatrix.clone();
194     }
195 
196     /** Get the correlation coefficients matrix.
197      * <p>This is the 6x6 matrix M such that:
198      * <p>Mij = Pij/(σi.σj)
199      * <p>Where:
200      * <ul>
201      * <li>P is the covariance matrix
202      * <li>σi is the i-th standard deviation (σi² = Pii)
203      * </ul>
204      * @return the correlation coefficient matrix (6x6)
205      */
206     public double[][] getCorrelationCoefficientsMatrix() {
207 
208         // Get the standard deviations
209         final double[] sigmas = getTheoreticalStandardDeviation();
210 
211         // Initialize the correlation coefficients matric to the covariance matrix
212         final double[][] corrCoefMatrix = new double[sigmas.length][sigmas.length];
213 
214         // Divide by the standard deviations
215         for (int i = 0; i < sigmas.length; i++) {
216             for (int j = 0; j < sigmas.length; j++) {
217                 corrCoefMatrix[i][j] = covarianceMatrix[i][j] / (sigmas[i] * sigmas[j]);
218             }
219         }
220         return corrCoefMatrix;
221     }
222 
223     /** {@inheritDoc} */
224     @Override
225     protected EstimatedMeasurement<PV> theoreticalEvaluation(final int iteration, final int evaluation,
226                                                              final SpacecraftState[] states) {
227 
228         // PV value
229         final TimeStampedPVCoordinates pv = states[0].getPVCoordinates();
230 
231         // prepare the evaluation
232         final EstimatedMeasurement<PV> estimated =
233                         new EstimatedMeasurement<>(this, iteration, evaluation, states,
234                                                    new TimeStampedPVCoordinates[] {
235                                                        pv
236                                                    });
237 
238         estimated.setEstimatedValue(new double[] {
239             pv.getPosition().getX(), pv.getPosition().getY(), pv.getPosition().getZ(),
240             pv.getVelocity().getX(), pv.getVelocity().getY(), pv.getVelocity().getZ()
241         });
242 
243         // partial derivatives with respect to state
244         estimated.setStateDerivatives(0, IDENTITY);
245 
246         return estimated;
247     }
248 
249     /** Extract standard deviations from a 6x6 PV covariance matrix.
250      * Check the size of the PV covariance matrix first.
251      * @param pvCovarianceMatrix the 6x6 PV covariance matrix
252      * @return the standard deviations (6-sized vector), they are
253      * the square roots of the diagonal elements of the covariance matrix in input.
254      */
255     private static double[] extractSigmas(final double[][] pvCovarianceMatrix) {
256 
257         // Check the size of the covariance matrix, should be 6x6
258         if (pvCovarianceMatrix.length != 6 || pvCovarianceMatrix[0].length != 6) {
259             throw new OrekitException(LocalizedCoreFormats.DIMENSIONS_MISMATCH_2x2,
260                                       pvCovarianceMatrix.length, pvCovarianceMatrix[0],
261                                       6, 6);
262         }
263 
264         // Extract the standard deviations (square roots of the diagonal elements)
265         final double[] sigmas = new double[6];
266         for (int i = 0; i < sigmas.length; i++) {
267             sigmas[i] = FastMath.sqrt(pvCovarianceMatrix[i][i]);
268         }
269         return sigmas;
270     }
271 
272     /** Build a 6x6 PV covariance matrix from two 3x3 matrices (covariances in position and velocity).
273      * Check the size of the matrices first.
274      * @param positionCovarianceMatrix the 3x3 covariance matrix in position
275      * @param velocityCovarianceMatrix the 3x3 covariance matrix in velocity
276      * @return the 6x6 PV covariance matrix
277      */
278     private static double[][] buildPvCovarianceMatrix(final double[][] positionCovarianceMatrix,
279                                                       final double[][] velocityCovarianceMatrix) {
280         // Check the sizes of the matrices first
281         if (positionCovarianceMatrix.length != 3 || positionCovarianceMatrix[0].length != 3) {
282             throw new OrekitException(LocalizedCoreFormats.DIMENSIONS_MISMATCH_2x2,
283                                       positionCovarianceMatrix.length, positionCovarianceMatrix[0],
284                                       3, 3);
285         }
286         if (velocityCovarianceMatrix.length != 3 || velocityCovarianceMatrix[0].length != 3) {
287             throw new OrekitException(LocalizedCoreFormats.DIMENSIONS_MISMATCH_2x2,
288                                       velocityCovarianceMatrix.length, velocityCovarianceMatrix[0],
289                                       3, 3);
290         }
291 
292         // Build the PV 6x6 covariance matrix
293         final double[][] pvCovarianceMatrix = new double[6][6];
294         for (int i = 0; i < 3; i++) {
295             for (int j = 0; j < 3; j++) {
296                 pvCovarianceMatrix[i][j]         = positionCovarianceMatrix[i][j];
297                 pvCovarianceMatrix[i + 3][j + 3] = velocityCovarianceMatrix[i][j];
298             }
299         }
300         return pvCovarianceMatrix;
301     }
302 
303     /** Build a 6x6 PV covariance matrix from a 6-sized vector (position and velocity standard deviations).
304      * Check the size of the vector first.
305      * @param sigmaPV 6-sized vector with position standard deviations on the first 3 elements
306      * and velocity standard deviations on the last 3 elements
307      * @return the 6x6 PV covariance matrix
308      */
309     private static double[][] buildPvCovarianceMatrix(final double[] sigmaPV) {
310         // Check the size of the vector first
311         if (sigmaPV.length != 6) {
312             throw new OrekitException(LocalizedCoreFormats.DIMENSIONS_MISMATCH, sigmaPV.length, 6);
313 
314         }
315 
316         // Build the PV 6x6 covariance matrix
317         final double[][] pvCovarianceMatrix = new double[6][6];
318         for (int i = 0; i < sigmaPV.length; i++) {
319             pvCovarianceMatrix[i][i] =  sigmaPV[i] * sigmaPV[i];
320         }
321         return pvCovarianceMatrix;
322     }
323 
324     /** Build a 6x6 PV covariance matrix from two 3-sized vectors (position and velocity standard deviations).
325      * Check the sizes of the vectors first.
326      * @param sigmaPosition standard deviations of the position (3-size vector)
327      * @param sigmaVelocity standard deviations of the velocity (3-size vector)
328      * @return the 6x6 PV covariance matrix
329      */
330     private static double[][] buildPvCovarianceMatrix(final double[] sigmaPosition,
331                                                       final double[] sigmaVelocity) {
332 
333         // Check the sizes of the vectors first
334         if (sigmaPosition.length != 3) {
335             throw new OrekitException(LocalizedCoreFormats.DIMENSIONS_MISMATCH, sigmaPosition.length, 3);
336 
337         }
338         if (sigmaVelocity.length != 3) {
339             throw new OrekitException(LocalizedCoreFormats.DIMENSIONS_MISMATCH, sigmaVelocity.length, 3);
340 
341         }
342 
343         // Build the PV 6x6 covariance matrix
344         final double[][] pvCovarianceMatrix = new double[6][6];
345         for (int i = 0; i < sigmaPosition.length; i++) {
346             pvCovarianceMatrix[i][i]         =  sigmaPosition[i] * sigmaPosition[i];
347             pvCovarianceMatrix[i + 3][i + 3] =  sigmaVelocity[i] * sigmaVelocity[i];
348         }
349         return pvCovarianceMatrix;
350     }
351 }