Skip to content
Snippets Groups Projects
OrbitDetermination.java 129 KiB
Newer Older
noeljanes's avatar
noeljanes committed
/* Copyright 2002-2019 CS Systèmes d'Information
 * Licensed to CS Systèmes d'Information (CS) under one or more
 * contributor license agreements.  See the NOTICE file distributed with
 * this work for additional information regarding copyright ownership.
 * CS licenses this file to You under the Apache License, Version 2.0
 * (the "License"); you may not use this file except in compliance with
 * the License.  You may obtain a copy of the License at
 *
 *   http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package fr.cs.examples.estimation;

import java.io.BufferedReader;
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.PrintStream;
import java.io.UnsupportedEncodingException;
import java.net.URISyntaxException;
import java.text.ParseException;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;
import java.util.HashMap;
import java.util.List;
import java.util.Locale;
import java.util.Map;
import java.util.NoSuchElementException;
import java.util.SortedSet;
import java.util.TreeSet;
import java.util.regex.Pattern;

import org.hipparchus.exception.LocalizedCoreFormats;
import org.hipparchus.geometry.euclidean.threed.Vector3D;
import org.hipparchus.linear.QRDecomposer;
noeljanes's avatar
noeljanes committed
import org.hipparchus.linear.RealMatrix;
noeljanes's avatar
noeljanes committed
import org.hipparchus.optim.nonlinear.vector.leastsquares.GaussNewtonOptimizer;
import org.hipparchus.optim.nonlinear.vector.leastsquares.LeastSquaresOptimizer;
import org.hipparchus.optim.nonlinear.vector.leastsquares.LeastSquaresProblem;
import org.hipparchus.optim.nonlinear.vector.leastsquares.LevenbergMarquardtOptimizer;
import org.hipparchus.stat.descriptive.StreamingStatistics;
import org.hipparchus.util.FastMath;
import org.hipparchus.util.Precision;
import org.orekit.attitudes.AttitudeProvider;
import org.orekit.attitudes.BodyCenterPointing;
import org.orekit.attitudes.LofOffset;
import org.orekit.attitudes.NadirPointing;
import org.orekit.attitudes.YawCompensation;
import org.orekit.attitudes.YawSteering;
import org.orekit.bodies.CelestialBody;
import org.orekit.bodies.CelestialBodyFactory;
import org.orekit.bodies.GeodeticPoint;
import org.orekit.bodies.OneAxisEllipsoid;
import org.orekit.data.DataProvidersManager;
import org.orekit.data.DirectoryCrawler;
import org.orekit.errors.OrekitException;
import org.orekit.errors.OrekitMessages;
import org.orekit.estimation.leastsquares.BatchLSEstimator;
import org.orekit.estimation.leastsquares.BatchLSObserver;
import org.orekit.estimation.measurements.AngularAzEl;
import org.orekit.estimation.measurements.EstimatedMeasurement;
import org.orekit.estimation.measurements.EstimationsProvider;
import org.orekit.estimation.measurements.GroundStation;
import org.orekit.estimation.measurements.ObservableSatellite;
import org.orekit.estimation.measurements.ObservedMeasurement;
import org.orekit.estimation.measurements.PV;
import org.orekit.estimation.measurements.Range;
import org.orekit.estimation.measurements.RangeRate;
import org.orekit.estimation.measurements.modifiers.AngularRadioRefractionModifier;
import org.orekit.estimation.measurements.modifiers.Bias;
import org.orekit.estimation.measurements.modifiers.OnBoardAntennaRangeModifier;
import org.orekit.estimation.measurements.modifiers.OutlierFilter;
import org.orekit.estimation.measurements.modifiers.RangeRateTroposphericDelayModifier;
import org.orekit.estimation.measurements.modifiers.RangeTroposphericDelayModifier;
noeljanes's avatar
noeljanes committed
import org.orekit.forces.PolynomialParametricAcceleration;
import org.orekit.forces.drag.DragForce;
import org.orekit.forces.drag.DragSensitive;
import org.orekit.forces.drag.IsotropicDrag;
import org.orekit.forces.gravity.HolmesFeatherstoneAttractionModel;
import org.orekit.forces.gravity.OceanTides;
import org.orekit.forces.gravity.Relativity;
import org.orekit.forces.gravity.SolidTides;
import org.orekit.forces.gravity.ThirdBodyAttraction;
import org.orekit.forces.gravity.potential.GravityFieldFactory;
import org.orekit.forces.gravity.potential.NormalizedSphericalHarmonicsProvider;
import org.orekit.forces.radiation.IsotropicRadiationSingleCoefficient;
import org.orekit.forces.radiation.RadiationSensitive;
import org.orekit.forces.radiation.SolarRadiationPressure;
import org.orekit.frames.EOPHistory;
import org.orekit.frames.Frame;
import org.orekit.frames.FramesFactory;
import org.orekit.frames.LOFType;
import org.orekit.frames.TopocentricFrame;
import org.orekit.gnss.MeasurementType;
import org.orekit.gnss.ObservationData;
import org.orekit.gnss.ObservationDataSet;
import org.orekit.gnss.RinexLoader;
import org.orekit.gnss.SatelliteSystem;
import org.orekit.models.AtmosphericRefractionModel;
import org.orekit.models.earth.EarthITU453AtmosphereRefraction;
import org.orekit.models.earth.atmosphere.Atmosphere;
import org.orekit.models.earth.atmosphere.NRLMSISE00;
noeljanes's avatar
noeljanes committed
import org.orekit.models.earth.atmosphere.data.MarshallSolarActivityFutureEstimation;
import org.orekit.models.earth.displacement.OceanLoading;
import org.orekit.models.earth.displacement.OceanLoadingCoefficientsBLQFactory;
import org.orekit.models.earth.displacement.StationDisplacement;
import org.orekit.models.earth.displacement.TidalDisplacement;
import org.orekit.models.earth.troposphere.DiscreteTroposphericModel;
import org.orekit.models.earth.troposphere.EstimatedTroposphericModel;
import org.orekit.models.earth.troposphere.GlobalMappingFunctionModel;
import org.orekit.models.earth.troposphere.MappingFunction;
import org.orekit.models.earth.troposphere.NiellMappingFunctionModel;
import org.orekit.models.earth.troposphere.ViennaModelCoefficientsLoader;
import org.orekit.models.earth.troposphere.ViennaModelType;
import org.orekit.models.earth.troposphere.ViennaThreeModel;
noeljanes's avatar
noeljanes committed
import org.orekit.orbits.CartesianOrbit;
import org.orekit.orbits.CircularOrbit;
import org.orekit.orbits.EquinoctialOrbit;
import org.orekit.orbits.KeplerianOrbit;
import org.orekit.orbits.Orbit;
import org.orekit.orbits.PositionAngle;
import org.orekit.propagation.SpacecraftState;
import org.orekit.propagation.analytical.tle.TLE;
import org.orekit.propagation.analytical.tle.TLEPropagator;
import org.orekit.propagation.conversion.DormandPrince853IntegratorBuilder;
import org.orekit.propagation.conversion.NumericalPropagatorBuilder;
import org.orekit.time.AbsoluteDate;
import org.orekit.time.TimeScale;
noeljanes's avatar
noeljanes committed
import org.orekit.time.TimeScalesFactory;
import org.orekit.utils.Constants;
import org.orekit.utils.IERSConventions;
import org.orekit.utils.PVCoordinates;
import org.orekit.utils.ParameterDriver;
import org.orekit.utils.ParameterDriversList;

import fr.cs.examples.KeyValueFileParser;

/** Orekit tutorial for orbit determination.
 * @author Luc Maisonobe
 */
public class OrbitDetermination { // Class 1

    /** Program entry point.
     * @param args program arguments (unused here)
     */
    public static void main(String[] args) {
        try {

            // configure Orekit
            File home       = new File(System.getProperty("user.home"));
            File orekitData = new File(home, "orekit-data");
            if (!orekitData.exists()) {
                System.err.format(Locale.US, "Failed to find %s folder%n",
                                  orekitData.getAbsolutePath());
                System.err.format(Locale.US, "You need to download %s from %s, unzip it in %s and rename it 'orekit-data' for this tutorial to work%n",
                                  "orekit-data-master.zip", "https://gitlab.orekit.org/orekit/orekit-data/-/archive/master/orekit-data-master.zip",
                                  home.getAbsolutePath());
                System.exit(1);
            }

            // input in tutorial resources directory/output
            final String inputPath = OrbitDetermination.class.getClassLoader().getResource("maxvalier.in").toURI().getPath(); // Brings in input file with orbit data
noeljanes's avatar
noeljanes committed
            final File input  = new File(inputPath);

            DataProvidersManager manager = DataProvidersManager.getInstance();
            manager.addProvider(new DirectoryCrawler(orekitData));
            manager.addProvider(new DirectoryCrawler(new File(input.getParentFile(), "Vienna-Model")));

noeljanes's avatar
noeljanes committed
            long t0 = System.currentTimeMillis(); // Returns current time in milliseconds
            new OrbitDetermination().run(input, home);
            long t1 = System.currentTimeMillis();
            System.out.println("wall clock run time (s): " + (0.001 * (t1 - t0)));

        } catch (URISyntaxException urise) {
            System.err.println(urise.getLocalizedMessage());
            System.exit(1);
        } catch (IOException ioe) {
            System.err.println(ioe.getLocalizedMessage());
            System.exit(1);
        } catch (IllegalArgumentException iae) {
            iae.printStackTrace(System.err);
            System.err.println(iae.getLocalizedMessage());
            System.exit(1);
        } catch (OrekitException oe) {
            System.err.println(oe.getLocalizedMessage());
            System.exit(1);
        } catch (ParseException pe) {
            System.err.println(pe.getLocalizedMessage());
            System.exit(1);
        }
    }

    private void run(final File input, final File home)  // Starts an initial guess and then propagates that
        throws IOException, IllegalArgumentException, OrekitException, ParseException {

        // read input parameters
        KeyValueFileParser<ParameterKey> parser = new KeyValueFileParser<ParameterKey>(ParameterKey.class);
        try (final FileInputStream fis = new FileInputStream(input)) {
            parser.parseInput(input.getAbsolutePath(), fis);
        }

        // log file
        final String baseName;
        final PrintStream logStream;
        if (parser.containsKey(ParameterKey.OUTPUT_BASE_NAME) &&
            parser.getString(ParameterKey.OUTPUT_BASE_NAME).length() > 0) {
            baseName  = parser.getString(ParameterKey.OUTPUT_BASE_NAME);
            logStream = new PrintStream(new File(home, baseName + "-log.out"), "UTF-8");
        } else {
            baseName  = null;
            logStream = null;
        }

        final RangeLog     rangeLog     = new RangeLog(home, baseName);
        final RangeRateLog rangeRateLog = new RangeRateLog(home, baseName);
        final AzimuthLog   azimuthLog   = new AzimuthLog(home, baseName);
        final ElevationLog elevationLog = new ElevationLog(home, baseName);
        final PositionLog  positionLog  = new PositionLog(home, baseName);
        final VelocityLog  velocityLog  = new VelocityLog(home, baseName);

        try {
            // gravity field
            final NormalizedSphericalHarmonicsProvider gravityField = createGravityField(parser);

            // Orbit initial guess
            final Orbit initialGuess = createOrbit(parser, gravityField.getMu());

            // IERS conventions
            final IERSConventions conventions;
            if (!parser.containsKey(ParameterKey.IERS_CONVENTIONS)) {
                conventions = IERSConventions.IERS_2010;
            } else {
                conventions = IERSConventions.valueOf("IERS_" + parser.getInt(ParameterKey.IERS_CONVENTIONS));
            }

            // central body
            final OneAxisEllipsoid body = createBody(parser);

            // propagator builder
            final NumericalPropagatorBuilder propagatorBuilder =
                            createPropagatorBuilder(parser, conventions, gravityField, body, initialGuess);

            // estimator
            final BatchLSEstimator estimator = createEstimator(parser, propagatorBuilder);

            final Map<String, StationData>    stations                 = createStationsData(parser, conventions, body);
            final PVData                      pvData                   = createPVData(parser);
            final ObservableSatellite         satellite                = createObservableSatellite(parser);
            final Bias<Range>                 satRangeBias             = createSatRangeBias(parser);
            final OnBoardAntennaRangeModifier satAntennaRangeModifier  = createSatAntennaRangeModifier(parser);
            final Weights                     weights                  = createWeights(parser);
            final OutlierFilter<Range>        rangeOutliersManager     = createRangeOutliersManager(parser);
            final OutlierFilter<RangeRate>    rangeRateOutliersManager = createRangeRateOutliersManager(parser);
            final OutlierFilter<AngularAzEl>  azElOutliersManager      = createAzElOutliersManager(parser);
            final OutlierFilter<PV>           pvOutliersManager        = createPVOutliersManager(parser);

            // measurements
            final List<ObservedMeasurement<?>> measurements = new ArrayList<ObservedMeasurement<?>>();
            for (final String fileName : parser.getStringsList(ParameterKey.MEASUREMENTS_FILES, ',')) {
noeljanes's avatar
noeljanes committed
                System.out.println("The imported file is: " + fileName);
noeljanes's avatar
noeljanes committed
                if (Pattern.matches(RinexLoader.DEFAULT_RINEX_2_SUPPORTED_NAMES, fileName) ||
                    Pattern.matches(RinexLoader.DEFAULT_RINEX_3_SUPPORTED_NAMES, fileName)) {
                    // the measurements come from a Rinex file
                    measurements.addAll(readRinex(new File(input.getParentFile(), fileName),
                                                  parser.getString(ParameterKey.SATELLITE_ID_IN_RINEX_FILES),
                                                  stations, satellite, satRangeBias, satAntennaRangeModifier, weights,
                                                  rangeOutliersManager, rangeRateOutliersManager));
                } else {
                    // the measurements come from an Orekit custom file
                    measurements.addAll(readMeasurements(new File(input.getParentFile(), fileName),
                                                         stations, pvData, satellite,
                                                         satRangeBias, satAntennaRangeModifier, weights,
                                                         rangeOutliersManager,
                                                         rangeRateOutliersManager,
                                                         azElOutliersManager,
                                                         pvOutliersManager));
                }

            }
            for (ObservedMeasurement<?> measurement : measurements) {
                estimator.addMeasurement(measurement);
            }

            // estimate orbit
            estimator.setObserver(new BatchLSObserver() {

                private PVCoordinates previousPV;
                {
                    previousPV = initialGuess.getPVCoordinates();
noeljanes's avatar
noeljanes committed

                    if (!parser.getBoolean(ParameterKey.OD_LOG_EXTENDED)) {
                        final String header = "iteration evaluations      ΔP(m)        ΔV(m/s)           RMS          nb Range    nb Range-rate  nb Angular     nb PV%n";   // nb = number
                        System.out.format(Locale.US, header);
                        if (logStream != null) {
                            logStream.format(Locale.US, header);
                        }
                    }
noeljanes's avatar
noeljanes committed
                }

noeljanes's avatar
noeljanes committed
                /** {@inheritDoc} */
                @Override
                public void evaluationPerformed(final int iterationsCount, final int evaluationsCount,
                                               final Orbit[] orbits,
                                               final ParameterDriversList estimatedOrbitalParameters,
                                               final ParameterDriversList estimatedPropagatorParameters,
                                               final ParameterDriversList estimatedMeasurementsParameters,
                                               final EstimationsProvider  evaluationsProvider,
                                               final LeastSquaresProblem.Evaluation lspEvaluation) {
noeljanes's avatar
noeljanes committed
                    PVCoordinates currentPV = orbits[0].getPVCoordinates();
noeljanes's avatar
noeljanes committed
                    Double pos = Vector3D.distance(currentPV.getPosition(), Vector3D.ZERO);
                    pos = (pos - body.getEquatorialRadius())/1000;
                    String altitude = Double.toString(pos);

                    double pxg = -5253194;
                    double pyg = -4400295;
                    double pzg = 80075;
                    double vxg = -559;
                    double vyg = 764;
                    double vzg = 7585;

                    Vector3D genPosition = new Vector3D(pxg, pyg, pzg);
                    Vector3D genVelocity = new Vector3D(vxg, vyg,vzg) ;
                    Double positionSeperation = Vector3D.distance(genPosition, currentPV.getPosition());
                    Double velocitySeperation = Vector3D.distance(genVelocity, currentPV.getVelocity());



noeljanes's avatar
noeljanes committed
                    final EvaluationCounter<Range>     rangeCounter     = new EvaluationCounter<Range>();
                    final EvaluationCounter<RangeRate> rangeRateCounter = new EvaluationCounter<RangeRate>();
                    final EvaluationCounter<AngularAzEl>   angularCounter   = new EvaluationCounter<AngularAzEl>();
                    final EvaluationCounter<PV>        pvCounter        = new EvaluationCounter<PV>();
                    for (final Map.Entry<ObservedMeasurement<?>, EstimatedMeasurement<?>> entry : estimator.getLastEstimations().entrySet()) {
                        if (entry.getKey() instanceof Range) {
                            @SuppressWarnings("unchecked")
                            EstimatedMeasurement<Range> evaluation = (EstimatedMeasurement<Range>) entry.getValue();
                            rangeCounter.add(evaluation);
                        } else if (entry.getKey() instanceof RangeRate) {
                            @SuppressWarnings("unchecked")
                            EstimatedMeasurement<RangeRate> evaluation = (EstimatedMeasurement<RangeRate>) entry.getValue();
                            rangeRateCounter.add(evaluation);
                        } else if (entry.getKey() instanceof AngularAzEl) {
                            @SuppressWarnings("unchecked")
                            EstimatedMeasurement<AngularAzEl> evaluation = (EstimatedMeasurement<AngularAzEl>) entry.getValue();
                            angularCounter.add(evaluation);
                        } else if (entry.getKey() instanceof PV) {
                            @SuppressWarnings("unchecked")
                            EstimatedMeasurement<PV> evaluation = (EstimatedMeasurement<PV>) entry.getValue();
                            pvCounter.add(evaluation);
                        }
noeljanes's avatar
noeljanes committed
                    }
noeljanes's avatar
noeljanes committed

noeljanes's avatar
noeljanes committed
                    if (!parser.getBoolean(ParameterKey.OD_LOG_EXTENDED)) {
noeljanes's avatar
noeljanes committed

noeljanes's avatar
noeljanes committed
                        final String formatNormalLog0 = "    %2d         %2d                                 %16.12f     %s       %s     %s     %s%n";
noeljanes's avatar
noeljanes committed
                        final String formatNormalLog = "    %2d         %2d      %13.6f %12.9f %16.12f     %s       %s     %s     %s%n";
noeljanes's avatar
noeljanes committed
                        if (evaluationsCount == 1) {
                            System.out.format(Locale.US, formatNormalLog0,
                                              iterationsCount, evaluationsCount,
                                              lspEvaluation.getRMS(),
                                              rangeCounter.format(8), rangeRateCounter.format(8),
                                              angularCounter.format(8), pvCounter.format(8));
noeljanes's avatar
noeljanes committed
                            if (logStream != null) {
                                logStream.format(Locale.US, formatNormalLog0,
                                                 iterationsCount, evaluationsCount,
                                                 lspEvaluation.getRMS(),
                                                 rangeCounter.format(8), rangeRateCounter.format(8),
                                                 angularCounter.format(8), pvCounter.format(8));

                            }
                        } else {
                            System.out.format(Locale.US, formatNormalLog,
                                              iterationsCount, evaluationsCount,
                                              Vector3D.distance(previousPV.getPosition(), currentPV.getPosition()),
                                              Vector3D.distance(previousPV.getVelocity(), currentPV.getVelocity()),
                                              lspEvaluation.getRMS(),
                                              rangeCounter.format(8), rangeRateCounter.format(8),
                                              angularCounter.format(8), pvCounter.format(8));

                            if (logStream != null) {
                                logStream.format(Locale.US, formatNormalLog,
                                                 iterationsCount, evaluationsCount,
                                                 Vector3D.distance(previousPV.getPosition(), currentPV.getPosition()),
                                                 Vector3D.distance(previousPV.getVelocity(), currentPV.getVelocity()),
                                                 lspEvaluation.getRMS(),
                                                 rangeCounter.format(8), rangeRateCounter.format(8),
                                                 angularCounter.format(8), pvCounter.format(8));
                            }
noeljanes's avatar
noeljanes committed
                        }
noeljanes's avatar
noeljanes committed
                    else{
noeljanes's avatar
noeljanes committed
                        final String iterationNumber = "Iteration Number: ";
                        final String evaluationNumber = "Evaluations performed: ";
                        final String PVCoords = "The estimated Cartesian parameters: ";
                        final String cd = "Estimated propagator parameters changes: ";
                        final String Position = "Altitude (km):";
                        final String dP = "ΔP(m):";
                        final String dV = "ΔV(m/s):";
                        final String rms = "RMS:";
                        final String nbRr = "nb Range-rate:";
                        final String posSep = "Position separation (m)";
                        final String velSep = "Velocity separation (m/s)";
noeljanes's avatar
noeljanes committed
                        final String formatExtendedLog0 = "%s %2d,     %s %2d,  %s %s,   %s %16.12f,      %s %s %n %s %s %n %s %s,     %s %s%n" ;
noeljanes's avatar
noeljanes committed
                        final String formatExtendedLog = "%n%n%s %2d,     %s %2d,  %s %s,     %s %13.6f,   %s %12.9f,   %s %16.12f,      %s %s %n %s %s %n %s %s,    %s %s%n" ;
noeljanes's avatar
noeljanes committed

                        int length = 0;
                        for (final ParameterDriver parameterDriver : estimatedOrbitalParameters.getDrivers()) {
                            length = FastMath.max(length, parameterDriver.getName().length());
                        }
                        for (final ParameterDriver parameterDriver : estimatedPropagatorParameters.getDrivers()) {
                            length = FastMath.max(length, parameterDriver.getName().length());
                        }
                        for (final ParameterDriver parameterDriver : estimatedMeasurementsParameters.getDrivers()) {
                            length = FastMath.max(length, parameterDriver.getName().length());
                        }

                        if (evaluationsCount == 1) {

                            System.out.format(Locale.US, formatExtendedLog0, iterationNumber, iterationsCount,
                                    evaluationNumber, evaluationsCount, Position, altitude,
                                    rms, lspEvaluation.getRMS(), nbRr, rangeRateCounter.format(8),
                                    PVCoords, currentPV, posSep, positionSeperation, velSep, velocitySeperation);

                            displayParametersChanges(System.out, "Estimated orbital parameters changes: ",
noeljanes's avatar
noeljanes committed
                                    false, length, estimatedOrbitalParameters);

noeljanes's avatar
noeljanes committed
                            displayParametersChanges(System.out, "Estimated propagator parameters changes: ",
noeljanes's avatar
noeljanes committed
                                    true, length, estimatedPropagatorParameters);

noeljanes's avatar
noeljanes committed
                            displayParametersChanges(System.out, "Estimated measurements parameters changes: ",
noeljanes's avatar
noeljanes committed
                                    true, length, estimatedMeasurementsParameters);

noeljanes's avatar
noeljanes committed
                            if (logStream != null) {
                                logStream.format(Locale.US, formatExtendedLog0, iterationNumber, iterationsCount, evaluationNumber, evaluationsCount, Position, altitude,
                                        rms, lspEvaluation.getRMS(), nbRr, rangeRateCounter.format(8), PVCoords, currentPV, posSep, positionSeperation, velSep, velocitySeperation);
noeljanes's avatar
noeljanes committed
                                displayParametersChanges(logStream, "Estimated orbital parameters changes: ",
                                        false, length, estimatedOrbitalParameters);
noeljanes's avatar
noeljanes committed
                                displayParametersChanges(logStream, "Estimated propagator parameters changes: ",
                                        true, length, estimatedPropagatorParameters);
noeljanes's avatar
noeljanes committed
                                displayParametersChanges(logStream, "Estimated measurements parameters changes: ",
                                        true, length, estimatedMeasurementsParameters);
noeljanes's avatar
noeljanes committed
                            }
                        } else {
                            System.out.format(Locale.US, formatExtendedLog, iterationNumber, iterationsCount, evaluationNumber, evaluationsCount, Position, altitude,
noeljanes's avatar
noeljanes committed
                                    dP, Vector3D.distance(previousPV.getPosition(), currentPV.getPosition()),
                                    dV, Vector3D.distance(previousPV.getVelocity(), currentPV.getVelocity()),
                                    rms, lspEvaluation.getRMS(), nbRr, rangeRateCounter.format(8), PVCoords, currentPV, posSep, positionSeperation, velSep, velocitySeperation);
noeljanes's avatar
noeljanes committed
                            displayParametersChanges(System.out, "Estimated orbital parameters changes: ",
noeljanes's avatar
noeljanes committed
                                    false, length, estimatedOrbitalParameters);

noeljanes's avatar
noeljanes committed
                            displayParametersChanges(System.out, "Estimated propagator parameters changes: ",
noeljanes's avatar
noeljanes committed
                                    true, length, estimatedPropagatorParameters);

noeljanes's avatar
noeljanes committed
                            displayParametersChanges(System.out, "Estimated measurements parameters changes: ",
noeljanes's avatar
noeljanes committed
                                    true, length, estimatedMeasurementsParameters);
noeljanes's avatar
noeljanes committed


                            if (logStream != null) {
                                logStream.format(Locale.US, formatExtendedLog, iterationNumber, iterationsCount, evaluationNumber, evaluationsCount, Position, altitude,
                                        dP, Vector3D.distance(previousPV.getPosition(), currentPV.getPosition()),
                                        dV, Vector3D.distance(previousPV.getVelocity(), currentPV.getVelocity()),
                                        rms, lspEvaluation.getRMS(), nbRr, rangeRateCounter.format(8), PVCoords, currentPV, posSep, positionSeperation, velSep, velocitySeperation);

                                displayParametersChanges(logStream, "Estimated orbital parameters changes: ",
                                        false, length, estimatedOrbitalParameters);

                                displayParametersChanges(logStream, "Estimated propagator parameters changes: ",
                                        true, length, estimatedPropagatorParameters);

                                displayParametersChanges(logStream, "Estimated measurements parameters changes: ",
                                        true, length, estimatedMeasurementsParameters);
                            }
noeljanes's avatar
noeljanes committed
                        }
noeljanes's avatar
noeljanes committed
                    }
                    previousPV = currentPV;
                }
            });
            Orbit estimated = estimator.estimate()[0].getInitialState().getOrbit();

            // compute some statistics
            for (final Map.Entry<ObservedMeasurement<?>, EstimatedMeasurement<?>> entry : estimator.getLastEstimations().entrySet()) {
                if (entry.getKey() instanceof Range) {
                    @SuppressWarnings("unchecked")
                    EstimatedMeasurement<Range> evaluation = (EstimatedMeasurement<Range>) entry.getValue();
                    rangeLog.add(evaluation);
                } else if (entry.getKey() instanceof RangeRate) {
                    @SuppressWarnings("unchecked")
                    EstimatedMeasurement<RangeRate> evaluation = (EstimatedMeasurement<RangeRate>) entry.getValue();
                    rangeRateLog.add(evaluation);
                } else if (entry.getKey() instanceof AngularAzEl) {
                    @SuppressWarnings("unchecked")
                    EstimatedMeasurement<AngularAzEl> evaluation = (EstimatedMeasurement<AngularAzEl>) entry.getValue();
                    azimuthLog.add(evaluation);
                    elevationLog.add(evaluation);
                } else if (entry.getKey() instanceof PV) {
                    @SuppressWarnings("unchecked")
                    EstimatedMeasurement<PV> evaluation = (EstimatedMeasurement<PV>) entry.getValue();
                    positionLog.add(evaluation);
                    velocityLog.add(evaluation);
                }
            }


            int iDrag = 6 ;
            int iDopplerBias1 = 7 ;
            int iDopplerBias2 = 8 ;
noeljanes's avatar
noeljanes committed

            Double dragSD = 0.00;
            Double dopplerBiasSD1 = 0.00;
            Double dragDopplerBias1Correlation = 0.00;
noeljanes's avatar
noeljanes committed

            if (parser.getBoolean(ParameterKey.OD_LOG_COVARIANCES)) {

                final RealMatrix covariance = estimator.getPhysicalCovariances(1*Math.pow(10,-15));

                //System.out.println(covariance);
                //logStream.println(covariance);
                //System.out.println(covariance.getEntry(6,6));
                dragSD = FastMath.sqrt(covariance.getEntry(iDrag, iDrag));// This gives the standard deviation of the drag with the drag, the larger this is the more difficult the drag was to estimate
                dopplerBiasSD1 = FastMath.sqrt(covariance.getEntry(iDopplerBias1, iDopplerBias1)) ;
                dragDopplerBias1Correlation = covariance.getEntry(iDrag, iDopplerBias1)/(dopplerBiasSD1 * dragSD) ; // Range between -1 and +1, greater mag is more correlated and 0 isn't correlated
noeljanes's avatar
noeljanes committed
            System.out.println("Estimated orbit: " + estimated);
            if (logStream != null) {
                logStream.println("Estimated orbit: " + estimated);
            }

noeljanes's avatar
noeljanes committed
            final ParameterDriversList orbitalParameters      = estimator.getOrbitalParametersDrivers(true);
            final ParameterDriversList propagatorParameters   = estimator.getPropagatorParametersDrivers(true);
            final ParameterDriversList measurementsParameters = estimator.getMeasurementsParametersDrivers(true);
            int length = 0;
            for (final ParameterDriver parameterDriver : orbitalParameters.getDrivers()) {
                length = FastMath.max(length, parameterDriver.getName().length());
            }
            for (final ParameterDriver parameterDriver : propagatorParameters.getDrivers()) {
                length = FastMath.max(length, parameterDriver.getName().length());
            }
            for (final ParameterDriver parameterDriver : measurementsParameters.getDrivers()) {
                length = FastMath.max(length, parameterDriver.getName().length());
            }
            displayParametersChanges(System.out, "Estimated orbital parameters changes: ",
                                     false, length, orbitalParameters);
            if (logStream != null) {
                displayParametersChanges(logStream, "Estimated orbital parameters changes: ",
                                         false, length, orbitalParameters);
            }
            displayParametersChanges(System.out, "Estimated propagator parameters changes: ",
                                     true, length, propagatorParameters);
noeljanes's avatar
noeljanes committed

            if (parser.getBoolean(ParameterKey.OD_LOG_COVARIANCES)) {
                System.out.println("Standard deviation of the estimated drag: " + dragSD);
            }

noeljanes's avatar
noeljanes committed
            if (logStream != null) {
                displayParametersChanges(logStream, "Estimated propagator parameters changes: ",
                                         true, length, propagatorParameters);
            }
            displayParametersChanges(System.out, "Estimated measurements parameters changes: ",
                                     true, length, measurementsParameters);
noeljanes's avatar
noeljanes committed
            if (logStream != null) {
                displayParametersChanges(logStream, "Estimated measurements parameters changes: ",
noeljanes's avatar
noeljanes committed
                         true, length, measurementsParameters);
noeljanes's avatar
noeljanes committed
            }

            System.out.println("Number of iterations: " + estimator.getIterationsCount());
            System.out.println("Number of evaluations: " + estimator.getEvaluationsCount());
            rangeLog.displaySummary(System.out);
            rangeRateLog.displaySummary(System.out);
            azimuthLog.displaySummary(System.out);
            elevationLog.displaySummary(System.out);
            positionLog.displaySummary(System.out);
            velocityLog.displaySummary(System.out);
noeljanes's avatar
noeljanes committed

            if (parser.getBoolean(ParameterKey.OD_LOG_COVARIANCES)) {
                System.out.println("Standard deviation of the estimated drag: " + dragSD);
                System.out.println("Standard deviation of the range rate bias: " + dopplerBiasSD1);
                System.out.println("Correlation of drag and doppler bias: " + dragDopplerBias1Correlation);
noeljanes's avatar
noeljanes committed
            if (logStream != null) {
                logStream.println("Number of iterations: " + estimator.getIterationsCount());
                logStream.println("Number of evaluations: " + estimator.getEvaluationsCount());
                rangeLog.displaySummary(logStream);
                rangeRateLog.displaySummary(logStream);
                azimuthLog.displaySummary(logStream);
                elevationLog.displaySummary(logStream);
                positionLog.displaySummary(logStream);
                velocityLog.displaySummary(logStream);
noeljanes's avatar
noeljanes committed
                if (parser.getBoolean(ParameterKey.OD_LOG_COVARIANCES)) {
                    logStream.println("Standard deviation of the estimated drag: " + dragSD);
                    logStream.println("Standard deviation of the range rate bias: " + dopplerBiasSD1);
                    logStream.println("Correlation of drag and doppler bias: " + dragDopplerBias1Correlation);
noeljanes's avatar
noeljanes committed
            }

noeljanes's avatar
noeljanes committed

            final List orbitalParameters2 = estimator.getOrbitalParametersDrivers(true).getDrivers() ;
            final List propagatorParameters2 = estimator.getPropagatorParametersDrivers(true).getDrivers() ;
            final List measurementsParameters2 = estimator.getMeasurementsParametersDrivers(true).getDrivers();
            System.out.println(orbitalParameters2.toString()+"\n"+propagatorParameters2.toString()+"\n"+measurementsParameters2.toString());

noeljanes's avatar
noeljanes committed
            rangeLog.displayResiduals();
            rangeRateLog.displayResiduals();
            azimuthLog.displayResiduals();
            elevationLog.displayResiduals();
            positionLog.displayResiduals();
            velocityLog.displayResiduals();

        } finally {
            if (logStream != null) {
                logStream.close();
            }
            rangeLog.close();
            rangeRateLog.close();
            azimuthLog.close();
            elevationLog.close();
            positionLog.close();
            velocityLog.close();
        }

    }

    /** Display parameters changes.
     * @param stream output stream
     * @param header header message
     * @param sort if true, parameters will be sorted lexicographically
     * @param parameters parameters list
     */
    private void displayParametersChanges(final PrintStream out, final String header, final boolean sort,
                                          final int length, final ParameterDriversList parameters) {

        List<ParameterDriver> list = new ArrayList<ParameterDriver>(parameters.getDrivers());
        if (sort) {
            // sort the parameters lexicographically
            Collections.sort(list, new Comparator<ParameterDriver>() {
                /** {@inheritDoc} */
                @Override
                public int compare(final ParameterDriver pd1, final ParameterDriver pd2) {
                    return pd1.getName().compareTo(pd2.getName());
                }

            });
        }

        out.println(header);
        int index = 0;
        for (final ParameterDriver parameter : list) {
            if (parameter.isSelected()) {
                final double factor;
                if (parameter.getName().endsWith("/az bias") || parameter.getName().endsWith("/el bias")) {
                    factor = FastMath.toDegrees(1.0);
                } else {
                    factor = 1.0;
                }
                final double initial = parameter.getReferenceValue();
                final double value   = parameter.getValue();
                out.format(Locale.US, "  %2d %s", ++index, parameter.getName());
                for (int i = parameter.getName().length(); i < length; ++i) {
                    out.format(Locale.US, " ");
                }
                out.format(Locale.US, "  %+.12f  (final value:  % .12f)%n",
                           factor * (value - initial), factor * value);
            }
        }

    }

    /** Create a propagator builder from input parameters
     * @param parser input file parser
     * @param conventions IERS conventions to use
     * @param gravityField gravity field
     * @param body central body
     * @param orbit first orbit estimate
     * @return propagator builder
     * @throws NoSuchElementException if input parameters are missing
     */
    private NumericalPropagatorBuilder createPropagatorBuilder(final KeyValueFileParser<ParameterKey> parser,
                                                               final IERSConventions conventions,
                                                               final NormalizedSphericalHarmonicsProvider gravityField,
                                                               final OneAxisEllipsoid body,
                                                               final Orbit orbit)
        throws NoSuchElementException {

        final double minStep;
        if (!parser.containsKey(ParameterKey.PROPAGATOR_MIN_STEP)) {
            minStep = 0.001;
        } else {
            minStep = parser.getDouble(ParameterKey.PROPAGATOR_MIN_STEP);
        }

        final double maxStep;
        if (!parser.containsKey(ParameterKey.PROPAGATOR_MAX_STEP)) {
            maxStep = 300;
        } else {
            maxStep = parser.getDouble(ParameterKey.PROPAGATOR_MAX_STEP);
        }

        final double dP;
        if (!parser.containsKey(ParameterKey.PROPAGATOR_POSITION_ERROR)) {
            dP = 10.0;
        } else {
            dP = parser.getDouble(ParameterKey.PROPAGATOR_POSITION_ERROR);
        }

        final double positionScale;
        if (!parser.containsKey(ParameterKey.ESTIMATOR_ORBITAL_PARAMETERS_POSITION_SCALE)) {
            positionScale = dP;
        } else {
            positionScale = parser.getDouble(ParameterKey.ESTIMATOR_ORBITAL_PARAMETERS_POSITION_SCALE);
        }
        final NumericalPropagatorBuilder propagatorBuilder =
                        new NumericalPropagatorBuilder(orbit,
                                                       new DormandPrince853IntegratorBuilder(minStep, maxStep, dP),
                                                       PositionAngle.MEAN,
                                                       positionScale);

        // initial mass
        final double mass;
        if (!parser.containsKey(ParameterKey.MASS)) {
            mass = 1000.0;
        } else {
            mass = parser.getDouble(ParameterKey.MASS);
        }
        propagatorBuilder.setMass(mass);

        // gravity field force model
        propagatorBuilder.addForceModel(new HolmesFeatherstoneAttractionModel(body.getBodyFrame(), gravityField));

        // ocean tides force model
        if (parser.containsKey(ParameterKey.OCEAN_TIDES_DEGREE) &&
            parser.containsKey(ParameterKey.OCEAN_TIDES_ORDER)) {
            final int degree = parser.getInt(ParameterKey.OCEAN_TIDES_DEGREE);
            final int order  = parser.getInt(ParameterKey.OCEAN_TIDES_ORDER);
            if (degree > 0 && order > 0) {
                propagatorBuilder.addForceModel(new OceanTides(body.getBodyFrame(),
                                                               gravityField.getAe(), gravityField.getMu(),
                                                               degree, order, conventions,
                                                               TimeScalesFactory.getUT1(conventions, true)));
            }
        }

        // solid tides force model
        List<CelestialBody> solidTidesBodies = new ArrayList<CelestialBody>();
        if (parser.containsKey(ParameterKey.SOLID_TIDES_SUN) &&
            parser.getBoolean(ParameterKey.SOLID_TIDES_SUN)) {
            solidTidesBodies.add(CelestialBodyFactory.getSun());
        }
        if (parser.containsKey(ParameterKey.SOLID_TIDES_MOON) &&
            parser.getBoolean(ParameterKey.SOLID_TIDES_MOON)) {
            solidTidesBodies.add(CelestialBodyFactory.getMoon());
        }
        if (!solidTidesBodies.isEmpty()) {
            propagatorBuilder.addForceModel(new SolidTides(body.getBodyFrame(),
                                                           gravityField.getAe(), gravityField.getMu(),
                                                           gravityField.getTideSystem(), conventions,
                                                           TimeScalesFactory.getUT1(conventions, true),
                                                           solidTidesBodies.toArray(new CelestialBody[solidTidesBodies.size()])));
        }

        // third body attraction
        if (parser.containsKey(ParameterKey.THIRD_BODY_SUN) &&
            parser.getBoolean(ParameterKey.THIRD_BODY_SUN)) {
            propagatorBuilder.addForceModel(new ThirdBodyAttraction(CelestialBodyFactory.getSun()));
        }
        if (parser.containsKey(ParameterKey.THIRD_BODY_MOON) &&
            parser.getBoolean(ParameterKey.THIRD_BODY_MOON)) {
            propagatorBuilder.addForceModel(new ThirdBodyAttraction(CelestialBodyFactory.getMoon()));
        }

        // drag
        if (parser.containsKey(ParameterKey.DRAG) && parser.getBoolean(ParameterKey.DRAG)) {
            final double  cd          = parser.getDouble(ParameterKey.DRAG_CD);
            final double  area        = parser.getDouble(ParameterKey.DRAG_AREA);
            final boolean cdEstimated = parser.getBoolean(ParameterKey.DRAG_CD_ESTIMATED);
noeljanes's avatar
noeljanes committed
            if (parser.containsKey(ParameterKey.DRAG_CD_MIN)) {
                System.out.println(parser.getDouble(ParameterKey.DRAG_CD_MIN));
            }
            else {
                System.out.println("No min");
            }
            if (parser.containsKey(ParameterKey.DRAG_CD_MAX)) {
                System.out.println(parser.getDouble(ParameterKey.DRAG_CD_MAX));
            }
            else {
                System.out.println("No min");
            }


noeljanes's avatar
noeljanes committed
            MarshallSolarActivityFutureEstimation msafe =
                            new MarshallSolarActivityFutureEstimation(MarshallSolarActivityFutureEstimation.DEFAULT_SUPPORTED_NAMES,
                                                                      MarshallSolarActivityFutureEstimation.StrengthLevel.AVERAGE);
            DataProvidersManager manager = DataProvidersManager.getInstance();
            manager.feed(msafe.getSupportedNames(), msafe);
            //Atmosphere atmosphere = new DTM2000(msafe, CelestialBodyFactory.getSun(), body);
            Atmosphere atmosphere = new NRLMSISE00(msafe, CelestialBodyFactory.getSun(), body);
noeljanes's avatar
noeljanes committed
            propagatorBuilder.addForceModel(new DragForce(atmosphere, new IsotropicDrag(area, cd)));
noeljanes's avatar
noeljanes committed
            if (cdEstimated) {
                for (final ParameterDriver driver : propagatorBuilder.getPropagationParametersDrivers().getDrivers()) {
                    if (driver.getName().equals(DragSensitive.DRAG_COEFFICIENT)) {
                        driver.setSelected(true);
noeljanes's avatar
noeljanes committed
                        if (parser.containsKey(ParameterKey.DRAG_CD_MIN)) {
                            driver.setMinValue(parser.getDouble(ParameterKey.DRAG_CD_MIN));
                        }

                        if (parser.containsKey(ParameterKey.DRAG_CD_MAX)) {
                            driver.setMaxValue(parser.getDouble(ParameterKey.DRAG_CD_MAX));
                        }
noeljanes's avatar
noeljanes committed
                }
            }
noeljanes's avatar
noeljanes committed
        }

        // solar radiation pressure
        if (parser.containsKey(ParameterKey.SOLAR_RADIATION_PRESSURE) && parser.getBoolean(ParameterKey.SOLAR_RADIATION_PRESSURE)) {
            final double  cr          = parser.getDouble(ParameterKey.SOLAR_RADIATION_PRESSURE_CR);
            final double  area        = parser.getDouble(ParameterKey.SOLAR_RADIATION_PRESSURE_AREA);
            final boolean cREstimated = parser.getBoolean(ParameterKey.SOLAR_RADIATION_PRESSURE_CR_ESTIMATED);

            propagatorBuilder.addForceModel(new SolarRadiationPressure(CelestialBodyFactory.getSun(),
                                                                       body.getEquatorialRadius(),
                                                                       new IsotropicRadiationSingleCoefficient(area, cr)));
            if (cREstimated) {
                for (final ParameterDriver driver : propagatorBuilder.getPropagationParametersDrivers().getDrivers()) {
                    if (driver.getName().equals(RadiationSensitive.REFLECTION_COEFFICIENT)) {
                        driver.setSelected(true);
                    }
                }
            }
        }

        // post-Newtonian correction force due to general relativity
        if (parser.containsKey(ParameterKey.GENERAL_RELATIVITY) && parser.getBoolean(ParameterKey.GENERAL_RELATIVITY)) {
            propagatorBuilder.addForceModel(new Relativity(gravityField.getMu()));
        }

        // extra polynomial accelerations
        if (parser.containsKey(ParameterKey.POLYNOMIAL_ACCELERATION_NAME)) {
            final String[]       names        = parser.getStringArray(ParameterKey.POLYNOMIAL_ACCELERATION_NAME);
            final Vector3D[]     directions   = parser.getVectorArray(ParameterKey.POLYNOMIAL_ACCELERATION_DIRECTION_X,
                                                                      ParameterKey.POLYNOMIAL_ACCELERATION_DIRECTION_Y,
                                                                      ParameterKey.POLYNOMIAL_ACCELERATION_DIRECTION_Z);
            final List<String>[] coefficients = parser.getStringsListArray(ParameterKey.POLYNOMIAL_ACCELERATION_COEFFICIENTS, ',');
            final boolean[]      estimated    = parser.getBooleanArray(ParameterKey.POLYNOMIAL_ACCELERATION_ESTIMATED);

            for (int i = 0; i < names.length; ++i) {

                final PolynomialParametricAcceleration ppa =
                                new PolynomialParametricAcceleration(directions[i], true, names[i], null,
                                                                     coefficients[i].size() - 1);
                for (int k = 0; k < coefficients[i].size(); ++k) {
                    final ParameterDriver driver = ppa.getParameterDriver(names[i] + "[" + k + "]");
                    driver.setValue(Double.parseDouble(coefficients[i].get(k)));
                    driver.setSelected(estimated[i]);
                }
                propagatorBuilder.addForceModel(ppa);
            }
        }

        // attitude mode
        final AttitudeMode mode;
        if (parser.containsKey(ParameterKey.ATTITUDE_MODE)) {
            mode = AttitudeMode.valueOf(parser.getString(ParameterKey.ATTITUDE_MODE));
        } else {
            mode = AttitudeMode.NADIR_POINTING_WITH_YAW_COMPENSATION;
        }
        propagatorBuilder.setAttitudeProvider(mode.getProvider(orbit.getFrame(), body));

        return propagatorBuilder;

    }

    /** Create a gravity field from input parameters
     * @param parser input file parser
     * @return gravity field
     * @throws NoSuchElementException if input parameters are missing
     */
    private NormalizedSphericalHarmonicsProvider createGravityField(final KeyValueFileParser<ParameterKey> parser)
        throws NoSuchElementException {

        final int degree = parser.getInt(ParameterKey.CENTRAL_BODY_DEGREE);
        final int order  = FastMath.min(degree, parser.getInt(ParameterKey.CENTRAL_BODY_ORDER));
        return GravityFieldFactory.getNormalizedProvider(degree, order);

    }

    /** Create an orbit from input parameters
     * @param parser input file parser
     * @param mu     central attraction coefficient
     * @throws NoSuchElementException if input parameters are missing
     */
    private OneAxisEllipsoid createBody(final KeyValueFileParser<ParameterKey> parser)
        throws NoSuchElementException {

        final Frame bodyFrame;
        if (!parser.containsKey(ParameterKey.BODY_FRAME)) {
            bodyFrame = FramesFactory.getITRF(IERSConventions.IERS_2010, true);
        } else {
            bodyFrame = parser.getEarthFrame(ParameterKey.BODY_FRAME);
        }

        final double equatorialRadius;
        if (!parser.containsKey(ParameterKey.BODY_EQUATORIAL_RADIUS)) {
            equatorialRadius = Constants.WGS84_EARTH_EQUATORIAL_RADIUS;
        } else {
            equatorialRadius = parser.getDouble(ParameterKey.BODY_EQUATORIAL_RADIUS);
        }

        final double flattening;
        if (!parser.containsKey(ParameterKey.BODY_INVERSE_FLATTENING)) {
            flattening = Constants.WGS84_EARTH_FLATTENING;
        } else {
            flattening = 1.0 / parser.getDouble(ParameterKey.BODY_INVERSE_FLATTENING);
        }

        return new OneAxisEllipsoid(equatorialRadius, flattening, bodyFrame);

    }

    /** Create an orbit from input parameters
     * @param parser input file parser
     * @param mu     central attraction coefficient
     * @throws NoSuchElementException if input parameters are missing
     */
    private Orbit createOrbit(final KeyValueFileParser<ParameterKey> parser,
                              final double mu)
        throws NoSuchElementException {
        final Frame frame;
        if (!parser.containsKey(ParameterKey.INERTIAL_FRAME)) {
            frame = FramesFactory.getEME2000();
        } else {
            frame = parser.getInertialFrame(ParameterKey.INERTIAL_FRAME);
        }

        // Orbit definition
        PositionAngle angleType = PositionAngle.MEAN;
        if (parser.containsKey(ParameterKey.ORBIT_ANGLE_TYPE)) {
            angleType = PositionAngle.valueOf(parser.getString(ParameterKey.ORBIT_ANGLE_TYPE).toUpperCase());
        }
        if (parser.containsKey(ParameterKey.ORBIT_KEPLERIAN_A)) {
            return new KeplerianOrbit(parser.getDouble(ParameterKey.ORBIT_KEPLERIAN_A),
                                      parser.getDouble(ParameterKey.ORBIT_KEPLERIAN_E),
                                      parser.getAngle(ParameterKey.ORBIT_KEPLERIAN_I),
                                      parser.getAngle(ParameterKey.ORBIT_KEPLERIAN_PA),
                                      parser.getAngle(ParameterKey.ORBIT_KEPLERIAN_RAAN),
                                      parser.getAngle(ParameterKey.ORBIT_KEPLERIAN_ANOMALY),
                                      angleType,
                                      frame,
                                      parser.getDate(ParameterKey.ORBIT_DATE,
                                                     TimeScalesFactory.getUTC()),
                                      mu);
        } else if (parser.containsKey(ParameterKey.ORBIT_EQUINOCTIAL_A)) {
            return new EquinoctialOrbit(parser.getDouble(ParameterKey.ORBIT_EQUINOCTIAL_A),
                                        parser.getDouble(ParameterKey.ORBIT_EQUINOCTIAL_EX),