Phase Angle calculation between two stars

I want to calculate the phase Angle between two satellites in the same orbit or different plane orbit, I use STK method as shown in the figure below, I also use Orekit to write some code to calculate, although the result is given, but I ignore one problem is time, STK software can calculate the phase Angle of each time point, but my program has no time information, which makes me very confused. My method first uses the Kepler roots of two satellites to propagate with a numerical integrator, then calculates the first vector and second vector of satellite eccentricity, calculates the mean latitude parameter, calculates the mean latitude argument according to these three parameters, and then subtraction the mean latitude argument of the two satellites. I don’t know if my practice is correct or not, I hope to get your help, I am a beginner,
type or paste code here :face_with_peeking_eye:

        final KeplerianOrbit initialOrbit2 = new KeplerianOrbit(6893678.08724067,0.00153912,
                                                                FastMath.toRadians(97.60317163),
                                                                FastMath.toRadians(65.73638295),
                                                                FastMath.toRadians(69.24863943),
                                                                FastMath.toRadians(55.36150646),
                                                                PositionAngleType.MEAN,
                                                                FramesFactory.getEME2000(),
                                                                orbitEpoch2, mu);
        // Initialize state
        final SpacecraftState initialState2 = new SpacecraftState(initialOrbit2, 31);
        // Define the numerical integration method
        new numericalIntegrator().NumericalIntegrator(initialOrbit2,initialState2,start,end);
        //Calculate the first and second components of the satellite orbit eccentricity vector
        double ex2 = initialOrbit2.getE()*Math.cos(initialOrbit2.getPerigeeArgument());
        double ey2 = initialOrbit2.getE()*Math.sin(initialOrbit2.getPerigeeArgument());
        //Calculate the mean latitude parameter(rad)
        double alphaE2=initialOrbit2.getE()+initialOrbit2.getPerigeeArgument();
        //Calculate  the mean latitude argument
        double argumentOfLatitude2=eccentricToMean(ex2,ey2,alphaE2);
        //Calculate the phase difference between two satellites
        double phaseDiff=argumentOfLatitude1-argumentOfLatitude2;
        System.out.println("phaseDiff:"+phaseDiff);
![c82451957f966267a9d3e23edb2d7ed|690x331](upload://tiRLmt8epKA9MsoKbdAP7nEy9Q1.png)

There are two issues in your code, one over-complication and one probable misunderstanding.

The first issue is the computation alphaE2=initialOrbit2.getE()+initialOrbit2.getPerigeeArgument(). Here you are adding the eccentricity to the perigee argument. I guess you thought getE() would return the eccentric anomaly, but it is getEccentricAnomaly() that does so. This method is available only in the specialized class KeplerianOrbit but as your orbit is indeed a KeplerianOrbit, you could call it.

The second issue is that the phase difference should rather been computed by subtracting true latitude arguments (but see next point) instead of eccentric latitude arguments.

The over-complication is that you attempt to compute the latitude argument by yourself from the Keplerian elements, but in fact you could rely on the longitude argument rather than latitude argument and compute the phase difference from both true longitude arguments. The true longitude argument is given by getLv, and is is available for all orbit types, so you can extract it directly from any SpacecraftState object by just calling getOrbit().getLv() without bothering about which orbit type is really in the spacecraft state.

The probable misunderstanding is the use of numerical integrator. Here you seem to create a numerical integrator (I think it is really a propagator), and that it will update the initialOrbit2. However orbits (and spacecraft states too) in Orekit are immutable objects, they are never updated. So when one does a propagation, one has to either retrieve the propagated state at the end of propagation from the return value of the propagate method or pick it up throughout propagation at some fixed time step intervals by registering a step handler.

One last point: as you are dealing with two satellites simultaneously, you could use the PropagatorsParallelizer class with your own implementation of MultiSatFixedStepHandler to perform the computation of phase differences throughout propagation.

Hello,

Below is an example using @luc explaination.

I used two arbitrary orbits with one having a much higher sma to see the lowest orbit catching up with the highest.

The phase difference is stored in a matrix so that you can get the phase difference for any satellites with respect to any other satellite.

Code

import org.hipparchus.linear.MatrixUtils;
import org.hipparchus.linear.RealMatrix;
import org.hipparchus.util.FastMath;
import org.hipparchus.util.MathUtils;
import org.orekit.data.DataContext;
import org.orekit.data.DataProvider;
import org.orekit.data.DirectoryCrawler;
import org.orekit.frames.FramesFactory;
import org.orekit.orbits.KeplerianOrbit;
import org.orekit.orbits.Orbit;
import org.orekit.orbits.PositionAngleType;
import org.orekit.propagation.Propagator;
import org.orekit.propagation.PropagatorsParallelizer;
import org.orekit.propagation.SpacecraftState;
import org.orekit.propagation.analytical.KeplerianPropagator;
import org.orekit.propagation.sampling.MultiSatFixedStepHandler;
import org.orekit.time.AbsoluteDate;
import org.orekit.utils.Constants;

import java.io.File;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;


public class PhaseBetweenSatellites {
    public static void main(String[] args) {
        // Load orekit data
        loadOrekitData();

        // Orbit 1
        final Orbit orbit1 = getOrbit1();

        // Orbit 2
        final Orbit orbit2 = getOrbit2();

        // Orbit 3
        final Orbit orbit3 = getOrbit3();

        // Create propagators
        final Propagator       propagator1 = new KeplerianPropagator(orbit1);
        final Propagator       propagator2 = new KeplerianPropagator(orbit2);
        final Propagator       propagator3 = new KeplerianPropagator(orbit3);
        final List<Propagator> propagators = Arrays.asList(propagator1, propagator2, propagator3);

        // Create multi sat step handler
        final PhaseDifferenceStepHandler handler = new PhaseDifferenceStepHandler();

        // Create propagators parallelizer
        double                        step         = 60.;
        final PropagatorsParallelizer parallelizer = new PropagatorsParallelizer(propagators, step, handler);

        // Propagate
        final AbsoluteDate startDate = orbit1.getDate();
        final AbsoluteDate stopDate  = startDate.shiftedBy(Constants.JULIAN_DAY);
        parallelizer.propagate(startDate, stopDate);

        // Retrieve list of phase angle differences
        final List<RealMatrix> phaseDifferenceMatrixList = handler.getPhaseDifferenceMatrixList();

        // Print difference between satellite 1 and 2 (angle2 - angle1) throughout the propagation
        for (int i = 0; i < phaseDifferenceMatrixList.size(); i++) {
            final double diff1With2                   = phaseDifferenceMatrixList.get(i).getData()[0][1];
            final double normalizedDiff1With2         = MathUtils.normalizeAngle(diff1With2, 0);
            final double normalizedDiff2With2InDegree = FastMath.toDegrees(normalizedDiff1With2);

            System.out.println(startDate.shiftedBy(i * step));
            if (normalizedDiff1With2 < 0) {
                System.out.format("Satellite 2 in front of satellite 1 by %4.2f°.\n\n",
                                  FastMath.abs(normalizedDiff2With2InDegree));
            } else if (normalizedDiff1With2 > 0) {
                System.out.format("Satellite 2 behind of satellite 1 by %4.2f°.\n\n",
                                  normalizedDiff2With2InDegree);
            } else {
                System.out.format("Satellite 2 at same phase angle satellite 1.\n\n");
            }
        }

    }

    private static void loadOrekitData() {
        final File rootFile   = new File(System.getProperty("user.home"));
        final File orekitData = new File(rootFile, "orekit-data");
        if (!orekitData.exists()) {
            System.out.format("File %s not found.%n", orekitData.getAbsolutePath());
        }
        final DataProvider dirCrawler = new DirectoryCrawler(orekitData);
        DataContext.getDefault().getDataProvidersManager().addProvider(dirCrawler);
    }

    private static Orbit getOrbit1() {
        double a     = 7000e3;
        double e     = 0.001;
        double i     = FastMath.toRadians(60.0);
        double omega = FastMath.toRadians(0.0);
        double raan  = FastMath.toRadians(45.0);
        double nu    = FastMath.toRadians(0); // True anomaly


        return new KeplerianOrbit(a, e, i, omega, raan, nu,
                                  PositionAngleType.TRUE,
                                  FramesFactory.getEME2000(),
                                  new AbsoluteDate(),
                                  Constants.IERS2010_EARTH_MU);
    }

    private static Orbit getOrbit2() {
        double a     = 10000e3;
        double e     = 0.001;
        double i     = FastMath.toRadians(60.0);
        double omega = FastMath.toRadians(0.0);
        double raan  = FastMath.toRadians(45.0);
        double nu    = FastMath.toRadians(30); // True anomaly


        return new KeplerianOrbit(a, e, i, omega, raan, nu,
                                  PositionAngleType.TRUE,
                                  FramesFactory.getEME2000(),
                                  new AbsoluteDate(),
                                  Constants.IERS2010_EARTH_MU);
    }

    private static Orbit getOrbit3() {
        double a     = 8500e3;
        double e     = 0.001;
        double i     = FastMath.toRadians(60.0);
        double omega = FastMath.toRadians(0.0);
        double raan  = FastMath.toRadians(45.0);
        double nu    = FastMath.toRadians(15); // True anomaly


        return new KeplerianOrbit(a, e, i, omega, raan, nu,
                                  PositionAngleType.TRUE,
                                  FramesFactory.getEME2000(),
                                  new AbsoluteDate(),
                                  Constants.IERS2010_EARTH_MU);
    }

    private static class PhaseDifferenceStepHandler implements MultiSatFixedStepHandler {

        final List<RealMatrix> phaseDifferenceMatrixList = new ArrayList<>();

        @Override
        public void handleStep(List<SpacecraftState> states) {

            // Create matrix to store results
            final RealMatrix phaseDifferenceMatrix = MatrixUtils.createRealDiagonalMatrix(new double[states.size()]);
            for (int i = 1; i < states.size(); i++) {
                for (int j = 0; j < i; j++) {

                    // Compute phase difference
                    final double phase2          = states.get(i).getLv();
                    final double phase1          = states.get(j).getLv();
                    final double phaseDifference = phase2 - phase1;

                    // Store in matrix
                    phaseDifferenceMatrix.setEntry(i, j, phaseDifference);
                    phaseDifferenceMatrix.setEntry(j, i, -phaseDifference);
                }
            }

            // Store in list
            phaseDifferenceMatrixList.add(phaseDifferenceMatrix);
        }

        public List<RealMatrix> getPhaseDifferenceMatrixList() {
            return phaseDifferenceMatrixList;
        }
    }
}

Cheers,
Vincent

o,I was still learning what luc said PropagatorsParallelizer yesterday, did not come to reply him urgently, thank you, this program I will try later.