Schemas
The schemas module holds wire-format message types: the catalog/observation
interchange shapes and the CCSDS Navigation Data Messages.
CCSDS Navigation Data Messages
keplime parses and serializes three CCSDS message types in both the KVN
(KEY = value) and XML (NDM/XML) encodings, mapping each to and from keplime's
native types:
OMM— Orbit Mean-Elements Message (CCSDS 502.0-B). Round-trips losslessly to aTLEviaOMM.to_tle/OMM.from_tle. Carries the SGP4 / SGP4-XP mean elements and catalog metadata (OMMMetadata,OMMMeanElements,OMMTLEParameters).OEM— Orbit Ephemeris Message (CCSDS 502.0-B). Maps oneEphemerisper segment viaOEM.to_ephemerides/OEM.from_ephemeris, with optional covariance records (OEMSegment,OEMMetadata,OEMCovarianceRecord).CDM— Conjunction Data Message (CCSDS 508.0-B).CDM.from_conjunctionbuilds a standard-conformant message from a computed encounter (miss distance, RTN relative state, RTN object covariances); the object metadata (CDMObjectData,CDMRelativeMetadata,CDMODParameters,CDMAdditionalParameters) is then filled in before emit.
Each message exposes a uniform codec surface:
| Method | Purpose |
|---|---|
from_kvn(text) |
Parse the KVN encoding. |
from_xml(text) |
Parse the XML (NDM/XML) encoding. |
from_str_any(text) |
Parse either encoding, sniffing XML versus KVN. |
from_file(path) |
Read a file, sniffing the encoding by content. |
to_kvn() |
Serialize to KVN. |
to_xml() |
Serialize to XML. |
Units
In-memory structs hold keplime-native units (angles in radians, lengths in
km); CCSDS unit conversion (degrees, meters) happens only at the
read/write boundary. The shared ODM header is NDMHeader; CDM carries its
own CDMHeader and uses UTC for all epochs.
The CCSDS enums — MeanElementTheory, InterpolationMethod, CDMManeuverable,
CDMCovarianceMethod — are documented under Enums.
API reference
schemas
CDM
A CCSDS Conjunction Data Message.
Build the emit path with from_conjunction, customize the object metadata,
then to_kvn. Parse external CDMs with from_kvn / from_file.
Attributes:
| Name | Type | Description |
|---|---|---|
header |
CDMHeader
|
CDM header. |
relative_metadata |
CDMRelativeMetadata
|
Conjunction geometry and Pc. |
object1 |
CDMObjectData
|
Object 1 data. |
object2 |
CDMObjectData
|
Object 2 data. |
header
property
CDM header.
from_conjunction(header, tca, state1, state2, covariance1, covariance2, collision_probability=None)
staticmethod
Builds a CDM from a computed conjunction (the emit path).
Both states must be at TCA in the same inertial frame. The miss distance, relative speed, and object-1-RTN relative position/velocity are computed; each covariance is converted to RTN against its own object's state. Object metadata is filled with neutral defaults.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
header
|
CDMHeader
|
The CDM header. |
required |
tca
|
ModifiedJulianDate
|
Time of closest approach [UTC]. |
required |
state1
|
CartesianState
|
Object 1 state at TCA [inertial; km, km/s]. |
required |
state2
|
CartesianState
|
Object 2 state at TCA [same frame]. |
required |
covariance1
|
CovarianceMatrix
|
Object 1 covariance. |
required |
covariance2
|
CovarianceMatrix
|
Object 2 covariance. |
required |
collision_probability
|
float | None
|
Optional Pc to record. |
None
|
Returns:
| Type | Description |
|---|---|
CDM
|
A CDM ready for |
Raises:
| Type | Description |
|---|---|
ValueError
|
If the states are not in the same frame, a state lacks a velocity, a covariance cannot be rotated to RTN, or the frame has no CDM label. |
from_file(path)
staticmethod
Reads a CDM from a KVN file.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
path
|
str
|
Path to a KVN CDM file. |
required |
Returns:
| Type | Description |
|---|---|
CDM
|
The parsed CDM. |
Raises:
| Type | Description |
|---|---|
ValueError
|
If the file cannot be read or fails to parse. |
from_kvn(text)
staticmethod
Parses a CDM from its KVN text encoding.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
text
|
str
|
The CDM KVN document. |
required |
Returns:
| Type | Description |
|---|---|
CDM
|
The parsed CDM. |
Raises:
| Type | Description |
|---|---|
ValueError
|
On any syntax error, missing required keyword, bad epoch, unsupported frame, or inconsistent covariance. |
from_str_any(text)
staticmethod
Parses a CDM from either encoding, sniffing XML versus KVN.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
text
|
str
|
A CDM in XML or KVN. |
required |
Returns:
| Type | Description |
|---|---|
CDM
|
The parsed CDM. |
Raises:
| Type | Description |
|---|---|
ValueError
|
On any parse failure. |
from_xml(text)
staticmethod
Parses a CDM from its XML (NDM/XML) encoding.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
text
|
str
|
The CDM XML document. |
required |
Returns:
| Type | Description |
|---|---|
CDM
|
The parsed CDM. |
Raises:
| Type | Description |
|---|---|
ValueError
|
On malformed XML or any parse-contract violation. |
to_kvn()
Serializes this CDM to its KVN text encoding.
Returns:
| Type | Description |
|---|---|
str
|
The CDM as a KVN string (trailing newline). |
Raises:
| Type | Description |
|---|---|
ValueError
|
If an object's state frame has no CCSDS emit label or a covariance is not at least 6x6. |
to_xml()
Serializes this CDM to its XML (NDM/XML) encoding.
Returns:
| Type | Description |
|---|---|
str
|
The CDM as an XML string (with prolog, trailing newline). |
Raises:
| Type | Description |
|---|---|
ValueError
|
If an object's state frame has no CCSDS emit label or a covariance is not at least 6x6. |
CDMAdditionalParameters
CDM additional object-property parameters block (all optional; m-based).
Attributes:
| Name | Type | Description |
|---|---|---|
area_pc |
float | None
|
|
cd_area_over_mass |
float | None
|
|
cr_area_over_mass |
float | None
|
|
thrust_acceleration |
float | None
|
|
sedr |
float | None
|
|
__init__()
Creates an empty additional-parameters block; set fields as needed.
CDMHeader
CDM header block (all CDM epochs are UTC).
Attributes:
| Name | Type | Description |
|---|---|---|
comments |
list[str]
|
|
message_version |
str
|
|
creation_date |
ModifiedJulianDate
|
|
originator |
str
|
|
message_for |
str | None
|
|
message_id |
str
|
|
creation_date
property
CREATION_DATE [UTC].
message_version
property
CCSDS_CDM_VERS value, verbatim (e.g. "1.0").
__init__(message_version, creation_date, originator, message_id, comments=..., message_for=None)
Creates a CDM header.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
message_version
|
str
|
|
required |
creation_date
|
ModifiedJulianDate
|
|
required |
originator
|
str
|
|
required |
message_id
|
str
|
|
required |
comments
|
list[str]
|
Optional header comments (default empty). |
...
|
message_for
|
str | None
|
Optional |
None
|
CDMODParameters
CDM orbit-determination parameters block (all optional).
Attributes:
| Name | Type | Description |
|---|---|---|
time_lastob_start |
ModifiedJulianDate | None
|
|
time_lastob_end |
ModifiedJulianDate | None
|
|
recommended_od_span |
float | None
|
|
actual_od_span |
float | None
|
|
obs_available |
int | None
|
|
obs_used |
int | None
|
|
tracks_available |
int | None
|
|
tracks_used |
int | None
|
|
residuals_accepted |
float | None
|
|
weighted_rms |
float | None
|
|
__init__()
Creates an empty OD-parameters block; set fields as needed.
CDMObjectData
CDM per-object data: metadata, OD/additional parameters, state, covariance.
The state, covariance, and reference frame are set by
CDM.from_conjunction; the metadata fields are settable.
Attributes:
| Name | Type | Description |
|---|---|---|
object_designator |
str
|
|
catalog_name |
str
|
|
object_name |
str
|
|
international_designator |
str
|
|
object_type |
str | None
|
|
operator_organization |
str | None
|
|
ephemeris_name |
str
|
|
covariance_method |
CDMCovarianceMethod
|
|
maneuverable |
CDMManeuverable
|
|
reference_frame |
ReferenceFrame
|
|
od_parameters |
CDMODParameters | None
|
OD-parameters block. |
additional_parameters |
CDMAdditionalParameters | None
|
Additional block. |
state |
CartesianState
|
State at TCA [km, km/s]. |
covariance |
CovarianceMatrix
|
RTN (Relative) covariance [km**2]. |
covariance
property
RTN (Relative) covariance [km**2].
reference_frame
property
REF_FRAME of the state.
state
property
State at TCA [km, km/s].
CDMRelativeMetadata
CDM relative metadata: the conjunction geometry and Pc.
The geometry fields are computed by CDM.from_conjunction; the screening
and Pc-method fields are settable.
Attributes:
| Name | Type | Description |
|---|---|---|
comments |
list[str]
|
|
tca |
ModifiedJulianDate
|
|
miss_distance |
float
|
|
relative_speed |
float | None
|
|
collision_probability |
float | None
|
|
collision_probability_method |
str | None
|
|
miss_distance
property
MISS_DISTANCE [km].
relative_speed
property
RELATIVE_SPEED [km/s], or None.
tca
property
TCA [UTC].
NDMHeader
Common ODM header block shared by OEM and OMM messages.
CDM carries its own header. Construct one to supply to
OMM.from_tle. The ODM v3 optional fields
(message_id, classification) are None for v1/v2 messages.
Attributes:
| Name | Type | Description |
|---|---|---|
comments |
list[str]
|
|
message_version |
str
|
|
creation_date |
ModifiedJulianDate
|
|
originator |
str
|
|
message_id |
str | None
|
|
classification |
str | None
|
|
__init__(message_version, creation_date, originator, comments=..., message_id=None, classification=None)
Creates an ODM header.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
message_version
|
str
|
|
required |
creation_date
|
ModifiedJulianDate
|
|
required |
originator
|
str
|
|
required |
comments
|
list[str]
|
Optional header comments (default empty). |
...
|
message_id
|
str | None
|
Optional |
None
|
classification
|
str | None
|
Optional |
None
|
OEM
A CCSDS Orbit Ephemeris Message.
One or more segments, each a tabulated trajectory. Parse with from_kvn /
from_file, build from an Ephemeris with
from_ephemeris, and map each segment back to an Ephemeris with
to_ephemerides.
Attributes:
| Name | Type | Description |
|---|---|---|
header |
NDMHeader
|
Common ODM header. |
segments |
list[OEMSegment]
|
One or more ephemeris segments. |
header
property
Common ODM header.
segments
property
One or more ephemeris segments.
covariance_at_epoch(epoch)
Returns the covariance record nearest at-or-before epoch.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
epoch
|
ModifiedJulianDate
|
The query epoch. |
required |
Returns:
| Type | Description |
|---|---|
OEMCovarianceRecord | None
|
The nearest record at-or-before |
OEMCovarianceRecord | None
|
record is after it. |
from_ephemeris(ephemeris, frame, time_system, header, object_id)
staticmethod
Builds a single-segment OEM from an Ephemeris.
States are emitted verbatim, each converted from the ephemeris's native
TEME to frame (ITRF EOP-guarded). Acceleration columns are emitted
iff every state carries acceleration.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
ephemeris
|
Ephemeris
|
The source ephemeris (TEME). |
required |
frame
|
ReferenceFrame
|
Frame to express the emitted states in. |
required |
time_system
|
TimeSystem
|
Time system to tag the emitted epochs with. |
required |
header
|
NDMHeader
|
The ODM header to attach. |
required |
object_id
|
str
|
The international designator for |
required |
Returns:
| Type | Description |
|---|---|
OEM
|
A single-segment OEM. |
Raises:
| Type | Description |
|---|---|
ValueError
|
If the ephemeris has no states, |
from_file(path)
staticmethod
Reads an OEM from a KVN file.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
path
|
str
|
Path to a KVN OEM file. |
required |
Returns:
| Type | Description |
|---|---|
OEM
|
The parsed OEM. |
Raises:
| Type | Description |
|---|---|
ValueError
|
If the file cannot be read or fails to parse. |
from_kvn(text)
staticmethod
Parses an OEM from its KVN text encoding.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
text
|
str
|
The OEM KVN document. |
required |
Returns:
| Type | Description |
|---|---|
OEM
|
The parsed OEM. |
Raises:
| Type | Description |
|---|---|
ValueError
|
On any syntax error, missing required keyword, bad epoch or state row, or unsupported frame / time system. |
from_str_any(text)
staticmethod
Parses an OEM from either encoding, sniffing XML versus KVN.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
text
|
str
|
An OEM in XML or KVN. |
required |
Returns:
| Type | Description |
|---|---|
OEM
|
The parsed OEM. |
Raises:
| Type | Description |
|---|---|
ValueError
|
On any parse failure. |
from_xml(text)
staticmethod
Parses an OEM from its XML (NDM/XML) encoding.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
text
|
str
|
The OEM XML document. |
required |
Returns:
| Type | Description |
|---|---|
OEM
|
The parsed OEM. |
Raises:
| Type | Description |
|---|---|
ValueError
|
On malformed XML or any parse-contract violation. |
to_ephemerides()
Maps each segment to an Ephemeris (states converted to TEME).
Returns:
| Type | Description |
|---|---|
list[Ephemeris]
|
One Ephemeris per segment, in order. |
Raises:
| Type | Description |
|---|---|
ValueError
|
If a segment's center is not EARTH, a state cannot be converted to TEME (including ITRF epochs outside EOP coverage), or a segment has no states. |
to_kvn()
Serializes this OEM to its KVN text encoding.
Returns:
| Type | Description |
|---|---|
str
|
The OEM as a KVN string (trailing newline). |
Raises:
| Type | Description |
|---|---|
ValueError
|
If a segment or covariance frame has no CCSDS emit label. |
to_xml()
Serializes this OEM to its XML (NDM/XML) encoding.
Returns:
| Type | Description |
|---|---|
str
|
The OEM as an XML string (with prolog, trailing newline). |
Raises:
| Type | Description |
|---|---|
ValueError
|
If a segment or covariance frame has no CCSDS emit label. |
OEMCovarianceRecord
One OEM covariance record: a 6x6 covariance at an epoch.
Attributes:
| Name | Type | Description |
|---|---|---|
epoch |
ModifiedJulianDate
|
The epoch the covariance applies at. |
covariance |
CovarianceMatrix
|
The 6x6 covariance [km-based units]. |
covariance
property
The 6x6 covariance [km-based units].
epoch
property
The epoch the covariance applies at.
OEMMetadata
OEM segment metadata block.
Attributes:
| Name | Type | Description |
|---|---|---|
comments |
list[str]
|
|
object_name |
str
|
|
object_id |
str
|
|
center_name |
str
|
|
reference_frame |
ReferenceFrame
|
|
ref_frame_epoch |
ModifiedJulianDate | None
|
|
time_system |
TimeSystem
|
|
start_time |
ModifiedJulianDate
|
|
useable_start_time |
ModifiedJulianDate | None
|
|
useable_stop_time |
ModifiedJulianDate | None
|
|
stop_time |
ModifiedJulianDate
|
|
interpolation |
tuple[InterpolationMethod, int] | None
|
|
center_name
property
CENTER_NAME; only EARTH maps to an Ephemeris.
comments
property
COMMENT lines in the segment.
interpolation
property
INTERPOLATION method and INTERPOLATION_DEGREE, or None.
object_id
property
OBJECT_ID.
object_name
property
OBJECT_NAME.
ref_frame_epoch
property
REF_FRAME_EPOCH, or None.
reference_frame
property
REF_FRAME of the states.
start_time
property
START_TIME.
stop_time
property
STOP_TIME.
time_system
property
TIME_SYSTEM.
useable_start_time
property
USEABLE_START_TIME, or None.
useable_stop_time
property
USEABLE_STOP_TIME, or None.
OEMSegment
One OEM segment: metadata, tabulated states, and covariance records.
Attributes:
| Name | Type | Description |
|---|---|---|
metadata |
OEMMetadata
|
Segment metadata. |
states |
list[CartesianState]
|
Tabulated states in the segment's frame. |
covariance_records |
list[OEMCovarianceRecord]
|
Covariance records. |
covariance_records
property
Covariance records, in epoch order.
metadata
property
Segment metadata.
states
property
Tabulated states in the segment's frame [km, km/s].
OMM
A CCSDS Orbit Mean-Elements Message.
Carries one set of mean orbital elements (the SGP4 elements a TLE encodes)
plus catalog metadata. Parse with from_kvn / from_file, build from a
TLE with from_tle, and convert back with
to_tle. Angles in the mean-element block are radians; MEAN_MOTION
stays in rev/day.
Attributes:
| Name | Type | Description |
|---|---|---|
header |
NDMHeader
|
Common ODM header. |
metadata |
OMMMetadata
|
Object identity, frame, time system, theory. |
mean_elements |
OMMMeanElements
|
Mean orbital elements at epoch. |
tle_parameters |
OMMTLEParameters | None
|
SGP4/SGP4-XP catalog and force-model parameters, when present. |
covariance |
CovarianceMatrix | None
|
Optional ODM covariance block. |
user_defined |
list[tuple[str, str]]
|
|
covariance
property
Optional ODM covariance block.
header
property
Common ODM header.
mean_elements
property
Mean orbital elements at epoch.
metadata
property
Object identity, frame, time system, theory.
tle_parameters
property
SGP4/SGP4-XP catalog and force-model parameters, when present.
user_defined
property
USER_DEFINED_* keys preserved verbatim.
from_file(path)
staticmethod
Reads an OMM from a KVN file.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
path
|
str
|
Path to a KVN OMM file. |
required |
Returns:
| Type | Description |
|---|---|
OMM
|
The parsed OMM. |
Raises:
| Type | Description |
|---|---|
ValueError
|
If the file cannot be read or fails to parse. |
from_kvn(text)
staticmethod
Parses an OMM from its KVN text encoding.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
text
|
str
|
The OMM KVN document. |
required |
Returns:
| Type | Description |
|---|---|
OMM
|
The parsed OMM. |
Raises:
| Type | Description |
|---|---|
ValueError
|
On any syntax error, unsupported version, missing required keyword, unit mismatch, bad epoch, or unsupported frame / time system / mean-element theory. |
from_str_any(text)
staticmethod
Parses an OMM from either encoding, sniffing XML versus KVN.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
text
|
str
|
An OMM in XML or KVN. |
required |
Returns:
| Type | Description |
|---|---|
OMM
|
The parsed OMM. |
Raises:
| Type | Description |
|---|---|
ValueError
|
On any parse failure. |
from_tle(tle, header)
staticmethod
from_xml(text)
staticmethod
Parses an OMM from its XML (NDM/XML) encoding.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
text
|
str
|
The OMM XML document. |
required |
Returns:
| Type | Description |
|---|---|
OMM
|
The parsed OMM. |
Raises:
| Type | Description |
|---|---|
ValueError
|
On malformed XML or any parse-contract violation. |
to_kvn()
Serializes this OMM to its KVN text encoding.
Returns:
| Type | Description |
|---|---|
str
|
The OMM as a KVN string (trailing newline). |
Raises:
| Type | Description |
|---|---|
ValueError
|
If the metadata or covariance frame has no CCSDS emit label. |
to_tle()
Converts this OMM to a NORAD TLE.
Returns:
| Type | Description |
|---|---|
TLE
|
A TLE at the OMM epoch in TEME. |
Raises:
| Type | Description |
|---|---|
ValueError
|
If |
to_xml()
Serializes this OMM to its XML (NDM/XML) encoding.
Returns:
| Type | Description |
|---|---|
str
|
The OMM as an XML string (with prolog, trailing newline). |
Raises:
| Type | Description |
|---|---|
ValueError
|
If the metadata or covariance frame has no CCSDS emit label. |
OMMMeanElements
OMM mean orbital elements at epoch.
Exactly one of mean_motion / semi_major_axis is set. Angles are
radians; mean_motion is rev/day.
Attributes:
| Name | Type | Description |
|---|---|---|
epoch |
ModifiedJulianDate
|
|
mean_motion |
float | None
|
|
semi_major_axis |
float | None
|
|
eccentricity |
float
|
|
inclination |
float
|
|
ascending_node |
float
|
|
argument_of_periapsis |
float
|
|
mean_anomaly |
float
|
|
gm |
float | None
|
|
argument_of_periapsis
property
ARG_OF_PERICENTER [rad].
ascending_node
property
RA_OF_ASC_NODE [rad].
eccentricity
property
ECCENTRICITY [dimensionless; 0..1).
epoch
property
EPOCH in the metadata time system.
gm
property
GM [km3/s2], or None.
inclination
property
INCLINATION [rad].
mean_anomaly
property
MEAN_ANOMALY [rad].
mean_motion
property
MEAN_MOTION [rev/day], or None.
semi_major_axis
property
SEMI_MAJOR_AXIS [km], or None.
OMMMetadata
OMM metadata block: object identity, frame, time system, theory.
Attributes:
| Name | Type | Description |
|---|---|---|
comments |
list[str]
|
|
object_name |
str
|
|
object_id |
str
|
|
center_name |
str
|
|
reference_frame |
ReferenceFrame
|
|
time_system |
TimeSystem
|
|
mean_element_theory |
MeanElementTheory
|
|
center_name
property
CENTER_NAME; only EARTH converts to a TLE.
comments
property
COMMENT lines in the metadata block.
mean_element_theory
property
MEAN_ELEMENT_THEORY.
object_id
property
OBJECT_ID (COSPAR international designator).
object_name
property
OBJECT_NAME.
reference_frame
property
REF_FRAME; TEME for SGP4.
time_system
property
TIME_SYSTEM.
OMMTLEParameters
OMM optional SGP4/SGP4-XP catalog and force-model parameters.
SGP4 uses bstar; SGP4-XP uses bterm and agom. Per ADR 0020,
mean_motion_dot/mean_motion_ddot are round-trip only — propagation
does not read them for GP/XP.
Attributes:
| Name | Type | Description |
|---|---|---|
ephemeris_type |
int
|
|
classification |
Classification
|
|
norad_cat_id |
int
|
|
element_set_no |
int
|
|
rev_at_epoch |
int
|
|
bstar |
float | None
|
|
bterm |
float | None
|
|
mean_motion_dot |
float
|
|
mean_motion_ddot |
float | None
|
|
agom |
float | None
|
|
agom
property
AGOM [m**2/kg] — SGP4-XP only, or None.
bstar
property
BSTAR [1/Earth-radii] — SGP4 drag term, or None.
bterm
property
BTERM [m**2/kg] — SGP4-XP drag term, or None.
classification
property
CLASSIFICATION_TYPE (U/C/S).
element_set_no
property
ELEMENT_SET_NO.
ephemeris_type
property
EPHEMERIS_TYPE (0/2 SGP4, 4 SGP4-XP).
mean_motion_ddot
property
MEAN_MOTION_DDOT [rev/day**3] — SGP4 only, or None.
mean_motion_dot
property
MEAN_MOTION_DOT [rev/day**2]; round-trip only.
norad_cat_id
property
NORAD_CAT_ID.
rev_at_epoch
property
REV_AT_EPOCH.
audit_citra_doa(citra_elsets, citra_observations, latest_span, full_span, expected_limits=...)
Summarize direction-of-arrival (TDOA) residual stats per DOA antenna.
Grouping, dedupe, the count fields, the per-sensor windowing rule,
and expected_limits semantics match
audit_citra_optical. Per-sensor keys are the DOA
primary_antenna_id. Per-sensor stat-block fields:
tdoa_bias / tdoa_noise [s] and ingest_delay_bias /
ingest_delay_noise [s]. angular / angular_rate are not
exposed at this level because DOA observations don't carry
pointing data; the unified antenna block
(audit_citra_sensors) surfaces them when a sister radar
observation provides them.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
citra_elsets
|
list[dict[str, object]]
|
List of CITRA elset dicts (same per-element shape
as the elset arg of |
required |
citra_observations
|
list[dict[str, object]]
|
List of CITRA DOA observation dicts. |
required |
latest_span
|
TimeSpan
|
Width of the short window applied to sensors that
appear in |
required |
full_span
|
TimeSpan
|
Minimum calibration history required for sensors
that do not appear in |
required |
expected_limits
|
list[dict[str, object]] | None
|
Optional list of per-sensor limit dicts. See
|
...
|
Returns:
| Type | Description |
|---|---|
list[dict[str, object]]
|
List of per-sensor stat blocks (one per DOA antenna that |
list[dict[str, object]]
|
produced data and met the calibration minimum, or that is listed |
list[dict[str, object]]
|
in |
list[dict[str, object]]
|
documented on |
list[dict[str, object]]
|
measurement fields: |
list[dict[str, object]]
|
|
list[dict[str, object]]
|
fields are not included because DOA observations do not carry |
list[dict[str, object]]
|
pointing data. |
Raises:
| Type | Description |
|---|---|
ValueError
|
|
Per-satellite construction, ephemeris caching, or residual
computation failures are logged at WARN and the offending
satellite is dropped from the audit; they do not raise.
audit_citra_optical(citra_elsets, citra_observations, latest_span, full_span, expected_limits=...)
Summarize optical residual stats per telescope.
Each optical observation is attributed to an elset by matching the
observation's satellite_id to the elset's satellite_id. Input
elsets that share a satellite_id are deduped by first
occurrence; later duplicates are silently dropped. Each observation
also carries a sensor identifier (telescope_id for optical), used
to break the residual stats out per sensor. Observations whose
satellite_id is None are reported as
uncorrelated_observation_count under the sensor that produced
them and contribute no residual samples. A sensor that produces no
usable bias / noise values across any field — e.g., uncorrelated
tracks only, with no upstream creation_epoch to populate
ingest_delay — is omitted from the output entirely.
Per-sensor window selection driven by expected_limits:
- Sensors with an entry in
expected_limitsare evaluated over the short window[S_last - latest_span, S_last], and the per-sensorstatusis checked against the supplied bias / noise bounds.latest_spanis a cap — even a newly-active sensor with little data still gets a block. - Sensors without an entry in
expected_limits(the un-characterized ones) are calibrated over every sample the sensor has produced.full_spanhere is a minimum required calibration history: if the sensor'sS_last - S_firstspan is less thanfull_span, the sensor is omitted from the output entirely — there isn't enough baseline to calibrate against. There is no cap on the long-baseline path: a 36-hour query against a 12-hour minimum runs over the full 36 hours.
S_last is the sensor's own latest sample, so a sensor whose
data ends earlier than another's still gets evaluated against
its own recent activity.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
citra_elsets
|
list[dict[str, object]]
|
List of CITRA elset dicts (same per-element shape as
the elset arg of |
required |
citra_observations
|
list[dict[str, object]]
|
List of CITRA optical observation dicts. |
required |
latest_span
|
TimeSpan
|
Width of the short window applied to sensors
that appear in |
required |
full_span
|
TimeSpan
|
Minimum calibration history required for
sensors that do not appear in |
required |
expected_limits
|
list[dict[str, object]] | None
|
Optional list of per-sensor limit dicts. Each
entry is |
...
|
Returns:
| Type | Description |
|---|---|
list[dict[str, object]]
|
List of per-sensor stat blocks ( |
list[dict[str, object]]
|
block contains: |
list[dict[str, object]]
|
|
list[dict[str, object]]
|
|
list[dict[str, object]]
|
|
list[dict[str, object]]
|
|
list[dict[str, object]]
|
|
list[dict[str, object]]
|
|
list[dict[str, object]]
|
|
list[dict[str, object]]
|
|
list[dict[str, object]]
|
|
list[dict[str, object]]
|
|
list[dict[str, object]]
|
Both bounds use |
list[dict[str, object]]
|
|
Raises:
| Type | Description |
|---|---|
ValueError
|
|
Per-satellite construction, ephemeris caching, or residual
computation failures are logged at WARN and the offending
satellite is dropped from the audit; they do not raise.
audit_citra_radar(citra_elsets, citra_observations, latest_span, full_span, expected_limits=...)
Summarize radar residual stats per radar antenna.
Grouping, dedupe, the count fields, the per-sensor windowing rule,
and expected_limits semantics match
audit_citra_optical. Per-sensor keys are the radar
antenna_id. Per-sensor stat-block fields:
range_bias / range_noise [km], range_rate_bias /
range_rate_noise [km/s], angular_bias / angular_noise
[deg], angular_rate_bias / angular_rate_noise [deg/s], and
ingest_delay_bias / ingest_delay_noise [s]. Radar
observations may carry RA/Dec independently of monostatic vs.
bistatic geometry; the angular pools draw from any radar
observation that has them. Observations whose measurement field is
missing still count toward correlated_observation_count but
contribute no samples to that field's pool.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
citra_elsets
|
list[dict[str, object]]
|
List of CITRA elset dicts (same per-element shape
as the elset arg of |
required |
citra_observations
|
list[dict[str, object]]
|
List of CITRA radar observation dicts. |
required |
latest_span
|
TimeSpan
|
Width of the short window applied to sensors that
appear in |
required |
full_span
|
TimeSpan
|
Minimum calibration history required for sensors
that do not appear in |
required |
expected_limits
|
list[dict[str, object]] | None
|
Optional list of per-sensor limit dicts. See
|
...
|
Returns:
| Type | Description |
|---|---|
list[dict[str, object]]
|
List of per-sensor stat blocks (one per radar antenna that |
list[dict[str, object]]
|
produced data and met the calibration minimum, or that is listed |
list[dict[str, object]]
|
in |
list[dict[str, object]]
|
documented on |
list[dict[str, object]]
|
measurement fields: |
list[dict[str, object]]
|
|
list[dict[str, object]]
|
/ |
list[dict[str, object]]
|
|
list[dict[str, object]]
|
|
Raises:
| Type | Description |
|---|---|
ValueError
|
|
Per-satellite construction, ephemeris caching, or residual
computation failures are logged at WARN and the offending
satellite is dropped from the audit; they do not raise.
audit_citra_sensors(citra_elsets, sensors, observations, latest_span, full_span, expected_limits=...)
Audit a fleet of CITRA sensors per sensor.
Unified entry point. Optical observations are aggregated per
telescope_id (each block tagged "sensor_type":
"telescope"); radar and DOA observations are aggregated per
antenna identifier (antenna_id for radar,
primary_antenna_id for DOA) and each block tagged
"sensor_type": "antenna". Telescope and antenna blocks are
returned in a single flat list — split downstream by the
sensor_type key if you need per-type views.
Only sensors that produced at least one usable bias / noise value
appear in the output. Catalog sensors listed in sensors but with
no observations are omitted regardless of whether they appear in
expected_limits, and sensors whose observations all
fail to populate a bias / noise pool (e.g., uncorrelated tracks
only, with no upstream creation_epoch) are likewise omitted.
Callers that need to detect silent or content-free sensors must
cross-reference the input catalog themselves. Per-sensor windowing
and expected_limits semantics match audit_citra_optical.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
citra_elsets
|
list[dict[str, object]]
|
List of CITRA elset dicts. |
required |
sensors
|
dict[str, list[dict[str, object]]]
|
|
required |
observations
|
dict[str, list[dict[str, object]]]
|
|
required |
latest_span
|
TimeSpan
|
Width of the short window applied to sensors
that appear in |
required |
full_span
|
TimeSpan
|
Minimum calibration history required for
sensors that do not appear in |
required |
expected_limits
|
list[dict[str, object]] | None
|
Optional list of per-sensor limit dicts. Each
entry is |
...
|
Returns:
| Type | Description |
|---|---|
list[dict[str, object]]
|
Flat list of per-sensor stat blocks |
list[dict[str, object]]
|
(``[{"id": |
list[dict[str, object]]
|
"sensor_type": "telescope" | "antenna", "audit_type": |
list[dict[str, object]]
|
"trend" | "baseline", ...}, ...]``). |
list[dict[str, object]]
|
Telescope blocks carry the optical fields documented on |
list[dict[str, object]]
|
|
list[dict[str, object]]
|
of radar + DOA fields ( |
list[dict[str, object]]
|
|
list[dict[str, object]]
|
|
list[dict[str, object]]
|
pair, plus |
Raises:
| Type | Description |
|---|---|
ValueError
|
|
Per-satellite construction, ephemeris caching, or residual
computation failures are logged at WARN and the offending
satellite is dropped from the audit; they do not raise.
citra_data_to_observations(citra_observations, calibrations=..., telescope_limits=..., antenna_limits=...)
Convert a CITRA observation envelope into keplime observations.
Records are converted and returned in the canonical order optical, radar, doa. Measurement noise is resolved per observation in two stages: a per-sensor calibration override, then a per-sensor-type limit clamp.
When calibrations is supplied, each converted observation whose sensor
id matches a calibration's sensor_id has its present noise fields
replaced (angular fields given in degrees, converted to radians). The
override is purely per-sensor, matched by id — there is no per-modality
logic. An observation whose sensor has no matching calibration keeps the
noise reported on its record, so to leave a sensor's noise untouched (for
example a trusted telescope) simply omit it from calibrations.
The resolved noise is then bounded to the supplied
SensorCalibrationLimits for the
observation's sensor type — optical observations use telescope_limits,
radar and DOA observations use antenna_limits. Clamping runs for every
observation whether or not a calibration matched, so unphysical record noise
(e.g. milli-arcsecond optical, kilometre-scale range) is corrected even with
no calibration. A None limits argument skips clamping for that sensor
type.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
citra_observations
|
dict[str, list[dict[str, object]]]
|
|
required |
calibrations
|
list[dict[str, object]] | None
|
Optional list of per-sensor noise-override mappings. Each
must carry |
...
|
telescope_limits
|
SensorCalibrationLimits | None
|
Optional
|
...
|
antenna_limits
|
SensorCalibrationLimits | None
|
Optional
|
...
|
Returns:
| Type | Description |
|---|---|
list[Observation]
|
Observations in the TEME frame, in optical -> radar -> doa order. |
Raises:
| Type | Description |
|---|---|
ValueError
|
If a record is missing a required field, an epoch cannot be parsed, or a sensor location cannot be propagated to its epoch. |
dnd_postgres_df_to_observations(dataframe)
Converts DND PostgreSQL observation rows into keplime observations.
The input is expected to be the Polars DataFrame returned by
pl.read_database_uri for the DND observation query. Required columns
are id, epoch, sensor_id, sensor_latitude,
sensor_longitude, and sensor_altitude. Optional columns are
right_ascension, declination, range, visual_magnitude,
radar_cross_section, provider_id, and dnd_id.
Angles and sensor geodetic coordinates are interpreted in radians. Range
and sensor altitude are interpreted in km. sensor_id is stored on
Observation.sensor.id, provider_id is stored on
Observation.expected_satellite_id, dnd_id is stored on
Observation.observed_satellite_id, and radar_cross_section is
stored on Observation.radar_cross_section. Converted sensors use the
package default measurement noise constants: angular observations receive
0.0005 deg (stored in radians), range observations receive 0.1 km, and
absent measurement types leave their corresponding noise fields unset.
Polars datetime epochs are read from their Arrow-backed integer storage
and interpreted as UTC Unix timestamps. String epochs are parsed directly.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
dataframe
|
Any
|
Polars dataframe returned by the DND PostgreSQL query. |
required |
Returns:
| Type | Description |
|---|---|
list[Observation]
|
Converted |
list[Observation]
|
input row order. |
Raises:
| Type | Description |
|---|---|
TypeError
|
If |
ValueError
|
If a row is missing a required column, a required value is null, an epoch cannot be parsed, or sensor coordinates cannot be propagated. |
dnd_postgres_elset_df_to_constellation(dataframe, start, end, step, purge_on_fail=..., reference_frame=...)
Builds a constellation with stitched ephemeris from a DND elset query.
The input is a Polars DataFrame with the required columns dnd_id,
elset_line_1, and elset_line_2, plus an optional name column.
Rows are grouped by dnd_id (each dnd_id becomes one satellite);
elset_line_1 / elset_line_2 are parsed as a two-line element set and
the epoch is read from the TLE itself. When present, name (taken to be
constant per dnd_id) sets each satellite's human-readable name.
For a satellite with a single element set the ephemeris is a plain SGP4 arc
over [start, end]. For a satellite with multiple element sets, one arc
is propagated per set across the span between consecutive epochs and the
arcs are joined at their closest-approach crossovers (see
Ephemeris.stitch), then resampled
onto the uniform [start, end, step] grid so every satellite in the
returned constellation shares the same epoch lattice. Each returned
satellite is keyed by its dnd_id and carries the freshest element set as
its TLE metadata.
Element sets are de-duplicated by epoch (records within 1 ms collapse to the
latest), and only the sets relevant to [start, end] are propagated.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
dataframe
|
Any
|
Polars dataframe with required |
required |
start
|
ModifiedJulianDate
|
Start of the ephemeris window. |
required |
end
|
ModifiedJulianDate
|
End of the ephemeris window. |
required |
step
|
TimeSpan
|
Propagation / resampling step. |
required |
purge_on_fail
|
bool
|
When |
...
|
reference_frame
|
ReferenceFrame | None
|
Frame for the cached states; defaults to TEME. |
...
|
Returns:
| Type | Description |
|---|---|
Constellation
|
One |
Constellation
|
|
Constellation
|
ephemeris over |
Raises:
| Type | Description |
|---|---|
TypeError
|
If |
ValueError
|
If a required column is missing, a value is null, an element
set cannot be parsed, or (when |
get_citra_residuals(citra_elset, citra_observations)
Compute citra-format residuals for a batch of citra observations.
Returns one dict per input observation (in input order: optical, then radar,
then doa). Each dict carries identifiers (satellite_id,
observation_id, elset_id, elset_username,
elset_user_group_name, review_status), the source observation
epoch (echoed from input), the residual total_error
(cross-line-of-sight, km), the type
("optical" / "radar" / "doa"), and the residual numbers
(range km, range_rate km/s, right_ascension /
declination / right_ascension_rate / declination_rate in
degrees, tdoa s, fdoa Hz). visual_magnitude is populated
only for optical entries.
Note: elset_username and elset_user_group_name are populated from
the citra elset dict's user_id and user_group_id fields (UUID
strings). If you need resolved human-readable names, do that join in
your own DB after this call.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
citra_elset
|
dict[str, object]
|
CITRA elset dict. Must carry at minimum
|
required |
citra_observations
|
dict[str, list[dict[str, object]]]
|
|
required |
Returns:
| Type | Description |
|---|---|
list[dict[str, object]]
|
One residual dict per input observation, in input order |
list[dict[str, object]]
|
(optical, then radar, then DOA). Each dict carries the identifier |
list[dict[str, object]]
|
and residual fields described above. |
Raises:
| Type | Description |
|---|---|
ValueError
|
If a CITRA record fails to parse, the satellite cannot be constructed from the elset, or residual computation fails. |