Space Domain Awareness (SDA) — tracking and characterizing all objects in Earth orbit to protect space assets and predict collisions — has moved from a niche Space Force mission to a critical national security requirement as orbital congestion increases. The software architecture requirements for modern SDA systems span real-time data ingestion, orbital mechanics computation, probabilistic conjunction analysis, and operator interface design.
What Space Domain Awareness Systems Must Do
A complete SDA architecture must:
- Ingest: Receive observations from diverse sensors (radar, optical, passive RF) in multiple formats at high volume
- Correlate: Associate new observations with known catalog objects or flag as uncorrelated tracks (UCTs)
- Propagate: Maintain accurate state vectors (position and velocity) for all catalog objects using orbital mechanics models
- Assess: Compute conjunction probabilities (probability of collision between objects) and generate alerts
- Display: Provide operator situational awareness — 3D visualization, alert dashboards, conjunction reports
- Disseminate: Share data with commercial operators, allies, and civil space agencies per policy
Data Ingestion Architecture
SDA systems receive sensor data from geographically distributed, heterogeneous sensors. A cloud-native ingestion architecture:
from dataclasses import dataclass
from datetime import datetime
from typing import Optional
import boto3
import json
@dataclass
class RadarObservation:
sensor_id: str
observation_time: str # ISO 8601 UTC
azimuth_deg: float
elevation_deg: float
range_km: float
range_rate_km_s: float
snr_db: float
covariance: list[list[float]] # 3x3 measurement covariance
object_id: Optional[str] = None # Assigned after correlation
def ingest_observation(obs: RadarObservation,
queue_url: str,
region: str = 'us-gov-east-1') -> str:
"""
Route observation to SQS queue for correlation processing.
Returns message ID for tracking.
"""
sqs = boto3.client('sqs', region_name=region)
msg = sqs.send_message(
QueueUrl=queue_url,
MessageBody=json.dumps({
'observation': obs.__dict__,
'ingested_at': datetime.utcnow().isoformat(),
'processing_state': 'PENDING_CORRELATION'
}),
MessageGroupId=obs.sensor_id, # FIFO queue by sensor
MessageAttributes={
'ObservationType': {
'StringValue': 'RADAR',
'DataType': 'String'
}
}
)
return msg['MessageId'] Orbital State Propagation
The Simplified General Perturbations 4 (SGP4) model is the standard for Earth-orbiting object propagation from Two-Line Element sets:
from skyfield.api import load, EarthSatellite
from skyfield.timelib import Time
import numpy as np
class CatalogObject:
def __init__(self, norad_id: int, name: str, tle_line1: str, tle_line2: str):
self.norad_id = norad_id
self.name = name
ts = load.timescale()
self.satellite = EarthSatellite(tle_line1, tle_line2, name, ts)
self._epoch = self.satellite.epoch
def propagate_to(self, utc_time: datetime) -> dict:
"""
Propagate to given time using SGP4.
Returns ECI position and velocity in km and km/s.
"""
ts = load.timescale()
t = ts.from_datetime(utc_time)
geocentric = self.satellite.at(t)
pos = geocentric.position.km
vel = geocentric.velocity.km_per_s
return {
'norad_id': self.norad_id,
'epoch': utc_time.isoformat(),
'position_eci_km': pos.tolist(),
'velocity_eci_km_s': vel.tolist(),
'age_days': (utc_time - self._epoch.utc_datetime()).total_seconds() / 86400
}
@property
def needs_refresh(self) -> bool:
"""TLE accuracy degrades over time - flag for refresh after threshold."""
ts = load.timescale()
age_days = ts.now() - self._epoch
return float(age_days) > 7.0 # Flag for TLE update after 7 days Conjunction Analysis
Conjunction analysis computes the probability of collision between pairs of objects:
from scipy.stats import multivariate_normal
import numpy as np
def compute_conjunction_probability(
primary_pos: np.ndarray, # ECI km
primary_cov: np.ndarray, # 3x3 position covariance
secondary_pos: np.ndarray,
secondary_cov: np.ndarray,
combined_hbr: float # Combined hard body radius in km
) -> float:
"""
Monte Carlo estimate of Pc (probability of collision).
For production, use Alfano or Foster analytic methods for efficiency.
"""
# Relative state
rel_pos = primary_pos - secondary_pos
rel_cov = primary_cov + secondary_cov
# Miss distance
miss_distance = np.linalg.norm(rel_pos)
if miss_distance > 10 * combined_hbr:
return 0.0 # Fast-reject for clearly non-conjunctions
# Simplified 2D probability in encounter plane
# (Production uses full 3D or encounter-plane reduction)
try:
rv = multivariate_normal(mean=rel_pos[:2], cov=rel_cov[:2, :2])
# Integrate within hard body radius circle
# This is simplified - production uses analytic methods
return float(rv.pdf(np.array([0, 0])) * np.pi * combined_hbr**2)
except Exception:
return float('nan') Alert Management and Dissemination
def evaluate_conjunction_alert(
primary_id: str,
secondary_id: str,
tca: datetime,
miss_distance_km: float,
probability_of_collision: float
) -> dict:
"""
Evaluate conjunction against alert thresholds and generate
Conjunction Data Message (CDM) per CCSDS standards.
"""
alert_level = 'GREEN'
if probability_of_collision > 1e-4 or miss_distance_km < 1.0:
alert_level = 'RED'
elif probability_of_collision > 1e-5 or miss_distance_km < 5.0:
alert_level = 'YELLOW'
return {
'cdm_version': '1.0',
'primary_object_id': primary_id,
'secondary_object_id': secondary_id,
'tca': tca.isoformat(),
'miss_distance_km': miss_distance_km,
'probability_of_collision': probability_of_collision,
'alert_level': alert_level,
'generated_at': datetime.utcnow().isoformat()
} See Rutagon's satellite telemetry cloud processing and Space Force acquisition reform for related program and architecture context.
Explore Rutagon's aerospace capabilities.
FAQ
What is the difference between Space Situational Awareness (SSA) and Space Domain Awareness (SDA)?
SSA historically referred to tracking and characterizing objects in the space environment — conjunction analysis, collision avoidance, and reentry prediction. SDA is a broader term adopted by Space Force that adds the characterization of spacecraft behavior, intent analysis, potential threat identification, and integration of space environment effects. SDA is SSA plus the intelligence dimension.
How are Two-Line Elements (TLEs) generated and distributed?
The Space Force 18th Space Control Squadron generates and maintains the publicly available space object catalog, including TLEs distributed through Space-Track.org. TLEs are generated from observations by the Space Surveillance Network (SSN) — a global network of radar and optical sensors. The public catalog covers objects approximately 10cm and larger in LEO. Higher-accuracy, more complete catalogs are maintained for classified purposes.
What programming languages are used in SDA systems?
Python is widely used for mission analysis, algorithm development, and data pipeline work — the astropy and skyfield libraries provide mature orbital mechanics foundations. C++ is used for latency-sensitive propagation and conjunction processing. Java and C# appear in legacy ground system software. Cloud-native SDA developments increasingly use Python for processing and React/TypeScript for operator interfaces.
How does the commercial SDA market interact with government programs?
Commercial SDA providers (LeoLabs, ExoAnalytic, Slingshot Aerospace) operate sensor networks and analytics platforms that supplement government SSN data. Space Force has contracts with commercial SSA providers to access commercial data. Under Space Policy Directive-3, civil conjunction alerts go through the Commerce Department's Office of Space Commerce (LeoLabs is a provider to this program), while military functions remain with Space Force.
What accuracy is required for conjunction analysis in low Earth orbit?
Useful conjunction analysis in LEO requires object state vector accuracy in the range of hundreds of meters to a few kilometers. Below this threshold, false positives (unnecessary avoidance maneuvers) become unacceptably frequent; above this threshold, genuine high-risk conjunctions may be missed. The accuracy depends on the quality and frequency of observations, the age of the TLE, and the accuracy of the propagation model used.