# Calculating TCA with two TLE data

Hello everyone. first post here (and new to orekit!). I am trying to calculate TCA and MissDistance with TLE data from CelesTrack, but it calculates the values a bit incorrectly. how can I calculate the exact values without error?

package org.example;

import org.hipparchus.geometry.euclidean.threed.Vector3D;
import org.orekit.propagation.SpacecraftState;
import org.orekit.propagation.analytical.tle.TLE;
import org.orekit.propagation.analytical.tle.TLEPropagator;
import org.orekit.time.AbsoluteDate;

public class Main {

``````public static void main(String[] args) {
try {
// Initialize Orekit
InitializeOrekit.init();

// TLE data for Sat1
String tleLine1Sat1 = "1 45746U 20038S   24135.58388045  .00013219  00000+0  85889-3 0  9991";
String tleLine2Sat1 = "2 45746  53.0549 337.5672 0001521 101.0908 259.0253 15.08327573216090";
TLE tleSat1 = new TLE(tleLine1Sat1, tleLine2Sat1);

// TLE data for SL-12 R/B(AUX MOTOR)
String tleLine1Sat2 = "1 54760U 22175C   24136.21138098  .00004893  00000+0  32507-3 0  9990";
String tleLine2Sat2 = "2 54760  53.2150 142.7806 0001482  72.0039 288.1115 15.08864831 77592";
TLE tleSat2 = new TLE(tleLine1Sat2, tleLine2Sat2);

// Create TLE propagators
TLEPropagator propagatorTianmu1 = TLEPropagator.selectExtrapolator(tleSat1);
TLEPropagator propagatorSl12RB = TLEPropagator.selectExtrapolator(tleSat2);

// Set start date
AbsoluteDate startDate = tleSat1.getDate();

// Set time interval
AbsoluteDate endDate = startDate.shiftedBy(360 * 3600); // 15 days

// Find the time and distance of closest approach (TCA)
double minDistance = Double.MAX_VALUE;

AbsoluteDate tcaDate = null;

// Iterate over the time interval
AbsoluteDate currentDate = startDate;
while (currentDate.compareTo(endDate) <= 0) {
// Get the state of both spacecraft
SpacecraftState stateSat1 = propagatorTianmu1.propagate(currentDate);
SpacecraftState stateSat2 = propagatorSl12RB.propagate(currentDate);

// Get the position vectors
Vector3D positionSat1 = stateSat1.getPVCoordinates().getPosition();
Vector3D positionSat2 = stateSat2.getPVCoordinates().getPosition();

// Calculate the distance
double distance = Vector3D.distance(positionSat2, positionSat1);

// Check for minimum distance
if (distance < minDistance) {
minDistance = distance;
}

currentDate = currentDate.shiftedBy(0.02);
}

// Print the time and distance of closest approach
if (tcaDate != null) {
System.out.println("Closest Approach Time (TCA): " + tcaDate);
System.out.println("Minimum Distance (km): " + minDistance / 1000); // Distance in meters
} else {
}

}       catch (Exception e) {
e.printStackTrace();
}
``````

}
}

Could you try using the ExtremumApproachDetector

You can add this detector to the propagatorTianmu1 and use propagatorSl12RB as PVCoordinatesProvider of the detector.

You can find example in the test class of the detector.

Best regards,
Bryan

1 Like

Hi @bcazabonne. thank you for your answer.

I get an error, java: type org.orekit.propagation.events.handlers.EventHandler does not take parameters

if you have some free time, I would be very grateful if you could show me how to do it.

package org.example;

import org.hipparchus.geometry.euclidean.threed.Vector3D;
import org.hipparchus.ode.events.Action;
import org.orekit.propagation.SpacecraftState;
import org.orekit.propagation.analytical.tle.TLE;
import org.orekit.propagation.analytical.tle.TLEPropagator;
import org.orekit.propagation.events.ExtremumApproachDetector;
import org.orekit.propagation.events.handlers.EventHandler;
import org.orekit.time.AbsoluteDate;

public class Main {

``````public static void main(String[] args) {
try {

InitializeOrekit.init();

// Sat1 için TLE verileri
String tleLine1Sat1 = "1 45746U 20038S   24135.58388045  .00013219  00000+0  85889-3 0  9991";
String tleLine2Sat1 = "2 45746  53.0549 337.5672 0001521 101.0908 259.0253 15.08327573216090";
TLE tleSat1 = new TLE(tleLine1Sat1, tleLine2Sat1);

String tleLine1Sat2 = "1 54760U 22175C   24136.21138098  .00004893  00000+0  32507-3 0  9990";
String tleLine2Sat2 = "2 54760  53.2150 142.7806 0001482  72.0039 288.1115 15.08864831 77592";
TLE tleSat2 = new TLE(tleLine1Sat2, tleLine2Sat2);

TLEPropagator propagatorSat1 = TLEPropagator.selectExtrapolator(tleSat1);
TLEPropagator propagatorSat2 = TLEPropagator.selectExtrapolator(tleSat2);

AbsoluteDate startDate = tleSat1.getDate();

AbsoluteDate endDate = startDate.shiftedBy(360 * 3600); // 15 gün sonrası

ExtremumApproachDetector extremumApproachDetector = new ExtremumApproachDetector(propagatorSat2)
.withHandler(new EventHandler<ExtremumApproachDetector>() {
@Override
public Action eventOccurred(SpacecraftState s, ExtremumApproachDetector detector, boolean increasing) {
return Action.STOP;
}

@Override
public SpacecraftState resetState(ExtremumApproachDetector detector, SpacecraftState oldState) {
return oldState;
}
});

double minDistance = Double.MAX_VALUE;
AbsoluteDate tcaDate = null;

AbsoluteDate currentDate = startDate;
double timeStep = 60.0; // Başlangıçta 60 saniye
while (currentDate.compareTo(endDate) <= 0) {

SpacecraftState stateSat1 = propagatorSat1.propagate(currentDate);
SpacecraftState stateSat2 = propagatorSat2.propagate(currentDate);

Vector3D positionSat1 = stateSat1.getPVCoordinates().getPosition();
Vector3D positionSat2 = stateSat2.getPVCoordinates().getPosition();

double distance = Vector3D.distance(positionSat2, positionSat1);

if (distance < minDistance) {
minDistance = distance;
}

currentDate = currentDate.shiftedBy(timeStep);

if (distance < 5000) {
timeStep = 1.0; // Mesafe 5km'den küçükse adımı küçült
}
if (distance < 3000) {
timeStep = 0.1; // Mesafe 3km'den küçükse adımı daha da küçült
}
if (distance < 1000) {
timeStep = 0.01; // Mesafe 1km'den küçükse adımı çok küçült
}
}

if (tcaDate != null) {
System.out.println("En Yakın Yaklaşma Zamanı (TCA): " + tcaDate);
System.out.println("En Küçük Uzaklık (km): " + minDistance / 1000); // Metre cinsinden uzaklık
} else {
}

} catch (Exception e) {
e.printStackTrace();
}
}
``````

}

Hi,

The handler you’ve implemented already exists. It’s called `StopOnEvent`.

Cheers,
Romain.

1 Like

Hi @Serrof
How exactly do i need to edit it? I do not know much abaout coding and GPT did not do a good job.
Thank you.

Use `withHandler(new StopOnEvent())`

1 Like

I did not understand where it is

package org.example;

import org.example.InitializeOrekit;
import org.hipparchus.geometry.euclidean.threed.Vector3D;
import org.junit.jupiter.api.Assertions;
import org.junit.jupiter.api.Test;
import org.orekit.propagation.SpacecraftState;
import org.orekit.propagation.analytical.tle.TLE;
import org.orekit.propagation.analytical.tle.TLEPropagator;
import org.orekit.propagation.events.ExtremumApproachDetector;
import org.orekit.time.AbsoluteDate;

public class Main {

``````@Test
public void testFindMinimumDistanceBetweenSatellites() {
try {
// Initialize Orekit
InitializeOrekit.init();

// TLE data for Sat1
String tleLine1Sat1 = "1 45746U 20038S   24135.58388045  .00013219  00000+0  85889-3 0  9991";
String tleLine2Sat1 = "2 45746  53.0549 337.5672 0001521 101.0908 259.0253 15.08327573216090";
TLE tleSat1 = new TLE(tleLine1Sat1, tleLine2Sat1);

// TLE data for Sat2
String tleLine1Sat2 = "1 54760U 22175C   24136.21138098  .00004893  00000+0  32507-3 0  9990";
String tleLine2Sat2 = "2 54760  53.2150 142.7806 0001482  72.0039 288.1115 15.08864831 77592";
TLE tleSat2 = new TLE(tleLine1Sat2, tleLine2Sat2);

// Create TLE propagators for both satellites
TLEPropagator propagatorTianmu1 = TLEPropagator.selectExtrapolator(tleSat1);
TLEPropagator propagatorSl12RB = TLEPropagator.selectExtrapolator(tleSat2);

// Set up the ExtremumApproachDetector with Sat2 as the secondary provider
ExtremumApproachDetector detector = new ExtremumApproachDetector(propagatorSl12RB);

// Add the detector to the propagator of Sat1

// Set the start date for propagation
AbsoluteDate startDate = tleSat1.getDate();

// Propagation time interval (e.g., 15 days)
AbsoluteDate endDate = startDate.shiftedBy(15 * 24 * 3600); // 15 days

// Variables to track minimum distance
double minDistance = Double.MAX_VALUE;
AbsoluteDate minDistanceDate = null;

// Propagate and detect closest approach events
AbsoluteDate currentDate = startDate;
while (currentDate.compareTo(endDate) < 0) {
// Propagate both satellites to the current date
SpacecraftState stateSat1 = propagatorTianmu1.propagate(currentDate);
SpacecraftState stateSat2 = propagatorSl12RB.propagate(currentDate);

// Calculate distance between the satellites
Vector3D positionSat1 = stateSat1.getPVCoordinates().getPosition();
Vector3D positionSat2 = stateSat2.getPVCoordinates().getPosition();
double distance = Vector3D.distance(positionSat1, positionSat2);

// Check for minimum distance
if (distance < minDistance) {
minDistance = distance;
minDistanceDate = currentDate;
}

// Advance time for propagation
currentDate = currentDate.shiftedBy(60); // Propagate every 60 seconds
}

// Output the minimum distance and the corresponding date
System.out.println("Minimum Distance: " + minDistance + " meters");
System.out.println("At Date: " + minDistanceDate);

} catch (Exception e) {
e.printStackTrace();
}
}
``````

}

is it correct this way?
@Serrof

I suggest you look at the orekit tutorials, which are documented here. You can in particular look at the ones dealing with propagation.
You will see that instead of performing a loop in time by yourself (you used a 60 s step for this in your code), you can set up a handler and have a single propagation run, that will be automatically stopped when the even occurs. Start with the first tutorials (simple propagation with no events) before diving into the next ones.

1 Like

It is highly recommend that you look at the tutorials, mentioned by @luc.
And the orekit is well documented. You should read that too.

Specifically here, what @Serrof said is the implemention of `new EventHandler<ExtremumApproachDetector>()` in `.withHandler()` in your code, it is just the `StopOnEvent`. So the code should be like the followings:

``````ExtremumApproachDetector extremumApproachDetector = new ExtremumApproachDetector(propagatorSat2)
.withHandler(new StopOnEvent());
``````

Further more, when we use event, the loop is no longer needed. The event is used instead of the loop, with high performance and high time resolution.

Here is the sample code in python. You can take a look.

``````    # Initialize the extremum approach detector and event slope filter for detecting
# and filtering increasing events.
extremumApproachDetector = ExtremumApproachDetector(secondaryPVProvider)
closeApproachDetector = EventSlopeFilter(extremumApproachDetector,
FilterType.TRIGGER_ONLY_INCREASING_EVENTS)\
.withHandler(StopOnEvent())

# Set up the event logger and add it to the propagator to monitor
# the close approach event.
eventsLogger = EventsLogger()
eventsLogger.monitorDetector(closeApproachDetector))

# Propagate from `absdateStart` to `absdateEnd` and clear the event detectors.
prop.propagate(absdateStart, absdateEnd)

# Get the unique logged event and extract relevant information.
event: EventsLogger.LoggedEvent = eventsLogger.getLoggedEvents().get(0)
absdate = event.getDate()
s: SpacecraftState = event.getState()
pv = s.getPVCoordinates(_eme2000)
secdPV = secondaryPVProvider.getPVCoordinates(absdate, _eme2000)
# Compute the distance， which is the minimum distance between the two bodies.
minDis = Vector3D.distance(secdPV.getPosition(),
pv.getPosition())
``````
``````prop=propagatorTianmu1
secondaryPVProvider=propagatorSl12RB
``````
1 Like

Hi all,

By using `ExtremumApproachDetector` with `EventSlopeFilter`, the event of closest approach can be detected. But for the two satellite, it is just the first one, not the one really minimum distance during the time span. How to solve it?

For the case here, the closest approach is as followings, which is just the first one.

``````2024-05-14T14:47:10.82068539554401Z 757.364km
``````

1 Like

Hi,

Well with `StopOnEvent` as handler, you do stop at the first occurence. If there are multiple close approaches and you want to know the closest of all, you need to somehow log all the events and check afterwards. So you could use `RecordAndContinue` for example.

Cheers,
Romain.

1 Like

Hi @Serrof ,

Thank you so much.
With `RecordAndContinue` handler and looping the logged events, the Closest-Approach can be found.

``````    # Loop the logged events to find the Closest-Approach during the time span,
# and assemble relevant information.
absdate_closest = None
info_closest = {}
dis_closest = None
for event in eventsLogger.getLoggedEvents():
absdate: AbsoluteDate = event.getDate()
s: SpacecraftState = event.getState()
pv = s.getPVCoordinates(_eme2000)
secdPV = secondaryPVProvider.getPVCoordinates(absdate, _eme2000)
# Compute the distance， which is the minimum distance between the two bodies.
dis = Vector3D.distance(secdPV.getPosition(),
pv.getPosition())
# Compute the relative velocity
relvel = Vector3D.subtract(secdPV.getVelocity(), pv.getVelocity())
# print('{} {:8.3f} {}'.format(absdate.toStringWithoutUtcOffset(_utc, 6),
#                              dis * 1e-3, relvel))

if (dis_closest is None) or (dis < dis_closest):
dis_closest = dis
absdate_closest = absdate
info_closest = {'dis': dis, 'relvel': relvel,
'pv': pv, 'secdPV': secdPV}
``````

The result is as followings:

``````2024-05-20T17:03:42.44189146462073Z {'dis': 855.1896383023153, 'relvel': <Vector3D: {968.4113496121; -1,378.8216963619; 11,971.6454535693}>, 'spv': <TimeStampedPVCoordinates: {2024-05-20T17:03:42.44189146462073, P(-3799683.4142968054, 5701844.024700588, 954500.4086337961), V(-4308.642532043876, -1862.0144038531332, -5970.1894198128475), A(4.57436435120161, -6.864338156237287, -1.1491043407152146)}>, 'pv': <TimeStampedPVCoordinates: {2024-05-20T17:03:42.44189146462073, P(-3799391.018639073, 5701048.681807317, 954385.1533565962), V(-3340.231182431817, -3240.836100215075, 6001.456033756488), A(4.575663018318098, -6.865857631474727, -1.1493802397005881)}>}
``````

BTW, the `StopOnEvent` is the default handler of `EventSlopeFilter`. Is that true?

1 Like

Hi, thank you so much for your answer.

Im trying to write in orekit but i could not convert yours.

Here is what I wrote;

import org.example.InitializeOrekit;
import org.hipparchus.geometry.euclidean.threed.Vector3D;
import org.hipparchus.ode.events.Action;
import org.orekit.bodies.OneAxisEllipsoid;
import org.orekit.data.DataProvidersManager;
import org.orekit.data.ZipJarCrawler;
import org.orekit.frames.FramesFactory;
import org.orekit.orbits.PositionAngleType;
import org.orekit.propagation.SpacecraftState;
import org.orekit.propagation.analytical.tle.TLE;
import org.orekit.propagation.analytical.tle.TLEPropagator;
import org.orekit.propagation.events.ExtremumApproachDetector;
import org.orekit.propagation.events.handlers.EventHandler;
import org.orekit.time.AbsoluteDate;
import org.orekit.time.TimeScalesFactory;
import org.orekit.utils.Constants;

import java.io.File;

public class Main {
public static void main(String args) {
try {
// Initialize Orekit
InitializeOrekit.init();

``````        // Load TLE data
String tleLine1Sat1 = "1 25544U 98067A   20029.54791667  .00016717  00000-0  10270-3 0  9000";
String tleLine2Sat1 = "2 25544  51.6442  25.4028 0007397  39.2633  65.7286 15.50199938209694";
TLE tleSat1 = new TLE(tleLine1Sat1, tleLine2Sat1);

String tleLine1Sat2 = "1 33591U 09005A   20029.54791667  .00016717  00000-0  10270-3 0  9000";
String tleLine2Sat2 = "2 33591  51.6442  25.4028 0007397  39.2633  65.7286 15.50199938209694";
TLE tleSat2 = new TLE(tleLine1Sat2, tleLine2Sat2);

// Create propagators
TLEPropagator propagatorSat1 = TLEPropagator.selectExtrapolator(tleSat1);
TLEPropagator propagatorSat2 = TLEPropagator.selectExtrapolator(tleSat2);

// Create detector for extremum approach
ExtremumApproachDetector detector = new ExtremumApproachDetector(1.0, propagatorSat2)
.withHandler(new EventHandler<ExtremumApproachDetector>() {
@Override
public Action eventOccurred(SpacecraftState state, ExtremumApproachDetector detector, boolean increasing) {
// Capture the TCA and miss distance
AbsoluteDate tca = state.getDate();
double missDistance = detector.getCurrentState().getPVCoordinates().getPosition().distance(state.getPVCoordinates().getPosition());
System.out.println("Closest Approach Time (TCA): " + tca);
System.out.println("Minimum Distance (km): " + missDistance / 1000);
return Action.STOP;
}

@Override
public SpacecraftState resetState(ExtremumApproachDetector detector, SpacecraftState oldState) {
return oldState;
}
});

// Set up time range for propagation
AbsoluteDate startDate = tleSat1.getDate();
AbsoluteDate endDate = startDate.shiftedBy(360 * 3600); // 15 days

// Add event detector to the propagator

// Propagate over the time range
propagatorSat1.propagate(startDate, endDate);

} catch (Exception e) {
e.printStackTrace();
}
}
``````

}

and this is the error i cant fix
java: type org.orekit.propagation.events.handlers.EventHandler does not take parameters

Replace `new EventHandler<ExtremumApproachDetector>` by `new EventHandler`. Generics have been removed from event handlers in january 2023, according to issue 1017. The change was later published in 12.0.

I replaced but now İntellij dont even run the code

I think here i have similar error

``````DateDetector maneuverDate = new DateDetector(tcaDate);
ImpulseManeuver<DateDetector> maneuver = new ImpulseManeuver<>(
maneuverDate,
deltaV,
isp
);
``````

error:
`java: type org.orekit.forces.maneuvers.ImpulseManeuver does not take parameters`

how do you provide tle?

what is wrong in here?

The first “>” symbol should be deleted. Your IDE should tell you what is the mistake here.

Cheers,
Maxime

I think what the “masters” mean is that ‘you have to take a bite of food and walk step by step’. It is best to follow the learning path of this tool, gradually delving into the engineering problem you want to solve from the first example. GPT cannot even solve geometry problems in junior high school, so you cannot expect it to really solve engineering problems. The current ability of AI is only to search for existing information online and reorganize it in order to approach the questions that you ask (most of the original information about the technical part is still outdated). Come on, let’s learn from scratch together. The suggestions given by everyone in the forum are often directional, rather than directly providing code that can be compiled. By the way, has the problem been resolved?

Cheers,
houmingyang

1 Like