Creating OMMs
An Orbit Mean-Elements Message (OMM) is represented by the OrbitMeanElementsMessage type. Although this structure follows the nested hierarchy defined by the CCSDS standard (header, metadata, and data), we can create a complete message using a single keyword constructor. It takes care of assembling the internal sections for us.
OrbitMeanElementsMessage(; kwargs...) -> OrbitMeanElementsMessageDate Fields
The fields creation_date, epoch, and ref_frame_epoch must be provided as NanoDate objects so that the message can retain the sub-second precision usually present in orbit data. We can build a NanoDate from a string or from a Dates.DateTime:
julia> using NanoDatesjulia> NanoDate("2025-12-30T18:12:04.533984")2025-12-30T18:12:04.533984julia> NanoDate(DateTime(2025, 12, 30, 18, 12, 4))2025-12-30T18:12:04
Minimal Example
The keyword constructor requires the mandatory fields defined by the standard: the message originator, the object identification, the reference frame and time system, and the mean Keplerian elements. The following example creates the OMM for the Amazonia 1 satellite:
julia> omm = OrbitMeanElementsMessage(; # == Header ======================================================== creation_date = NanoDate("2025-12-30T23:36:37"), originator = "18 SPCS", # == Metadata ====================================================== object_name = "AMAZONIA 1", object_id = "2021-015A", center_name = "EARTH", ref_frame = "TEME", time_system = "UTC", mean_element_theory = "SGP4", # == Mean Keplerian Elements ======================================= epoch = NanoDate("2025-12-30T18:12:04.533984"), mean_motion = 14.40772474, eccentricity = 0.00011240, inclination = 98.3721, raan = 75.0877, arg_of_pericenter = 97.3772, mean_anomaly = 262.7545, )OrbitMeanElementsMessage: ├─ Header │ Creation Date : 2025-12-30T23:36:37 │ Originator : 18 SPCS ├─ Metadata │ Object Name : AMAZONIA 1 │ Object ID : 2021-015A │ Center Name : EARTH │ Ref. Frame : TEME │ Time System : UTC │ Mean Element Theory : SGP4 └─ Data └─ Mean Keplerian Elements Epoch : 2025-12-30T18:12:04.533984 Mean Motion : 14.40772474 rev/day Eccentricity : 0.0001124 Inclination : 98.3721° RA of Asc. Node : 75.0877° Arg. of Pericenter : 97.3772° Mean Anomaly : 262.7545°
The mean elements section requires either mean_motion or semi_major_axis. All angular quantities (inclination, raan, arg_of_pericenter, and mean_anomaly) are expressed in degrees, following the CCSDS 502.0-B-3 convention.
Adding Optional Sections
The OMM standard defines several optional sections. They can be populated by passing the corresponding keywords. For example, we can add the TLE-related parameters and some spacecraft data:
julia> omm = OrbitMeanElementsMessage(; creation_date = NanoDate("2025-12-30T23:36:37"), originator = "18 SPCS", object_name = "AMAZONIA 1", object_id = "2021-015A", center_name = "EARTH", ref_frame = "TEME", time_system = "UTC", mean_element_theory = "SGP4", epoch = NanoDate("2025-12-30T18:12:04.533984"), mean_motion = 14.40772474, eccentricity = 0.00011240, inclination = 98.3721, raan = 75.0877, arg_of_pericenter = 97.3772, mean_anomaly = 262.7545, # == Spacecraft Data =============================================== mass = 640.0, drag_area = 8.5, drag_coeff = 2.2, # == TLE-Related Parameters ======================================== norad_cat_id = 47699, classification_type = 'U', element_set_number = 999, rev_at_epoch = 25439, bstar = 0.0001533, mean_motion_dot = 0.00000447, mean_motion_ddot = 0.0, # == User-Defined Parameters ======================================= user_defined_parameters = [ "COUNTRY_CODE" => "BRAZ", "LAUNCH_DATE" => "2021-02-28", ], )OrbitMeanElementsMessage: ├─ Header │ Creation Date : 2025-12-30T23:36:37 │ Originator : 18 SPCS ├─ Metadata │ Object Name : AMAZONIA 1 │ Object ID : 2021-015A │ Center Name : EARTH │ Ref. Frame : TEME │ Time System : UTC │ Mean Element Theory : SGP4 └─ Data ├─ Mean Keplerian Elements │ Epoch : 2025-12-30T18:12:04.533984 │ Mean Motion : 14.40772474 rev/day │ Eccentricity : 0.0001124 │ Inclination : 98.3721° │ RA of Asc. Node : 75.0877° │ Arg. of Pericenter : 97.3772° │ Mean Anomaly : 262.7545° ├─ Spacecraft Parameters │ Mass : 640.0 kg │ Drag Area : 8.5 m² │ Drag Coefficient : 2.2 ├─ TLE Related Parameters │ Classification Type : U │ NORAD Cat ID : 47699 │ Element Set Number : 999 │ Rev at Epoch : 25439 │ B* : 0.0001533 1/ER │ ∂(Mean Motion)/∂t : 4.47e-6 rev/day² │ ∂²(Mean Motion)/∂t² : 0.0 rev/day³ └─ User-Defined Parameters COUNTRY_CODE : BRAZ LAUNCH_DATE : 2021-02-28
Building the Sections Individually
The sections can also be created one at a time with the keyword constructors of OmmHeader, OmmMetadata, and OmmData, whose keywords are the section fields, and then assembled into the message. This form is convenient when the sections come from different sources or are reused across messages:
julia> header = OmmHeader(; creation_date = NanoDate("2025-12-30T23:36:37"), originator = "18 SPCS", )OmmHeader(String[], nothing, 2025-12-30T23:36:37, "18 SPCS", nothing)julia> metadata = OmmMetadata(; object_name = "AMAZONIA 1", object_id = "2021-015A", center_name = "EARTH", ref_frame = "TEME", time_system = "UTC", mean_element_theory = "SGP4", )OmmMetadata(String[], "AMAZONIA 1", "2021-015A", "EARTH", "TEME", nothing, "UTC", "SGP4")julia> data = OmmData(; epoch = NanoDate("2025-12-30T18:12:04.533984"), mean_motion = 14.40772474, eccentricity = 0.00011240, inclination = 98.3721, raan = 75.0877, arg_of_pericenter = 97.3772, mean_anomaly = 262.7545, )OmmData(String[], String[], 2025-12-30T18:12:04.533984, nothing, 14.40772474, 0.0001124, 98.3721, 75.0877, 97.3772, 262.7545, nothing, String[], nothing, nothing, nothing, nothing, nothing, String[], nothing, nothing, nothing, nothing, nothing, nothing, nothing, nothing, nothing, nothing, nothing, Pair{String, String}[])julia> omm = OrbitMeanElementsMessage(header, metadata, data)OrbitMeanElementsMessage: ├─ Header │ Creation Date : 2025-12-30T23:36:37 │ Originator : 18 SPCS ├─ Metadata │ Object Name : AMAZONIA 1 │ Object ID : 2021-015A │ Center Name : EARTH │ Ref. Frame : TEME │ Time System : UTC │ Mean Element Theory : SGP4 └─ Data └─ Mean Keplerian Elements Epoch : 2025-12-30T18:12:04.533984 Mean Motion : 14.40772474 rev/day Eccentricity : 0.0001124 Inclination : 98.3721° RA of Asc. Node : 75.0877° Arg. of Pericenter : 97.3772° Mean Anomaly : 262.7545°
The rules relating the fields (for example, exactly one of semi_major_axis and mean_motion) are checked when the message is assembled, so an invalid section is rejected at that point. Each section also has a copy constructor that overrides selected fields, e.g. OmmData(data; mean_motion = 14.5).
The type name is long, so the package exports the alias OMM, which can be used wherever OrbitMeanElementsMessage is expected:
julia> OMM === OrbitMeanElementsMessagetrue
Covariance Matrix
The covariance matrix section, OmmCovarianceMatrix, stores the 21 elements of the lower triangle with their CCSDS names (cx_x, cy_x, etc.). It can be created from a 6×6 matrix whose rows and columns are ordered as (x, y, z, ẋ, ẏ, ż), and the full matrix is recovered with Matrix or SMatrix:
julia> using StaticArraysjulia> matrix = [i == j ? 1.0 : 0.1 for i in 1:6, j in 1:6]6×6 Matrix{Float64}: 1.0 0.1 0.1 0.1 0.1 0.1 0.1 1.0 0.1 0.1 0.1 0.1 0.1 0.1 1.0 0.1 0.1 0.1 0.1 0.1 0.1 1.0 0.1 0.1 0.1 0.1 0.1 0.1 1.0 0.1 0.1 0.1 0.1 0.1 0.1 1.0julia> cov = OmmCovarianceMatrix(matrix; cov_ref_frame = "RTN")OmmCovarianceMatrix(String[], "RTN", 1.0, 0.1, 1.0, 0.1, 0.1, 1.0, 0.1, 0.1, 0.1, 1.0, 0.1, 0.1, 0.1, 0.1, 1.0, 0.1, 0.1, 0.1, 0.1, 0.1, 1.0)julia> cov.cy_x0.1julia> Matrix(cov)6×6 Matrix{Float64}: 1.0 0.1 0.1 0.1 0.1 0.1 0.1 1.0 0.1 0.1 0.1 0.1 0.1 0.1 1.0 0.1 0.1 0.1 0.1 0.1 0.1 1.0 0.1 0.1 0.1 0.1 0.1 0.1 1.0 0.1 0.1 0.1 0.1 0.1 0.1 1.0julia> SMatrix(cov)6×6 StaticArraysCore.SMatrix{6, 6, Float64, 36} with indices SOneTo(6)×SOneTo(6): 1.0 0.1 0.1 0.1 0.1 0.1 0.1 1.0 0.1 0.1 0.1 0.1 0.1 0.1 1.0 0.1 0.1 0.1 0.1 0.1 0.1 1.0 0.1 0.1 0.1 0.1 0.1 0.1 1.0 0.1 0.1 0.1 0.1 0.1 0.1 1.0
Copying and Modifying a Message
Since OrbitMeanElementsMessage is immutable, we can create a modified copy of an existing message by passing it to the constructor together with the keywords we want to override. The remaining fields are copied from the original message:
julia> new_omm = OrbitMeanElementsMessage(omm; originator = "SATELLITE TOOLBOX")OrbitMeanElementsMessage: ├─ Header │ Creation Date : 2025-12-30T23:36:37 │ Originator : SATELLITE TOOLBOX ├─ Metadata │ Object Name : AMAZONIA 1 │ Object ID : 2021-015A │ Center Name : EARTH │ Ref. Frame : TEME │ Time System : UTC │ Mean Element Theory : SGP4 └─ Data └─ Mean Keplerian Elements Epoch : 2025-12-30T18:12:04.533984 Mean Motion : 14.40772474 rev/day Eccentricity : 0.0001124 Inclination : 98.3721° RA of Asc. Node : 75.0877° Arg. of Pericenter : 97.3772° Mean Anomaly : 262.7545°julia> new_omm.header.originator"SATELLITE TOOLBOX"
Available Keywords
The following table lists all keywords accepted by the constructor. Fields marked as required must always be provided.
| Keyword | Type | Section | Required |
|---|---|---|---|
header_comments | Vector{String} | Header | |
classification | String | Header | |
creation_date | NanoDate | Header | ✅ |
originator | String | Header | ✅ |
message_id | String | Header | |
metadata_comments | Vector{String} | Metadata | |
object_name | String | Metadata | ✅ |
object_id | String | Metadata | ✅ |
center_name | String | Metadata | ✅ |
ref_frame | String | Metadata | ✅ |
ref_frame_epoch | NanoDate | Metadata | |
time_system | String | Metadata | ✅ |
mean_element_theory | String | Metadata | ✅ |
data_comments | Vector{String} | Data | |
mean_elements_comments | Vector{String} | Mean Elements | |
epoch | NanoDate | Mean Elements | ✅ |
semi_major_axis | Float64 | Mean Elements | ✅ [1] |
mean_motion | Float64 | Mean Elements | ✅ [1] |
eccentricity | Float64 | Mean Elements | ✅ |
inclination | Float64 | Mean Elements | ✅ |
raan | Float64 | Mean Elements | ✅ |
arg_of_pericenter | Float64 | Mean Elements | ✅ |
mean_anomaly | Float64 | Mean Elements | ✅ |
GM | Float64 | Mean Elements | |
spacecraft_parameters_comments | Vector{String} | Spacecraft Data | |
mass | Float64 | Spacecraft Data | |
solar_rad_area | Float64 | Spacecraft Data | |
solar_rad_coeff | Float64 | Spacecraft Data | |
drag_area | Float64 | Spacecraft Data | |
drag_coeff | Float64 | Spacecraft Data | |
tle_parameters_comments | Vector{String} | TLE Parameters | |
ephemeris_type | Int | TLE Parameters | |
classification_type | Char | TLE Parameters | |
norad_cat_id | Int | TLE Parameters | |
element_set_number | Int | TLE Parameters | |
rev_at_epoch | Int | TLE Parameters | |
bstar | Float64 | TLE Parameters | |
bterm | Float64 | TLE Parameters | |
mean_motion_dot | Float64 | TLE Parameters | |
mean_motion_ddot | Float64 | TLE Parameters | |
agom | Float64 | TLE Parameters | |
covariance_matrix | OmmCovarianceMatrix | Covariance Matrix | |
user_defined_parameters | Vector{Pair{String, String}} | User-Defined |
Comment keywords accept vectors because each XML section may contain multiple COMMENT elements. data_comments applies directly to <data>, while mean_elements_comments applies to <meanElements>.
If any TLE-related parameter is supplied, mean_motion_dot is required. Exactly one of bstar or bterm, and exactly one of mean_motion_ddot or agom, must also be supplied. The constructor throws ArgumentError when these constraints are not met.
Covariance Matrix
The OMM standard defines an optional covariance matrix section. It is represented by the OmmCovarianceMatrix type, which stores the 21 unique upper-triangular elements of the symmetric 6×6 matrix, along with an optional comment and reference frame:
julia> cov = OmmCovarianceMatrix(; cov_ref_frame = "ITRF", cx_x = 1.0, cy_x = 2.0, cy_y = 3.0, cz_x = 4.0, cz_y = 5.0, cz_z = 6.0, cx_dot_x = 7.0, cx_dot_y = 8.0, cx_dot_z = 9.0, cx_dot_x_dot = 10.0, cy_dot_x = 11.0, cy_dot_y = 12.0, cy_dot_z = 13.0, cy_dot_x_dot = 14.0, cy_dot_y_dot = 15.0, cz_dot_x = 16.0, cz_dot_y = 17.0, cz_dot_z = 18.0, cz_dot_x_dot = 19.0, cz_dot_y_dot = 20.0, cz_dot_z_dot = 21.0, )OmmCovarianceMatrix(String[], "ITRF", 1.0, 2.0, 3.0, 4.0, 5.0, 6.0, 7.0, 8.0, 9.0, 10.0, 11.0, 12.0, 13.0, 14.0, 15.0, 16.0, 17.0, 18.0, 19.0, 20.0, 21.0)julia> omm = OrbitMeanElementsMessage(omm; covariance_matrix = cov)OrbitMeanElementsMessage: ├─ Header │ Creation Date : 2025-12-30T23:36:37 │ Originator : 18 SPCS ├─ Metadata │ Object Name : AMAZONIA 1 │ Object ID : 2021-015A │ Center Name : EARTH │ Ref. Frame : TEME │ Time System : UTC │ Mean Element Theory : SGP4 └─ Data ├─ Mean Keplerian Elements │ Epoch : 2025-12-30T18:12:04.533984 │ Mean Motion : 14.40772474 rev/day │ Eccentricity : 0.0001124 │ Inclination : 98.3721° │ RA of Asc. Node : 75.0877° │ Arg. of Pericenter : 97.3772° │ Mean Anomaly : 262.7545° └─ Covariance Matrix Ref. Frame : ITRF CX_X : 1.0 km² CY_X : 2.0 km² CY_Y : 3.0 km² CZ_X : 4.0 km² CZ_Y : 5.0 km² CZ_Z : 6.0 km² CX_DOT_X : 7.0 km²/s CX_DOT_Y : 8.0 km²/s CX_DOT_Z : 9.0 km²/s CX_DOT_X_DOT : 10.0 km²/s² CY_DOT_X : 11.0 km²/s CY_DOT_Y : 12.0 km²/s CY_DOT_Z : 13.0 km²/s CY_DOT_X_DOT : 14.0 km²/s² CY_DOT_Y_DOT : 15.0 km²/s² CZ_DOT_X : 16.0 km²/s CZ_DOT_Y : 17.0 km²/s CZ_DOT_Z : 18.0 km²/s CZ_DOT_X_DOT : 19.0 km²/s² CZ_DOT_Y_DOT : 20.0 km²/s² CZ_DOT_Z_DOT : 21.0 km²/s²julia> omm.data.covariance_matrix.cov_ref_frame"ITRF"
- 1At least one of
semi_major_axisormean_motionmust be provided.