Skip to content

Commit 3b8e304

Browse files
authored
Merge pull request #37 from thkruz/claude/conjunction-assessment-workflow-013nkXNDCBzpdeJG9z7Y7N2b
feat: add high accuracy conjunction assessment workflow
2 parents a281380 + b2fe3d3 commit 3b8e304

7 files changed

Lines changed: 1436 additions & 1 deletion

File tree

Lines changed: 247 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,247 @@
1+
/**
2+
* @file Conjunction Assessment Example
3+
* @description Demonstrates high accuracy conjunction assessment using
4+
* historical TLE accuracy and covariance propagation.
5+
*
6+
* This example shows how to:
7+
* 1. Set up a conjunction assessment between two space objects
8+
* 2. Use high-fidelity propagators for improved accuracy
9+
* 3. Propagate covariance matrices based on TLE quality
10+
* 4. Calculate probability of collision
11+
*
12+
* @author Theodore Kruczek
13+
* @license AGPL-3.0-or-later
14+
* @copyright (c) 2025 Kruczek Labs LLC
15+
*/
16+
17+
import {
18+
ConjunctionAssessment,
19+
EpochUTC,
20+
ForceModel,
21+
Kilometers,
22+
Tle,
23+
StateCovariance,
24+
CovarianceFrame,
25+
} from '../src/main';
26+
27+
// Example 1: Basic Conjunction Assessment using TLEs
28+
function basicConjunctionAssessment() {
29+
console.log('=== Example 1: Basic Conjunction Assessment ===\n');
30+
31+
// Sample TLE data for two satellites in close proximity
32+
const primaryTle = new Tle(
33+
'1 25544U 98067A 25019.50000000 .00016717 00000-0 10270-3 0 9005',
34+
'2 25544 51.6400 339.8000 0002571 90.5000 269.6000 15.50000000000000',
35+
);
36+
37+
const secondaryTle = new Tle(
38+
'1 44691U 19074A 25019.50000000 .00016500 00000-0 10200-3 0 9006',
39+
'2 44691 51.6450 339.8050 0002600 90.5050 269.6050 15.50005000000000',
40+
);
41+
42+
// Create conjunction assessment with object radii
43+
const assessment = new ConjunctionAssessment(
44+
{
45+
name: 'ISS (Zarya)',
46+
tle: primaryTle,
47+
radius: 0.05 as Kilometers, // 50 meters
48+
},
49+
{
50+
name: 'Secondary Object',
51+
tle: secondaryTle,
52+
radius: 0.01 as Kilometers, // 10 meters
53+
},
54+
);
55+
56+
// Define search window (6 hours)
57+
const startTime = EpochUTC.fromDateTimeString('2025-01-19T12:00:00.000Z');
58+
const endTime = EpochUTC.fromDateTimeString('2025-01-19T18:00:00.000Z');
59+
60+
// Perform conjunction assessment
61+
const event = assessment.assess({
62+
startTime,
63+
endTime,
64+
});
65+
66+
// Display results
67+
console.log(event.toString());
68+
console.log(`\nHigh Risk: ${event.isHighRisk(1.0 as Kilometers)}`);
69+
}
70+
71+
// Example 2: High-Fidelity Propagation with Covariance
72+
function highFidelityConjunctionAssessment() {
73+
console.log('\n=== Example 2: High-Fidelity Assessment with Covariance ===\n');
74+
75+
const primaryTle = new Tle(
76+
'1 25544U 98067A 25019.50000000 .00016717 00000-0 10270-3 0 9005',
77+
'2 25544 51.6400 339.8000 0002571 90.5000 269.6000 15.50000000000000',
78+
);
79+
80+
const secondaryTle = new Tle(
81+
'1 44691U 19074A 25019.50000000 .00016500 00000-0 10200-3 0 9006',
82+
'2 44691 51.6450 339.8050 0002600 90.5050 269.6050 15.50005000000000',
83+
);
84+
85+
const assessment = new ConjunctionAssessment(
86+
{
87+
name: 'ISS (Zarya)',
88+
tle: primaryTle,
89+
radius: 0.05 as Kilometers,
90+
},
91+
{
92+
name: 'Secondary Object',
93+
tle: secondaryTle,
94+
radius: 0.01 as Kilometers,
95+
},
96+
);
97+
98+
const startTime = EpochUTC.fromDateTimeString('2025-01-19T12:00:00.000Z');
99+
const endTime = EpochUTC.fromDateTimeString('2025-01-19T18:00:00.000Z');
100+
101+
// Use high-fidelity propagation with force model
102+
const forceModel = new ForceModel().setGravity(8, 8).setAtmosphericDrag().setSolarRadiationPressure();
103+
104+
const event = assessment.assess({
105+
startTime,
106+
endTime,
107+
useHighFidelity: true,
108+
forceModel,
109+
propagateCovariance: true, // Propagate TLE-based covariances
110+
});
111+
112+
console.log(event.toString());
113+
114+
if (event.probabilityOfCollision !== undefined) {
115+
console.log(`\nProbability of Collision: ${event.probabilityOfCollision.toExponential(6)}`);
116+
}
117+
118+
if (event.getMahalanobisDistance() !== undefined) {
119+
console.log(`Mahalanobis Distance: ${event.getMahalanobisDistance()!.toFixed(3)} sigma`);
120+
}
121+
}
122+
123+
// Example 3: Custom Covariance Matrices
124+
function customCovarianceAssessment() {
125+
console.log('\n=== Example 3: Custom Covariance Matrices ===\n');
126+
127+
const primaryTle = new Tle(
128+
'1 25544U 98067A 25019.50000000 .00016717 00000-0 10270-3 0 9005',
129+
'2 25544 51.6400 339.8000 0002571 90.5000 269.6000 15.50000000000000',
130+
);
131+
132+
const secondaryTle = new Tle(
133+
'1 44691U 19074A 25019.50000000 .00016500 00000-0 10200-3 0 9006',
134+
'2 44691 51.6450 339.8050 0002600 90.5050 269.6050 15.50005000000000',
135+
);
136+
137+
// Define custom covariances (1-sigma values in RIC frame)
138+
// [radial, intrack, crosstrack, radial_vel, intrack_vel, crosstrack_vel]
139+
const primaryCovariance = StateCovariance.fromSigmas(
140+
[
141+
0.5, // 500 m radial uncertainty
142+
1.5, // 1.5 km intrack uncertainty
143+
0.5, // 500 m crosstrack uncertainty
144+
0.001, // 1 m/s radial velocity uncertainty
145+
0.003, // 3 m/s intrack velocity uncertainty
146+
0.001, // 1 m/s crosstrack velocity uncertainty
147+
],
148+
CovarianceFrame.RIC,
149+
);
150+
151+
const secondaryCovariance = StateCovariance.fromSigmas(
152+
[0.3, 1.0, 0.3, 0.0005, 0.002, 0.0005],
153+
CovarianceFrame.RIC,
154+
);
155+
156+
const assessment = new ConjunctionAssessment(
157+
{
158+
name: 'ISS (Zarya)',
159+
tle: primaryTle,
160+
covariance: primaryCovariance,
161+
radius: 0.05 as Kilometers,
162+
},
163+
{
164+
name: 'Secondary Object',
165+
tle: secondaryTle,
166+
covariance: secondaryCovariance,
167+
radius: 0.01 as Kilometers,
168+
},
169+
);
170+
171+
const startTime = EpochUTC.fromDateTimeString('2025-01-19T12:00:00.000Z');
172+
const endTime = EpochUTC.fromDateTimeString('2025-01-19T18:00:00.000Z');
173+
174+
const event = assessment.assess({
175+
startTime,
176+
endTime,
177+
});
178+
179+
console.log(event.toString());
180+
}
181+
182+
// Example 4: Screening Multiple Objects
183+
function screeningExample() {
184+
console.log('\n=== Example 4: Multi-Object Screening ===\n');
185+
186+
const primaryTle = new Tle(
187+
'1 25544U 98067A 25019.50000000 .00016717 00000-0 10270-3 0 9005',
188+
'2 25544 51.6400 339.8000 0002571 90.5000 269.6000 15.50000000000000',
189+
);
190+
191+
// List of potential conjunction objects
192+
const secondaryTles = [
193+
new Tle(
194+
'1 44691U 19074A 25019.50000000 .00016500 00000-0 10200-3 0 9006',
195+
'2 44691 51.6450 339.8050 0002600 90.5050 269.6050 15.50005000000000',
196+
),
197+
new Tle(
198+
'1 12345U 81001A 25019.50000000 .00016400 00000-0 10100-3 0 9007',
199+
'2 12345 51.6500 339.8100 0002650 90.5100 269.6100 15.50010000000000',
200+
),
201+
];
202+
203+
const startTime = EpochUTC.fromDateTimeString('2025-01-19T12:00:00.000Z');
204+
const endTime = EpochUTC.fromDateTimeString('2025-01-19T18:00:00.000Z');
205+
206+
const screeningThreshold = 5.0 as Kilometers; // 5 km screening threshold
207+
const pcThreshold = 1e-6; // Pc > 1e-6 is concerning
208+
209+
console.log(`Screening ${secondaryTles.length} objects for conjunctions...\n`);
210+
211+
secondaryTles.forEach((secondaryTle, index) => {
212+
const assessment = new ConjunctionAssessment(
213+
{ tle: primaryTle, radius: 0.05 as Kilometers },
214+
{ tle: secondaryTle, radius: 0.01 as Kilometers },
215+
);
216+
217+
const event = assessment.assess({
218+
startTime,
219+
endTime,
220+
useHighFidelity: true,
221+
propagateCovariance: true,
222+
});
223+
224+
if (event.missDistance < screeningThreshold) {
225+
console.log(`Object ${index + 1}: CLOSE APPROACH DETECTED`);
226+
console.log(` TCA: ${event.tca.toISOString()}`);
227+
console.log(` Miss Distance: ${event.missDistance.toFixed(3)} km`);
228+
229+
if (event.probabilityOfCollision !== undefined && event.probabilityOfCollision > pcThreshold) {
230+
console.log(` Pc: ${event.probabilityOfCollision.toExponential(3)} [HIGH RISK]`);
231+
} else if (event.probabilityOfCollision !== undefined) {
232+
console.log(` Pc: ${event.probabilityOfCollision.toExponential(3)}`);
233+
}
234+
console.log();
235+
}
236+
});
237+
}
238+
239+
// Run all examples
240+
if (require.main === module) {
241+
basicConjunctionAssessment();
242+
highFidelityConjunctionAssessment();
243+
customCovarianceAssessment();
244+
screeningExample();
245+
246+
console.log('\n=== All Examples Complete ===');
247+
}

0 commit comments

Comments
 (0)