Collision Package in development

Hi everybody,

I’m looking for a solution to compute collision avoidance maneuvers parametrized with a collision probability. That could be a manually implemented evaluation of the maneuver w.r.t an iterative computation of the probability of collision or even the implementation of a maneuver optimizer tailored by a probability of collision.

A quiet well established work has been conducted so far by the Orekit team on implementing a collision package.
From what I understand, the current implementation is awaiting approval for merge within Orekit develop but is blocked by a bug fixe action on Hipparrchus side.

I would like to ask you if the package is fully tested and would be valide for usage ?
Would it be possible to make use of the current collision package version and locally implement a work around solution of the Hipparcchus bug ?

Thanks in advance for your assistance.

Best regards,
Gueorguy

Hi @Gueorguy,

I can assure you that this package has been extensively tested and validated (>95% code covered by tests). Also, I would highly recommand you to use the Laas2015 method as it is both accurate and fast to compute.

What you could do would be to create a project on your favourite IDE and use a local version of both Hipparchus and Orekit that implement associated changes to make use of this collision package.

Finally, I can also tell you that this will be merged in the following weeks :+1:.

Hope i was able to answer your questions.

Cheers,
Vincent

2 Likes

Hi @Vincent

Thanks for your reply and your suggestions.
Will do as suggested and will be following for the release of the Orekit version integrating your package.

Best regards,
Gueorguy

Hi,

Not sure this is the right thread to deal with the problem I currently have.

I try to install the hipparchus local package with maven, cloned from the issue related to the Collision Package merge request.
The procedure followed is the one described in here.

After tackling some issues related to incompatibility btw Maven versions and JDK, the installation of the hipparchus local package seems to start well.
Unfortunatly the process freezes at this stage without further logs or exceptions raised (see screenshot below).

Would you have by any chance some recommendations on how to work around this ?

Thanks in advance for the assistance.

Best regards,
Gueorguy

EDIT:
The installation process was actually running but took 30min haha.

The following error was raised in the process

Not sure what could be the cause of it… Probably the Maven plugin version.

This looks like a transient error due to some repository being unavailable, at lest I saw this a few times.
Could you just retry to see if it occurs always?

Hi @luc @Vincent

Just to keep you informed, I’ve tried to build the Hypparchus repo several times with Maven without success. I believe I miss a settings.xml file with the maven installation directory, but I’m not confortable enough with this building took to edit it manually.
Eventually I switched to Gradle, as it is the tool I’m using for my current java project.

FYI, I’ve noticed a missing Hypparchus packages within issue #218 called by the current collision package in review (hipparchus.analysis).
It doesn’t seem to affect implementation work with the collision package though.

I wish you a pleasant day.

Best regards,
Gueorguy

Hi @Gueorguy ,

That’s unfortunate, what version of maven are you using ? I’m using 3.8.1. Also, are you perhaps behind a proxy ? That would explain why it does not resolve any dependencies if the setting.xml is not configured correctly.

Regarding the missing hipparchus package, i think you’re mixing packages and modules as the analysis package is located within the hipparchus core module.

Pleasant day to you as well :slight_smile: !

Cheers,
Vincent

1 Like

hi @Vincent,

Yes you are absolutely right.
I’ve confused it with one apparent missing class within the hypparchus.analysis package of issue #218: SmoothStepFactory.java. Also I’ve noticed the ODEEventDetector.java class is missing from the hypparchus.ode one.

I might be forgetting something in the process, but anyway it hasn’t affected the local implementations with the collision package so far.

Best regards,
Gueorguy

Hi @Gueorguy,

Glad to see that it does not prevent you from working with it then.

Wish you luck for your project :+1: !

Best regards,
Vincent

hi @Vincent

I’ve implemented the probability of collision model making use of CDMs input extracted from SpaceTrack reports.
When comparing the probability of collision provided within the CDM (Foster1992 model) with the ones computed with the collision package, I obtain quiet far distant results.
When the Foster model on the screening provider side displays a probability of collision of 3.076069e-3, the scenarios implemented with the orekit collision package provides with:

  • Computed probability with Laas2015: 5.54342534405121e-42
  • Computed probability with Alfriend1999: 4.9490178521973275e-42
  • Computed probability with Alfriend1999Max: 2.71289085895617e-7
  • Computed probability with Chan1997: 4.962193166437073e-42
  • Computed probability with Patera2005: 6.059614597312072-42
  • Computed probability with Alfano2005: 6.059417682405797e-42

Please find below the implemented script of the aforementioned scenarios:

    Utils.setDataRoot("regular-data");

    // --- define primary object --- //
    // build initial state
    Frame inertialFrame = FramesFactory.getGCRF();
    TimeScale timeScale = TimeScalesFactory.getUTC();
    AbsoluteDate TCA = new AbsoluteDate(2023, 7, 3, 12, 34, 32.599000, timeScale);
    double mu = Constants.IERS2010_EARTH_MU;
    double xPrimary = 4296801.23;
    double yPrimary = -1966274.999;
    double zPrimary= 5052907.476;
    double vXPrimary = 4132.322154;
    double vYPrimary = -4021.363748; 
    double vZPrimary = -5048.9202;
    Vector3D positionPrimary = new Vector3D(xPrimary, yPrimary, zPrimary);
    Vector3D velocityPrimary = new Vector3D(vXPrimary, vYPrimary, vZPrimary);
    PVCoordinates pvaCoordinatesPrimary = new PVCoordinates(positionPrimary, velocityPrimary);
    Orbit orbitPrimary = new CartesianOrbit(pvaCoordinatesPrimary, inertialFrame, TCA, mu);

    // setup the covariance 
    double CR_R = 56.62842163398181;
    double CT_R = -962.9563299841413;
    double CT_T = 310062.8913173134;
    double CN_R = -3.083858227930857;
    double CN_T = -46.45715481699554;
    double CN_N = 78.29324044591742;
    double CRDOT_R = 0.998511039366841;
    double CRDOT_T = -341.0481042572872;
    double CRDOT_N = 0.03260535358155862;
    double CRDOT_RDOT = 0.375360870029045;
    double CTDOT_R = -0.06144319200138919;
    double CTDOT_T = 0.9751825354400959;
    double CTDOT_N = 0.003260615484735145;
    double CTDOT_RDOT = -0.001006600453836089;
    double CTDOT_TDOT = 0.00006679522022854233;
    double CNDOT_R = -0.02228119520697623;
    double CNDOT_T = 0.1307553131929408;
    double CNDOT_N = -0.02432170137777874;
    double CNDOT_RDOT = -0.0001074101838404644;
    double CNDOT_TDOT = 0.00002431601369177786;
    double CNDOT_DNOT = 0.00005026883850368887;
    
    double[][] dPrimary = {{CR_R, 0, 0, 0, 0, 0},
                           {CT_R, CT_T, 0, 0, 0, 0},
                           {CN_R, CN_T, CN_N, 0, 0, 0},
                           {CRDOT_R, CRDOT_T, CRDOT_N, CRDOT_RDOT, 0, 0},
                           {CTDOT_R, CTDOT_T, CTDOT_N, CTDOT_RDOT, CTDOT_TDOT, 0},
                           {CNDOT_R, CNDOT_T, CNDOT_N, CNDOT_RDOT, CNDOT_TDOT, CNDOT_DNOT}};

    Array2DRowRealMatrix orbitalCovariancePrimary = new Array2DRowRealMatrix(dPrimary);
    OrbitType orbitType = OrbitType.CARTESIAN;
    PositionAngle angleType = PositionAngle.TRUE;
    StateCovariance primaryCovariance = new StateCovariance(orbitalCovariancePrimary, TCA, inertialFrame, orbitType, angleType);

    double primaryRadius = 1.2007;

    // --- define secondary object --- //
    // build initial state 
    double xSecondary = 4297381.534;
    double ySecondary = -1965864.602;
    double zSecondary = 5052619.888;
    double vXSecondary = 240.610078;
    double vYSecondary= 6859.734286; 
    double vZSecondary = 2458.170234;
    Vector3D positionSecondary = new Vector3D(xSecondary, ySecondary, zSecondary);
    Vector3D velocitySecondary = new Vector3D(vXSecondary, vYSecondary, vZSecondary);
    PVCoordinates pvaCoordinatesSecondary = new PVCoordinates(positionSecondary, velocitySecondary);
    Orbit orbitSecondary = new CartesianOrbit(pvaCoordinatesSecondary, inertialFrame, TCA, mu);

    // setup the covariance 
    CR_R = 1013.814481667735;
    CT_R = -88108.82679766405;
    CT_T = 14067560.00855414;
    CN_R = -226.8393479402682;
    CN_T = 4470.621526532557;
    CN_N = 468.1211116302592;
    CRDOT_R = 96.28391345584748;
    CRDOT_T = -15385.68147491196;
    CRDOT_N = -4.899368598020352;
    CRDOT_RDOT = 16.82759829543032;
    CTDOT_R = -0.5407243780299632;
    CTDOT_T = 8.469091149439802;
    CTDOT_N = 0.2196216487071619;
    CTDOT_RDOT = -0.00917698377502303;
    CTDOT_TDOT = 0.0005267887127943032;
    CNDOT_R = 0.02282824384209208;
    CNDOT_T = -27.61496475491904;
    CNDOT_N = 0.2697886845984878;
    CNDOT_RDOT = 0.03023699728632098;
    CNDOT_TDOT = 0.000155855727404517;
    CNDOT_DNOT = 0.000973699438998447;
    
    double[][] dSecondary = {{CR_R, 0, 0, 0, 0, 0},
                             {CT_R, CT_T, 0, 0, 0, 0},
                             {CN_R, CN_T, CN_N, 0, 0, 0},
                             {CRDOT_R, CRDOT_T, CRDOT_N, CRDOT_RDOT, 0, 0},
                             {CTDOT_R, CTDOT_T, CTDOT_N, CTDOT_RDOT, CTDOT_TDOT, 0},
                             {CNDOT_R, CNDOT_T, CNDOT_N, CNDOT_RDOT, CNDOT_TDOT, CNDOT_DNOT}};

    Array2DRowRealMatrix orbitalCovariance = new Array2DRowRealMatrix(dSecondary);
    StateCovariance secondaryCovariance = new StateCovariance(orbitalCovariance, TCA, inertialFrame, orbitType, angleType);

    double secondaryRadius = 1.7437;

    // compute collision probability
    double combinedRadius = primaryRadius + secondaryRadius;

    // Laas2015 method
    ShortTermEncounter2DPOCMethod method = new Laas2015();
    ProbabilityOfCollision probabilityOfCollision = method.compute(orbitPrimary, primaryCovariance, orbitSecondary, secondaryCovariance, combinedRadius, 1e-10);

    if (probabilityOfCollision.getValue() == 0.0003076069) {
        System.out.println("It concurs with Laas2015!");

    } else {
        System.out.println("Computed probability with Laas2015: " + probabilityOfCollision.getValue());
    }

    // Alfano2005 method
    method = new Alfano2005();
    probabilityOfCollision = method.compute(orbitPrimary, primaryCovariance, orbitSecondary, secondaryCovariance, combinedRadius, 1e-10);

    if (probabilityOfCollision.getValue() == 0.0003076069) {
        System.out.println("It concurs with Alfano2005!");

    } else {
        System.out.println("Computed probability with Alfano2005: " + probabilityOfCollision.getValue());
    }

    // Alfriend1999 method
    method = new Alfriend1999();
    probabilityOfCollision = method.compute(orbitPrimary, primaryCovariance, orbitSecondary, secondaryCovariance, combinedRadius, 1e-10);

    if (probabilityOfCollision.getValue() == 0.0003076069) {
        System.out.println("It concurs with Alfriend1999!");

    } else {
        System.out.println("Computed probability with Alfriend1999: " + probabilityOfCollision.getValue());
    }

    // Alfriend1999Max method
    method = new Alfriend1999Max();
    probabilityOfCollision = method.compute(orbitPrimary, primaryCovariance, orbitSecondary, secondaryCovariance, combinedRadius, 1e-10);

    if (probabilityOfCollision.getValue() == 0.0003076069) {
        System.out.println("It concurs with Alfriend1999Max!");

    } else {
        System.out.println("Computed probability with Alfriend1999Max: " + probabilityOfCollision.getValue());
    }

    // Chan1997 method
    method = new Chan1997();
    probabilityOfCollision = method.compute(orbitPrimary, primaryCovariance, orbitSecondary, secondaryCovariance, combinedRadius, 1e-10);

    if (probabilityOfCollision.getValue() == 0.0003076069) {
        System.out.println("It concurs with Chan1997!");

    } else {
        System.out.println("Computed probability with Chan1997: " + probabilityOfCollision.getValue());
    }

    // Patera2005 method
    method = new Patera2005();
    probabilityOfCollision = method.compute(orbitPrimary, primaryCovariance, orbitSecondary, secondaryCovariance, combinedRadius, 1e-10);

    if (probabilityOfCollision.getValue() == 0.0003076069) {
        System.out.println("It concurs with Patera2005!");

    } else {
        System.out.println("Computed probability with Patera2005: " + probabilityOfCollision.getValue());
    }

I’ve also noticed that the unit test of the Laas2015 model directly implementing CDM file provides with a probability of collision of a magnitude of 1e-40 while the CDM data specifies a Foster1992 collision probability of magnitude 1e-1.
Litterature on Laas2015 model validates the computation model with regard to Foster1992 and other 2D gaussian computation methodologies though (i.e. table 3, page 25 of the hyperlinked paper).

So with all that beeing said, I believe that I might be missing a step in the collision probability assessment. Shouldn’t we obtain a strongly close probability of collision w.r.t the reference CDM data when calling the compute() method of an implemented model (Laas2015 or else) ?

I thank you in advance for your time on this.

Best regards,
Gueorguy

Hi @Gueorguy ,

Thank you for the associated code, this will be very helpful to figure out what’s wrong. The unit test which use a CDM is only here to test that the method taking in a CDM does not fail but the values between the CDM and the output poc should not be compared. I’ll look into it just in case.

A first thing to look at would be units as this can tremendously change the expected result. Unfortunatly i won’t have any time to investigate this today but i’ll try to look into it this weekend, sorry :grimacing:.

Cheers,
Vincent

Hello,

From a very quick look at your code, why are your covariance matrices triangular? Maybe it’s the way to call the method in which case my bad.
Another remark, for 2D methods like Patera, any covariance that doesn’t relate to position is actually not used.

Cheers,
Romain.

Hi @Gueorguy,

I investigated your code a bit and found one mistake that drastically close the gap with the probability of collision you’re looking for.

When defining the StateCovariance for the primary and secondary collision object, you define them using the inertial frame when you should be defining them using the LOFType.QSW_INERTIAL local orbital frame:
new StateCovariance(orbitalCovariance, TCA, LOFType.QSW_INERTIAL);

When fixed, i find a probability of collision around ~3.3E-5 which is already much closer to the 3.076069e-3 (by the way, you use 3.076069e-4 in your code ?).

Could you perhaps check the CDM again to see the expected probability of collision ? Also perhaps look for comment indicating if this probability is expressed in % because i find it odd that we’re almost exactly 10^2 order of magnitude away from the expected value.

Cheers,
Vincent

hi @Vincent and @Serrof,

Thanks for your time and availability on this topic.
To answer chronologically to both of your questions:

  • @Serrof the covariance matrix is retrieved as-is from the CDM file. It’s triangularized by the screening provider.

  • @Vincent Yes indeed the probability of collision provided in the CDM from the above scenario is of 3.076069e-4.

  • The CDM is set on the CCSDS 508.0-B-1 standard where the probability is given as a value defined in the interval [0.0, 1.0].

I’ve noticed that the reference frame set within the extracted CDM files is the fixed ITRF one.
It causes the method compute() inputting a cdm file to crash when trying to build an orekit orbit instance requiring a non-inertial frame. See below the related code and thrown exception.
It might be interesting to set a checker with a frame transformation loop within the mentionned method.

    // Patera2005 method
    ShortTermEncounter2DPOCMethod method = new Patera2005();

    String CDM_PATH = "collision-resources/ION_SCV8_vs_STARLINK_1233.cdm";
    ClassLoader classloader = Thread.currentThread().getContextClassLoader();
    URL         inputUrl    = classloader.getResource(CDM_PATH);
    DataSource  data        = new DataSource(inputUrl.getPath());
    Cdm         cdm         = new ParserBuilder().buildCdmParser().parseMessage(data);
    double primaryRadius = 5.0;
    double secondaryRadius = 5.0;
    double PoC = method.compute(cdm, primaryRadius, secondaryRadius).getValue();

    System.out.println("Computed probability with Patera2005: " + PoC);

Thrown exception:

Exception in thread “main” org.orekit.errors.OrekitIllegalArgumentException: non pseudo-inertial frame “ITRF-2020/CIO/2010-based ITRF simple EOP”
at org.orekit.orbits.Orbit.ensurePseudoInertialFrame(Orbit.java:205)
at org.orekit.orbits.Orbit.(Orbit.java:145)
at org.orekit.orbits.CartesianOrbit.(CartesianOrbit.java:100)
at org.orekit.orbits.CartesianOrbit.(CartesianOrbit.java:123)
at org.orekit.ssa.collision.shorttermencounter.probability.twod.AbstractShortTermEncounter2DPOCMethod.getPrimaryFromCdm(AbstractShortTermEncounter2DPOCMethod.java:242)
at org.orekit.ssa.collision.shorttermencounter.probability.twod.AbstractShortTermEncounter2DPOCMethod.compute(AbstractShortTermEncounter2DPOCMethod.java:95)
at org.orekit.ssa.collision.shorttermencounter.probability.twod.ShortTermEncounter2DPOCMethod.compute(ShortTermEncounter2DPOCMethod.java:64)
at org.orekit.CollisionRiskProbabilityComputationWithCDM.main(CollisionRiskProbabilityComputationWithCDM.java:28)

I confirm that defining the covariance matrices with the QSW_INERTIAL local orbital frame does increase the probability of collision to some order of magnitudes close to the reference PoC. However it doesn’t seem to make sense to virtually set it referenced to a local orbital frame when they are actually defined within the ITRF one.

I’ve decided to project the input PV coordinates and covariance matrices from the CDM (defined in the ITRF frame) respectively to the GCRF frame (allowing the definitition of satellite orbits) and the QSW_INERTIAL local orbital frame. The results are very encouraging:

  • Computed probability with Laas2015: 0.001483649317441629
  • Computed probability with Alfano2005: 0.0014836595274094796
  • Computed probability with Alfriend1999: 0.0015020406713417813
  • Computed probability with Alfriend1999Max: 0.19427013238554633
  • Computed probability with Chan1997: 0.0015009131774305908
  • Computed probability with Patera2005: 0.0014836493174408775

When the reference PoC provided within the CDM is 0.004450713 (Foster1992).
The order of magnitude are matching apart from Alfriend1999Max.
The residual deviation might be inherant to each model algorithms…
Here’s the reference CDM file retrieved from recent conjunctions notified by CSpOC.
ION_SCV8_vs_STARLINK_1233.txt (12.9 KB)

Let me know what do you think about it.

You can find below the related script:

   // initial setup 
    Frame itrf = FramesFactory.getITRF(IERSConventions.IERS_2010, false);
    Frame inertialFrame = FramesFactory.getGCRF();
    LOFType LOF = LOFType.QSW_INERTIAL;
    LofOffset lofOffset = new LofOffset(inertialFrame, LOF);
    TimeScale timeScale = TimeScalesFactory.getUTC();
    AbsoluteDate TCA = new AbsoluteDate(2023, 7, 5, 20, 31, 15.893, timeScale);
    double mu = Constants.IERS2010_EARTH_MU;
    double[][] jacobian = new double[6][6];

    // --- define primary object --- //
    // build initial state
    double xPrimary = -5719153.201;
    double yPrimary = -2486155.271;
    double zPrimary= -3021252.701;
    double vXPrimary = 2333.174842 ;
    double vYPrimary = 2825.732323 ; 
    double vZPrimary = -6727.808538;
    Vector3D positionPrimary = new Vector3D(xPrimary, yPrimary, zPrimary);
    Vector3D velocityPrimary = new Vector3D(vXPrimary, vYPrimary, vZPrimary);
    PVCoordinates pvaCoordinatesPrimary = new PVCoordinates(positionPrimary, velocityPrimary);
    
    AbsolutePVCoordinates absPVACoordinatesPrimary = new AbsolutePVCoordinates(itrf, TCA, pvaCoordinatesPrimary);
    Attitude primaryAttitude = lofOffset.getAttitude(absPVACoordinatesPrimary, TCA, itrf);
    SpacecraftState primaryState = new SpacecraftState(absPVACoordinatesPrimary, primaryAttitude);        
    
    Transform primaryTransform = primaryState.toTransform();
    primaryTransform.getJacobian(CartesianDerivativesFilter.USE_PV, jacobian);
    RealMatrix primarydC2dC1 = MatrixUtils.createRealMatrix(jacobian);

    // setup the covariance 
    double CR_R = 127.5401258877026 ;
    double CT_R = -216.5469301895778;
    double CT_T = 9738.762752029239;
    double CN_R = 23.41184551274494;
    double CN_T = -5.346171445289681;
    double CN_N = 24.60870138594973;
    double CRDOT_R = 0.2482739312599897;
    double CRDOT_T = -10.55496325674788 ;
    double CRDOT_N = 0.005950144116086071;
    double CRDOT_RDOT = 0.01147849769311488 ;
    double CTDOT_R = -0.1375882369099475 ;
    double CTDOT_T = 0.1222189661319367 ;
    double CTDOT_N = -0.02576925085939057;
    double CTDOT_RDOT = -0.0001458466399925159;
    double CTDOT_TDOT = 0.0001499094267380701;
    double CNDOT_R = 0.008141795305978281;
    double CNDOT_T = -0.05578838789977865;
    double CNDOT_N = -0.0003344474012710994;
    double CNDOT_RDOT = 0.00005801069817622688;
    double CNDOT_TDOT = -0.000008757429553163563;
    double CNDOT_DNOT = 0.00009287778622823746;
    
    double[][] dPrimary = {{CR_R, 0, 0, 0, 0, 0},
                           {CT_R, CT_T, 0, 0, 0, 0},
                           {CN_R, CN_T, CN_N, 0, 0, 0},
                           {CRDOT_R, CRDOT_T, CRDOT_N, CRDOT_RDOT, 0, 0},
                           {CTDOT_R, CTDOT_T, CTDOT_N, CTDOT_RDOT, CTDOT_TDOT, 0},
                           {CNDOT_R, CNDOT_T, CNDOT_N, CNDOT_RDOT, CNDOT_TDOT, CNDOT_DNOT}};

    Array2DRowRealMatrix orbitalCovariancePrimary = new Array2DRowRealMatrix(dPrimary);
    OrbitType orbitType = OrbitType.CARTESIAN;
    PositionAngle angleType = PositionAngle.TRUE;


    // --- define secondary object --- //
    // build initial state 
    double xSecondary = -5719163.147;
    double ySecondary = -2486109.2;
    double zSecondary = -3021222.87;
    double vXSecondary = -415.96327;
    double vYSecondary= -5206.88041; 
    double vZSecondary = 5081.948896;
    Vector3D positionSecondary = new Vector3D(xSecondary, ySecondary, zSecondary);
    Vector3D velocitySecondary = new Vector3D(vXSecondary, vYSecondary, vZSecondary);
    PVCoordinates pvaCoordinatesSecondary = new PVCoordinates(positionSecondary, velocitySecondary);
    
    AbsolutePVCoordinates absPVACoordinatesSecondary = new AbsolutePVCoordinates(itrf, TCA, pvaCoordinatesSecondary);
    Attitude secondaryAttitude = lofOffset.getAttitude(absPVACoordinatesSecondary, TCA, itrf);
    SpacecraftState secondaryState = new SpacecraftState(absPVACoordinatesSecondary, secondaryAttitude);        
    
    Transform secondaryTransform = secondaryState.toTransform();
    secondaryTransform.getJacobian(CartesianDerivativesFilter.USE_PV, jacobian);
    RealMatrix secondarydC2dC1 = MatrixUtils.createRealMatrix(jacobian);

    // setup the covariance 
    CR_R = 964.6447977021088;
    CT_R = -29096.52093664356;
    CT_T = 1555885.738355947;
    CN_R = -610.4622634358643;
    CN_T = 7105.637820746857;
    CN_N = 1325.505208766663;
    CRDOT_R = 31.55505053547703;
    CRDOT_T = -1687.047343882137;
    CRDOT_N = -7.503566951636299;
    CRDOT_RDOT = 1.829454352163062;
    CTDOT_R = -0.7822616662183071;
    CTDOT_T = 16.88006830847172;
    CTDOT_N = 0.627700053500938;
    CTDOT_RDOT = -0.01829894383644205;
    CTDOT_TDOT = 0.000706074549697974;
    CNDOT_R = 0.004835998593925756;
    CNDOT_T = -0.1102870161755583;
    CNDOT_N = -0.2277988353274012;
    CNDOT_RDOT = 0.00005700360443949522;
    CNDOT_TDOT = -0.00001234324761245689;
    CNDOT_DNOT = 0.0003799085974184537;
    
    double[][] dSecondary = {{CR_R, 0, 0, 0, 0, 0},
                             {CT_R, CT_T, 0, 0, 0, 0},
                             {CN_R, CN_T, CN_N, 0, 0, 0},
                             {CRDOT_R, CRDOT_T, CRDOT_N, CRDOT_RDOT, 0, 0},
                             {CTDOT_R, CTDOT_T, CTDOT_N, CTDOT_RDOT, CTDOT_TDOT, 0},
                             {CNDOT_R, CNDOT_T, CNDOT_N, CNDOT_RDOT, CNDOT_TDOT, CNDOT_DNOT}};

    Array2DRowRealMatrix orbitalCovarianceSecondary = new Array2DRowRealMatrix(dSecondary);

    // transform Covariances from ITRF to defined LOF
    RealMatrix transformedPrimaryCovarianceRealMatrix = primarydC2dC1.multiply(orbitalCovariancePrimary).multiplyTransposed(primarydC2dC1);
    RealMatrix transformedSecondaryCovarianceRealMatrix = secondarydC2dC1.multiply(orbitalCovarianceSecondary).multiplyTransposed(secondarydC2dC1);

    StateCovariance primaryTransformedCovariance = new StateCovariance(transformedPrimaryCovarianceRealMatrix, TCA, LOF);
    StateCovariance secondaryTransformedCovariance = new StateCovariance(transformedSecondaryCovarianceRealMatrix, TCA, LOF);

    // transform PVCoordinates from ITRF to GCRF and build associated orbits
    Transform frameTransform = itrf.getTransformTo(inertialFrame, TCA);

    PVCoordinates transformedPvCoordinatesPrimary = frameTransform.transformPVCoordinates(pvaCoordinatesPrimary);
    PVCoordinates transformedPvCoordinatesSecondary = frameTransform.transformPVCoordinates(pvaCoordinatesSecondary);

    Orbit orbitPrimary = new CartesianOrbit(transformedPvCoordinatesPrimary, inertialFrame, TCA, mu);
    Orbit orbitSecondary = new CartesianOrbit(transformedPvCoordinatesSecondary, inertialFrame, TCA, mu);

    // compute collision probability
    double primaryRadius = 5.000000;
    double secondaryRadius = 5.000000;

    double combinedRadius = primaryRadius + secondaryRadius;

    // Laas2015 method
    ShortTermEncounter2DPOCMethod method = new Laas2015();
    ProbabilityOfCollision probabilityOfCollision = method.compute(orbitPrimary, primaryTransformedCovariance, orbitSecondary, secondaryTransformedCovariance, combinedRadius, 1e-10);

    if (probabilityOfCollision.getValue() == 0.004450713) {
        System.out.println("It matches with Laas2015!");

    } else {
        System.out.println("Computed probability with Laas2015: " + probabilityOfCollision.getValue());
    }

    // Alfano2005 method
    method = new Alfano2005();
    probabilityOfCollision = method.compute(orbitPrimary, primaryTransformedCovariance, orbitSecondary, secondaryTransformedCovariance, combinedRadius, 1e-10);

    if (probabilityOfCollision.getValue() == 0.004450713) {
        System.out.println("It matches with Alfano2005!");

    } else {
        System.out.println("Computed probability with Alfano2005: " + probabilityOfCollision.getValue());
    }

    // Alfriend1999 method
    method = new Alfriend1999();
    probabilityOfCollision = method.compute(orbitPrimary, primaryTransformedCovariance, orbitSecondary, secondaryTransformedCovariance, combinedRadius, 1e-10);

    if (probabilityOfCollision.getValue() == 0.004450713) {
        System.out.println("It matches with Alfriend1999!");

    } else {
        System.out.println("Computed probability with Alfriend1999: " + probabilityOfCollision.getValue());
    }

    // Alfriend1999Max method
    method = new Alfriend1999Max();
    probabilityOfCollision = method.compute(orbitPrimary, primaryTransformedCovariance, orbitSecondary, secondaryTransformedCovariance, combinedRadius, 1e-10);

    if (probabilityOfCollision.getValue() == 0.004450713) {
        System.out.println("It matches with Alfriend1999Max!");

    } else {
        System.out.println("Computed probability with Alfriend1999Max: " + probabilityOfCollision.getValue());
    }

    // Chan1997 method
    method = new Chan1997();
    probabilityOfCollision = method.compute(orbitPrimary, primaryTransformedCovariance, orbitSecondary, secondaryTransformedCovariance, combinedRadius, 1e-10);

    if (probabilityOfCollision.getValue() == 0.004450713) {
        System.out.println("It matches with Chan1997!");

    } else {
        System.out.println("Computed probability with Chan1997: " + probabilityOfCollision.getValue());
    }

    // Patera2005 method
    method = new Patera2005();
    probabilityOfCollision = method.compute(orbitPrimary, primaryTransformedCovariance, orbitSecondary, secondaryTransformedCovariance, combinedRadius, 1e-10);

    if (probabilityOfCollision.getValue() == 0.004450713) {
        System.out.println("It matches with Patera2005!");

    } else {
        System.out.println("Computed probability with Patera2005: " + probabilityOfCollision.getValue());
    }
}

hi @Gueorguy,

Thanks for your detailed answer. Regarding your question about the local orbital frame, only the position and velocity are expressed in the ITRF frame whereas the covariance components are expressed in the RTN (equivalent to QSW) local orbital frame of each object. I also agree with you that we should be able to handle non inertial frame in CDM.

I took a look at your code and made some changes. However, i still had a probability of collision of 3e-3 with the new CDM instead of 0.00445… Given that the covariance is expressed properly and not scaled according to the CDM, the only option left if the combined radius being different. That’s why i added to the combined radius, the radius computed from AREA_PC from both objects. Using this slightly larger combined radius (11,38 m instead of 10m), i find a poc of 4.23e-3.

Ultimately, we don’t know what configuration they used when using Foster1992 so the remaining difference may be due to that ?

I’m posting the modifed code for the new CDM below :

        // initial setup
        Frame        itrf          = FramesFactory.getITRF(IERSConventions.IERS_2010, false);
        Frame        inertialFrame = FramesFactory.getGCRF();
        TimeScale    timeScale     = TimeScalesFactory.getUTC();
        AbsoluteDate tca           = new AbsoluteDate(2023, 7, 5, 20, 31, 15.893, timeScale);
        double       mu            = Constants.IERS2010_EARTH_MU;

        // --- define primary object --- //
        // build initial state
        double        xPrimary                    = -5719153.201;
        double        yPrimary                    = -2486155.271;
        double        zPrimary                    = -3021252.701;
        double        vXPrimary                   = 2333.174842;
        double        vYPrimary                   = 2825.732323;
        double        vZPrimary                   = -6727.808538;
        Vector3D      positionPrimary             = new Vector3D(xPrimary, yPrimary, zPrimary);
        Vector3D      velocityPrimary             = new Vector3D(vXPrimary, vYPrimary, vZPrimary);
        PVCoordinates pvaCoordinatesPrimaryInITRF = new PVCoordinates(positionPrimary, velocityPrimary);

        // setup the covariance
        double CR_R       = 127.5401258877026;
        double CT_R       = -216.5469301895778;
        double CT_T       = 9738.762752029239;
        double CN_R       = 23.41184551274494;
        double CN_T       = -5.346171445289681;
        double CN_N       = 24.60870138594973;
        double CRDOT_R    = 0.2482739312599897;
        double CRDOT_T    = -10.55496325674788;
        double CRDOT_N    = 0.005950144116086071;
        double CRDOT_RDOT = 0.01147849769311488;
        double CTDOT_R    = -0.1375882369099475;
        double CTDOT_T    = 0.1222189661319367;
        double CTDOT_N    = -0.02576925085939057;
        double CTDOT_RDOT = -0.0001458466399925159;
        double CTDOT_TDOT = 0.0001499094267380701;
        double CNDOT_R    = 0.008141795305978281;
        double CNDOT_T    = -0.05578838789977865;
        double CNDOT_N    = -0.0003344474012710994;
        double CNDOT_RDOT = 0.00005801069817622688;
        double CNDOT_TDOT = -0.000008757429553163563;
        double CNDOT_DNOT = 0.00009287778622823746;

        double[][] dPrimary = { { CR_R, 0, 0, 0, 0, 0 },
                                { CT_R, CT_T, 0, 0, 0, 0 },
                                { CN_R, CN_T, CN_N, 0, 0, 0 },
                                { CRDOT_R, CRDOT_T, CRDOT_N, CRDOT_RDOT, 0, 0 },
                                { CTDOT_R, CTDOT_T, CTDOT_N, CTDOT_RDOT, CTDOT_TDOT, 0 },
                                { CNDOT_R, CNDOT_T, CNDOT_N, CNDOT_RDOT, CNDOT_TDOT, CNDOT_DNOT } };

        RealMatrix orbitalCovariancePrimary = new BlockRealMatrix(dPrimary);

        // --- define secondary object --- //
        // build initial state
        double        xSecondary              = -5719163.147;
        double        ySecondary              = -2486109.2;
        double        zSecondary              = -3021222.87;
        double        vXSecondary             = -415.96327;
        double        vYSecondary             = -5206.88041;
        double        vZSecondary             = 5081.948896;
        Vector3D      positionSecondary       = new Vector3D(xSecondary, ySecondary, zSecondary);
        Vector3D      velocitySecondary       = new Vector3D(vXSecondary, vYSecondary, vZSecondary);
        PVCoordinates pvaCoordinatesSecondaryInITRF = new PVCoordinates(positionSecondary, velocitySecondary);

        // setup the covariance
        CR_R       = 964.6447977021088;
        CT_R       = -29096.52093664356;
        CT_T       = 1555885.738355947;
        CN_R       = -610.4622634358643;
        CN_T       = 7105.637820746857;
        CN_N       = 1325.505208766663;
        CRDOT_R    = 31.55505053547703;
        CRDOT_T    = -1687.047343882137;
        CRDOT_N    = -7.503566951636299;
        CRDOT_RDOT = 1.829454352163062;
        CTDOT_R    = -0.7822616662183071;
        CTDOT_T    = 16.88006830847172;
        CTDOT_N    = 0.627700053500938;
        CTDOT_RDOT = -0.01829894383644205;
        CTDOT_TDOT = 0.000706074549697974;
        CNDOT_R    = 0.004835998593925756;
        CNDOT_T    = -0.1102870161755583;
        CNDOT_N    = -0.2277988353274012;
        CNDOT_RDOT = 0.00005700360443949522;
        CNDOT_TDOT = -0.00001234324761245689;
        CNDOT_DNOT = 0.0003799085974184537;

        double[][] dSecondary = { { CR_R, 0, 0, 0, 0, 0 },
                                  { CT_R, CT_T, 0, 0, 0, 0 },
                                  { CN_R, CN_T, CN_N, 0, 0, 0 },
                                  { CRDOT_R, CRDOT_T, CRDOT_N, CRDOT_RDOT, 0, 0 },
                                  { CTDOT_R, CTDOT_T, CTDOT_N, CTDOT_RDOT, CTDOT_TDOT, 0 },
                                  { CNDOT_R, CNDOT_T, CNDOT_N, CNDOT_RDOT, CNDOT_TDOT, CNDOT_DNOT } };

        RealMatrix orbitalCovarianceSecondary = new BlockRealMatrix(dSecondary);

        // create state covariance
        StateCovariance primaryCovariance =
                new StateCovariance(orbitalCovariancePrimary, tca, LOFType.QSW_INERTIAL);
        StateCovariance secondaryCovariance =
                new StateCovariance(orbitalCovarianceSecondary, tca, LOFType.QSW_INERTIAL);

        // transform PVCoordinates from ITRF to GCRF and build associated orbits
        Transform itrfToInertial = itrf.getTransformTo(inertialFrame, tca);

        PVCoordinates pvaCoordinatesPrimaryInInertial   = itrfToInertial.transformPVCoordinates(pvaCoordinatesPrimaryInITRF);
        PVCoordinates pvaCoordinatesSecondaryInInertial = itrfToInertial.transformPVCoordinates(pvaCoordinatesSecondaryInITRF);

        Orbit orbitPrimary   = new CartesianOrbit(pvaCoordinatesPrimaryInInertial, inertialFrame, tca, mu);
        Orbit orbitSecondary = new CartesianOrbit(pvaCoordinatesSecondaryInInertial, inertialFrame, tca, mu);

        // compute collision probability
        double primaryRadius = 5.000000;
        double primaryRadiusPC = FastMath.sqrt(1.2007/FastMath.PI);
        double secondaryRadius = 5.000000;
        double secondaryRadiusPC = FastMath.sqrt(1.8385/FastMath.PI);

        double combinedRadius = primaryRadius + secondaryRadius + primaryRadiusPC + secondaryRadiusPC;
        
        // Laas2015 method
        ShortTermEncounter2DPOCMethod method = new Laas2015();
        ProbabilityOfCollision probabilityOfCollision =
                method.compute(orbitPrimary, primaryCovariance, orbitSecondary, secondaryCovariance,
                               combinedRadius, 1e-10);

        if (probabilityOfCollision.getValue() == 0.004450713) {
            System.out.println("It matches with Laas2015!");

        }
        else {
            System.out.println("Computed probability with Laas2015: " + probabilityOfCollision.getValue());
        }

        // Alfano2005 method
        method                 = new Alfano2005();
        probabilityOfCollision =
                method.compute(orbitPrimary, primaryCovariance, orbitSecondary, secondaryCovariance,
                               combinedRadius, 1e-10);

        if (probabilityOfCollision.getValue() == 0.004450713) {
            System.out.println("It matches with Alfano2005!");

        }
        else {
            System.out.println("Computed probability with Alfano2005: " + probabilityOfCollision.getValue());
        }

        // Alfriend1999 method
        method                 = new Alfriend1999();
        probabilityOfCollision =
                method.compute(orbitPrimary, primaryCovariance, orbitSecondary, secondaryCovariance,
                               combinedRadius, 1e-10);

        if (probabilityOfCollision.getValue() == 0.004450713) {
            System.out.println("It matches with Alfriend1999!");

        }
        else {
            System.out.println("Computed probability with Alfriend1999: " + probabilityOfCollision.getValue());
        }

        // Alfriend1999Max method
        method                 = new Alfriend1999Max();
        probabilityOfCollision =
                method.compute(orbitPrimary, primaryCovariance, orbitSecondary, secondaryCovariance,
                               combinedRadius, 1e-10);

        if (probabilityOfCollision.getValue() == 0.004450713) {
            System.out.println("It matches with Alfriend1999Max!");

        }
        else {
            System.out.println("Computed probability with Alfriend1999Max: " + probabilityOfCollision.getValue());
        }

        // Chan1997 method
        method                 = new Chan1997();
        probabilityOfCollision =
                method.compute(orbitPrimary, primaryCovariance, orbitSecondary, secondaryCovariance,
                               combinedRadius, 1e-10);

        if (probabilityOfCollision.getValue() == 0.004450713) {
            System.out.println("It matches with Chan1997!");

        }
        else {
            System.out.println("Computed probability with Chan1997: " + probabilityOfCollision.getValue());
        }

        // Patera2005 method
        method                 = new Patera2005();
        probabilityOfCollision =
                method.compute(orbitPrimary, primaryCovariance, orbitSecondary, secondaryCovariance,
                               combinedRadius, 1e-10);

        if (probabilityOfCollision.getValue() == 0.004450713) {
            System.out.println("It matches with Patera2005!");

        }
        else {
            System.out.println("Computed probability with Patera2005: " + probabilityOfCollision.getValue());
        }

I would have liked to give you a more definite answer but i’m afraid that is the best i can do.

Cheers,
Vincent

Hi there,

In this note:

You can read on the last page that CSpOC doesn’t use a disk as the 2D projected combined object but a square that contains it, hence the overestimation in the CDM.

Cheers,
Romain.

2 Likes

Hi,

Thank you both again for your contribution on this.

@Vincent:
Indeed, the covariance projection frame is specified in strong black and white letters within the CCSDS CDM recommanded standard document… my bad for this.

Regarding the exclusion areas, do you consider it to be in addition of the PC_AREA , like a catchment area? The definition on the JSPOC document provided by Serrof is not quiet clear and I find nothing on the CCSDS side.

@Serrof:
Thanks for the document, this detail might indeed explain the remaining discrepancy in the model !

Best regards,
Gueorguy

Hi @Gueorguy,

Don’t worry about it, i’ve had my fair share of problems with frames so i can sympathize with you.

In my last attempt, i have indeed added the exclusion radius to the radius deduced from the PC_AREA field, giving me a combined radius of 11.38m instead of 10m. However, and after reading the paper mentioned by @Serrof, i think that only the exclusion volume radius should be considered when it is given as in your provided CDM. If not provided, then you should use the AREA_PC to deduce the equivalent sphere radius.

Also, i would like to take this opportunity to ask for your feedback on the use of the future collision package (apart from the fact that Orekit does not handle CDM in non inertial frame :sweat_smile: ) ?

EDIT: It was not Orekit that could not handle the non inertial frame but my code :grimacing: , this is now fixed. I’m going to merge it into develop soon :partying_face:.

Cheers,
Vincent

1 Like

Hi @Vincent,

Sorry for my very late reply.

Good news for the non-inertial frame issue !

The implementation of a collision package within Orekit is a great and necessary addition.
From our extensive exchange on the issues we’ve faced trying to replicate collision computation models taken from CSpOC (former JSpOC), I do believe that this package is promissing. The open points indentified in this thread are not necessarily related to the implemented models and methods (apart from the resolved frame issue) but more on the initial setup/assumptions to be considered when making use of the models:

  • Which frames, non-inertial or inertial ?

  • 2D projection models (circular, squared)

  • Applied primary and secondary object radius

  • … etc

I believe the release of this package should be conducted with prior validation tests aligned with approved collision computation models. One could even consider the Orekit package to implement pre-built collision computations models fully aligned with institutional screening services models (CSpOC, EU SST, …). However, this last consideration is probably a bit off the Orekit functional scope.

I hope this feedback would help.
Looking forward to seeing the package released in dev.

Best regards,
Gueorguy