DOPComputer.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.gnss;

  18. import java.util.List;

  19. import org.hipparchus.geometry.euclidean.threed.Vector3D;
  20. import org.hipparchus.linear.MatrixUtils;
  21. import org.hipparchus.linear.RealMatrix;
  22. import org.hipparchus.util.FastMath;
  23. import org.orekit.bodies.GeodeticPoint;
  24. import org.orekit.bodies.OneAxisEllipsoid;
  25. import org.orekit.errors.OrekitException;
  26. import org.orekit.errors.OrekitMessages;
  27. import org.orekit.frames.TopocentricFrame;
  28. import org.orekit.propagation.Propagator;
  29. import org.orekit.time.AbsoluteDate;
  30. import org.orekit.utils.ElevationMask;
  31. import org.orekit.utils.TrackingCoordinates;

  32. /**
  33.  * This class aims at computing the dilution of precision.
  34.  *
  35.  * @author Pascal Parraud
  36.  * @since 8.0
  37.  * @see <a href="http://en.wikipedia.org/wiki/Dilution_of_precision_%28GPS%29">Dilution of precision</a>
  38.  */
  39. public class DOPComputer {

  40.     // Constants
  41.     /** Minimum elevation : 0°. */
  42.     public static final double DOP_MIN_ELEVATION = 0.;

  43.     /** Minimum number of propagators for DOP computation. */
  44.     private static final int DOP_MIN_PROPAGATORS = 4;

  45.     // Fields
  46.     /** The location as a topocentric frame. */
  47.     private final TopocentricFrame frame;

  48.     /** Elevation mask used for computation, if defined. */
  49.     private final ElevationMask elevationMask;

  50.     /** Minimum elevation value used if no mask is defined. */
  51.     private final double minElevation;

  52.     /**
  53.      * Constructor for DOP computation.
  54.      *
  55.      * @param frame the topocentric frame linked to the locations where DOP will be computed
  56.      * @param minElev the minimum elevation to consider (rad)
  57.      * @param elevMask the elevation mask to consider
  58.      */
  59.     private DOPComputer(final TopocentricFrame frame, final double minElev, final ElevationMask elevMask) {
  60.         // Set the topocentric frame
  61.         this.frame = frame;
  62.         // Set the min elevation
  63.         this.minElevation = minElev;
  64.         // Set the elevation mask
  65.         this.elevationMask = elevMask;
  66.     }

  67.     /**
  68.      * Creates a DOP computer for one location.
  69.      *
  70.      * <p>A minimum elevation of 0° is taken into account to compute
  71.      * visibility between the location and the GNSS spacecrafts.</p>
  72.      *
  73.      * @param shape the body shape on which the location is defined
  74.      * @param location the point of interest
  75.      * @return a configured DOP computer
  76.      */
  77.     public static DOPComputer create(final OneAxisEllipsoid shape, final GeodeticPoint location) {
  78.         return new DOPComputer(new TopocentricFrame(shape, location, "Location"), DOP_MIN_ELEVATION, null);
  79.     }

  80.     /**
  81.      * Set the minimum elevation.
  82.      *
  83.      * <p>This will override an elevation mask if it has been configured as such previously.</p>
  84.      *
  85.      * @param newMinElevation minimum elevation for visibility (rad)
  86.      * @return a new DOP computer with updated configuration (the instance is not changed)
  87.      *
  88.      * @see #getMinElevation()
  89.      */
  90.     public DOPComputer withMinElevation(final double newMinElevation) {
  91.         return new DOPComputer(frame, newMinElevation, null);
  92.     }

  93.     /**
  94.      * Set the elevation mask.
  95.      *
  96.      * <p>This will override the min elevation if it has been configured as such previously.</p>
  97.      *
  98.      * @param newElevationMask elevation mask to use for the computation
  99.      * @return a new detector with updated configuration (the instance is not changed)
  100.      *
  101.      * @see #getElevationMask()
  102.      */
  103.     public DOPComputer withElevationMask(final ElevationMask newElevationMask) {
  104.         return new DOPComputer(frame, DOP_MIN_ELEVATION, newElevationMask);
  105.     }

  106.     /**
  107.      * Compute the {@link DOP} at a given date for a set of GNSS spacecrafts.
  108.      * <p>Four GNSS spacecraft at least are needed to compute the DOP.
  109.      * If less than 4 propagators are provided, an exception will be thrown.
  110.      * If less than 4 spacecrafts are visible at the date, all DOP values will be
  111.      * set to {@link java.lang.Double#NaN NaN}.</p>
  112.      *
  113.      * @param date the computation date
  114.      * @param gnss the propagators for GNSS spacecraft involved in the DOP computation
  115.      * @return the {@link DOP} at the location
  116.      */
  117.     public DOP compute(final AbsoluteDate date, final List<Propagator> gnss) {

  118.         // Checks the number of provided propagators
  119.         if (gnss.size() < DOP_MIN_PROPAGATORS) {
  120.             throw new OrekitException(OrekitMessages.NOT_ENOUGH_GNSS_FOR_DOP, gnss.size(), DOP_MIN_PROPAGATORS);
  121.         }

  122.         // Initializes DOP values
  123.         double gdop = Double.NaN;
  124.         double pdop = Double.NaN;
  125.         double hdop = Double.NaN;
  126.         double vdop = Double.NaN;
  127.         double tdop = Double.NaN;

  128.         // Loop over the propagators of GNSS orbits
  129.         final double[][] satDir = new double[gnss.size()][4];
  130.         int satNb = 0;
  131.         for (Propagator prop : gnss) {
  132.             final Vector3D            pos   = prop.getPosition(date, frame);
  133.             final TrackingCoordinates tc    = frame.getTrackingCoordinates(pos, frame, date);
  134.             final double              elMin = (elevationMask != null) ?
  135.                                               elevationMask.getElevation(tc.getAzimuth()) :
  136.                                                   minElevation;
  137.             // Only visible satellites are considered
  138.             if (tc.getElevation() > elMin) {
  139.                 // Create the rows of the H matrix
  140.                 final Vector3D r = pos.normalize();
  141.                 satDir[satNb][0] = r.getX();
  142.                 satDir[satNb][1] = r.getY();
  143.                 satDir[satNb][2] = r.getZ();
  144.                 satDir[satNb][3] = -1.;
  145.                 satNb++;
  146.             }
  147.         }

  148.         // DOP values are computed only if at least 4 SV are visible from the location
  149.         if (satNb > 3) {
  150.             // Construct matrix H
  151.             final RealMatrix h = MatrixUtils.createRealMatrix(satNb, 4);
  152.             for (int k = 0; k < satNb; k++) {
  153.                 h.setRow(k, satDir[k]);
  154.             }

  155.             // Compute the pseudo-inverse of H
  156.             final RealMatrix hInv = MatrixUtils.inverse(h.transpose().multiply(h));
  157.             final double sx2 = hInv.getEntry(0, 0);
  158.             final double sy2 = hInv.getEntry(1, 1);
  159.             final double sz2 = hInv.getEntry(2, 2);
  160.             final double st2 = hInv.getEntry(3, 3);

  161.             // Extract various DOP : GDOP, PDOP, HDOP, VDOP, TDOP
  162.             gdop = FastMath.sqrt(hInv.getTrace());
  163.             pdop = FastMath.sqrt(sx2 + sy2 + sz2);
  164.             hdop = FastMath.sqrt(sx2 + sy2);
  165.             vdop = FastMath.sqrt(sz2);
  166.             tdop = FastMath.sqrt(st2);
  167.         }

  168.         // Return all the DOP values
  169.         return new DOP(frame.getPoint(), date, satNb, gdop, pdop, hdop, vdop, tdop);
  170.     }

  171.     /**
  172.      * Get the minimum elevation.
  173.      *
  174.      * @return the minimum elevation (rad)
  175.      */
  176.     public double getMinElevation() {
  177.         return minElevation;
  178.     }

  179.     /**
  180.      * Get the elevation mask.
  181.      *
  182.      * @return the elevation mask
  183.      */
  184.     public ElevationMask getElevationMask() {
  185.         return elevationMask;
  186.     }
  187. }