space-data-module-sdk 0.8.16 → 0.8.18

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (65) hide show
  1. package/bin/space-data-module.js +24 -6
  2. package/docs/browser-wasmedge-isomorphic.html +1 -1
  3. package/docs/byo-wasm-quickstart.html +1 -1
  4. package/docs/conformance.html +10 -4
  5. package/docs/conformance.md +20 -4
  6. package/docs/events-abi.html +1 -1
  7. package/docs/families/analytics.html +1 -1
  8. package/docs/families/attitude.html +1 -1
  9. package/docs/families/behavior.html +1 -1
  10. package/docs/families/breakup.html +1 -1
  11. package/docs/families/conjunction.html +1 -1
  12. package/docs/families/data-source.html +7 -2
  13. package/docs/families/effects.html +1 -1
  14. package/docs/families/environment.html +1 -1
  15. package/docs/families/estimation.html +56 -54
  16. package/docs/families/estimation.md +155 -125
  17. package/docs/families/gnc.html +1 -1
  18. package/docs/families/maneuver.html +1 -1
  19. package/docs/families/obstruction.html +1 -1
  20. package/docs/families/propagator.html +16 -2
  21. package/docs/families/propulsion.html +1 -1
  22. package/docs/families/reentry.html +1 -1
  23. package/docs/families/rf.html +1 -1
  24. package/docs/families/scheduler.html +1 -1
  25. package/docs/families/sensor.html +1 -1
  26. package/docs/families/signature.html +1 -1
  27. package/docs/flatsql-host-contract.html +1 -1
  28. package/docs/flatsql-streaming-standard.html +1 -1
  29. package/docs/gpu-module-abi.html +1 -1
  30. package/docs/harness-family-matrix.md +7 -7
  31. package/docs/index.html +2 -2
  32. package/docs/isomorphic-pthreads.html +1 -1
  33. package/docs/isomorphic-sdn-runtime-plan.html +1 -1
  34. package/docs/language-runtime-matrix.html +1 -1
  35. package/docs/llms.txt +1 -1
  36. package/docs/module-bundle-runtime-plan.html +1 -1
  37. package/docs/module-publication-standard.html +1 -1
  38. package/docs/node-red-default-node-parity.html +1 -1
  39. package/docs/propagator-abi.md +52 -0
  40. package/docs/protect-and-sign.html +1 -1
  41. package/docs/protocol-installation.html +1 -1
  42. package/docs/provider-access-abi.md +25 -0
  43. package/docs/publication-submission.html +1 -1
  44. package/docs/secrets-capability.html +1 -1
  45. package/docs/testing-harness.html +1 -1
  46. package/docs/tri-runtime-parity-gate.html +1 -1
  47. package/docs/tri-runtime-parity.html +1 -1
  48. package/include/orbpro/orbpro_estimation_abi.h +883 -0
  49. package/include/orbpro/orbpro_propagator_abi.h +58 -0
  50. package/include/orbpro/orbpro_solver_abi.h +183 -0
  51. package/package.json +4 -2
  52. package/schemas/orbpro/Estimation.fbs +244 -0
  53. package/schemas/orbpro/Propagator.fbs +64 -0
  54. package/schemas/orbpro/Solver.fbs +115 -0
  55. package/src/conformance/estimationReference.js +81 -0
  56. package/src/conformance/estimationSuite.js +134 -0
  57. package/src/conformance/index.js +39 -2
  58. package/src/generated/orbpro/propagator-abi.js +21 -0
  59. package/src/generated/orbpro/propagator-abi.ts +50 -0
  60. package/src/standards/sharedCatalog.js +7 -0
  61. package/templates/estimation-module/README.md +24 -0
  62. package/templates/estimation-module/build.mjs +32 -0
  63. package/templates/estimation-module/package.json +12 -0
  64. package/templates/estimation-module/plugin-manifest.json +34 -0
  65. package/templates/estimation-module/src/reference_estimation.cpp +53 -0
@@ -82,6 +82,64 @@ typedef enum {
82
82
  ORBPRO_STATE_HAS_COVARIANCE = 32,
83
83
  } OrbProStateFlags;
84
84
 
85
+ /* ========================================================================= */
86
+ /* ErrorCode */
87
+ /* ========================================================================= */
88
+
89
+ /**
90
+ * The negative return codes every propagator export shares.
91
+ *
92
+ * These were documented in docs/propagator-abi.md and declared NOWHERE, so
93
+ * every module hand-typed them as literals and the contract lived only in
94
+ * prose. A propagator that returns -1 for everything is unconformable — the
95
+ * host cannot tell a bad entity index from an uninitialized module, so it
96
+ * cannot place the failure on the degradation ladder — and the cheapest way
97
+ * to end up there is having no names to return.
98
+ *
99
+ * VALUES ARE FROZEN. New classes are appended downward.
100
+ */
101
+ typedef enum {
102
+ ORBPRO_PROP_OK = 0,
103
+ ORBPRO_PROP_NOT_INITIALIZED = -1, /**< No elements or ephemeris ingested yet. */
104
+ ORBPRO_PROP_BAD_ENTITY_INDEX = -2, /**< Entity index at or beyond the entity count. */
105
+ ORBPRO_PROP_NULL_OUTPUT = -3, /**< The caller passed a null output pointer. */
106
+ ORBPRO_PROP_BAD_INPUT = -4, /**< Malformed or short input buffer. */
107
+ ORBPRO_PROP_NOT_CONVERGED = -5, /**< The solve failed to converge. */
108
+ ORBPRO_PROP_UNPHYSICAL = -6, /**< The elements describe no closed orbit, or the result is not a number. */
109
+ ORBPRO_PROP_UNSUPPORTED_FORMAT = -7, /**< The ephemeris container is not one this module reads, or AUTO could not identify it, or its declared frame has no member on the ReferenceFrame roster. */
110
+ ORBPRO_PROP_EPOCH_OUT_OF_RANGE = -8, /**< The requested epoch lies outside every segment the loaded ephemeris covers. A refusal, never a silent extrapolation: a caller cannot detect an extrapolated state from the value alone. */
111
+ } OrbProPropagatorError;
112
+
113
+ /* ========================================================================= */
114
+ /* EphemerisFormat */
115
+ /* ========================================================================= */
116
+
117
+ /**
118
+ * The container an ephemeris-driven propagator was handed on
119
+ * `plugin_init_ephemeris`. A format is DATA, not identity: one ephemeris
120
+ * provider reads every member below behind this discriminator rather than
121
+ * shipping one artifact per container, because the interpolation, the time
122
+ * scale handling and the frame rotation are shared and splitting them
123
+ * re-creates the five-mirror drift this file exists to end.
124
+ *
125
+ * AUTO is the honest default: every container here is self-identifying in its
126
+ * first bytes (`DAF/SPK ` / `NAIF/DAF`, the OEM version keyword, the STK
127
+ * `stk.v.` banner, the SP3 `#d` line, the Code-500 fixed header block), so a
128
+ * caller that does not know what it fetched says so rather than guessing. A
129
+ * module that cannot identify the bytes returns UNSUPPORTED_FORMAT; it never
130
+ * falls back to a default container.
131
+ *
132
+ * VALUES ARE FROZEN AND ARE NEVER RENUMBERED. New containers are APPENDED.
133
+ */
134
+ typedef enum {
135
+ ORBPRO_EPHEM_FORMAT_AUTO = 0, /**< Identify the container from its own leading bytes. */
136
+ ORBPRO_EPHEM_FORMAT_CCSDS_OEM_KVN = 1, /**< CCSDS Orbit Ephemeris Message, keyword-value notation. */
137
+ ORBPRO_EPHEM_FORMAT_SPK_DAF = 2, /**< NAIF Double Precision Array File carrying SPK segments. */
138
+ ORBPRO_EPHEM_FORMAT_CODE500 = 3, /**< Fixed-record binary ephemeris, 500-word logical records. */
139
+ ORBPRO_EPHEM_FORMAT_STK_EPHEMERIS = 4, /**< Ephemeris interchange text with a scenario epoch and typed data blocks. */
140
+ ORBPRO_EPHEM_FORMAT_SP3_D = 5, /**< Precise orbit product, revision d. */
141
+ } OrbProEphemerisFormat;
142
+
85
143
  /* ========================================================================= */
86
144
  /* OrbProStateVector — 64 bytes, 8-byte aligned */
87
145
  /* ========================================================================= */
@@ -0,0 +1,183 @@
1
+ /* ===========================================================================
2
+ * SCHEMA-DERIVED ABI CONTRACT.
3
+ *
4
+ * Source of truth : schemas/orbpro/Solver.fbs
5
+ * Contract : pull/supply maneuver-family solver ABI
6
+ *
7
+ * A solver has no propagator import. plugin_solver_next yields a candidate;
8
+ * the host evaluates it through the selected propagator/objective ports and
9
+ * returns the answer through plugin_solver_supply.
10
+ * ===========================================================================
11
+ */
12
+
13
+ #ifndef ORBPRO_SOLVER_ABI_H
14
+ #define ORBPRO_SOLVER_ABI_H
15
+
16
+ #include <stddef.h>
17
+ #include <stdint.h>
18
+
19
+ #if defined(__cplusplus)
20
+ #define ORBPRO_SOLVER_STATIC_ASSERT(cond, msg) static_assert(cond, msg)
21
+ #else
22
+ #define ORBPRO_SOLVER_STATIC_ASSERT(cond, msg) _Static_assert(cond, msg)
23
+ #endif
24
+
25
+ #ifdef __cplusplus
26
+ extern "C" {
27
+ #endif
28
+
29
+ #define ORBPRO_SOLVER_MAX_DIMENSION 16u
30
+ #define ORBPRO_SOLVER_MAX_JACOBIAN_VALUES 256u
31
+
32
+ typedef enum {
33
+ ORBPRO_SOLVER_NEWTON_RAPHSON = 0,
34
+ ORBPRO_SOLVER_BROYDEN = 1,
35
+ ORBPRO_SOLVER_MODIFIED_BROYDEN = 2,
36
+ ORBPRO_SOLVER_SQP = 3,
37
+ } OrbProSolverAlgorithm;
38
+
39
+ typedef enum {
40
+ ORBPRO_SOLVER_DIFFERENCE_FORWARD = 0,
41
+ ORBPRO_SOLVER_DIFFERENCE_CENTRAL = 1,
42
+ ORBPRO_SOLVER_DIFFERENCE_ANALYTIC_STM = 2,
43
+ } OrbProSolverDifferenceMode;
44
+
45
+ typedef enum {
46
+ ORBPRO_SOLVER_STATUS_IDLE = 0,
47
+ ORBPRO_SOLVER_STATUS_NEEDS_EVALUATION = 1,
48
+ ORBPRO_SOLVER_STATUS_CONVERGED = 2,
49
+ ORBPRO_SOLVER_STATUS_INVALID_PROBLEM = 3,
50
+ ORBPRO_SOLVER_STATUS_EVALUATION_FAILED = 4,
51
+ ORBPRO_SOLVER_STATUS_SINGULAR_JACOBIAN = 5,
52
+ ORBPRO_SOLVER_STATUS_BUDGET_EXCEEDED = 6,
53
+ ORBPRO_SOLVER_STATUS_STALLED = 7,
54
+ ORBPRO_SOLVER_STATUS_INFEASIBLE = 8,
55
+ } OrbProSolverStatus;
56
+
57
+ typedef enum {
58
+ ORBPRO_SOLVER_EVALUATE_VALUES = 0,
59
+ ORBPRO_SOLVER_EVALUATE_VALUES_AND_JACOBIAN = 1,
60
+ } OrbProSolverEvaluationKind;
61
+
62
+ typedef struct {
63
+ uint8_t algorithm;
64
+ uint8_t difference_mode;
65
+ uint16_t _reserved0;
66
+ uint32_t maximum_iterations;
67
+ uint32_t maximum_evaluations;
68
+ uint32_t variable_count;
69
+ uint32_t goal_count;
70
+ uint32_t equality_constraint_count;
71
+ uint32_t inequality_constraint_count;
72
+ double residual_tolerance;
73
+ double step_tolerance;
74
+ double constraint_tolerance;
75
+ double kkt_tolerance;
76
+ } OrbProSolverSettings;
77
+
78
+ ORBPRO_SOLVER_STATIC_ASSERT(sizeof(OrbProSolverSettings) == 64,
79
+ "OrbProSolverSettings must be 64 bytes");
80
+ ORBPRO_SOLVER_STATIC_ASSERT(offsetof(OrbProSolverSettings, variable_count) == 12,
81
+ "OrbProSolverSettings.variable_count offset");
82
+ ORBPRO_SOLVER_STATIC_ASSERT(offsetof(OrbProSolverSettings, equality_constraint_count) == 20,
83
+ "OrbProSolverSettings.equality_constraint_count offset");
84
+ ORBPRO_SOLVER_STATIC_ASSERT(offsetof(OrbProSolverSettings, residual_tolerance) == 32,
85
+ "OrbProSolverSettings.residual_tolerance offset");
86
+
87
+ typedef struct {
88
+ uint64_t request_id;
89
+ uint8_t kind;
90
+ uint8_t _reserved0[3];
91
+ uint32_t variable_count;
92
+ double variables[ORBPRO_SOLVER_MAX_DIMENSION];
93
+ } OrbProSolverEvaluationRequest;
94
+
95
+ ORBPRO_SOLVER_STATIC_ASSERT(sizeof(OrbProSolverEvaluationRequest) == 144,
96
+ "OrbProSolverEvaluationRequest must be 144 bytes");
97
+
98
+ typedef struct {
99
+ uint64_t request_id;
100
+ uint8_t valid;
101
+ uint8_t _reserved0[3];
102
+ uint32_t goal_count;
103
+ uint32_t constraint_count;
104
+ uint32_t jacobian_rows;
105
+ uint32_t jacobian_columns;
106
+ double goals[ORBPRO_SOLVER_MAX_DIMENSION];
107
+ double objective;
108
+ double constraints[ORBPRO_SOLVER_MAX_DIMENSION];
109
+ double jacobian[ORBPRO_SOLVER_MAX_JACOBIAN_VALUES];
110
+ } OrbProSolverEvaluation;
111
+
112
+ ORBPRO_SOLVER_STATIC_ASSERT(sizeof(OrbProSolverEvaluation) == 2344,
113
+ "OrbProSolverEvaluation must be 2344 bytes");
114
+ ORBPRO_SOLVER_STATIC_ASSERT(offsetof(OrbProSolverEvaluation, goals) == 32,
115
+ "OrbProSolverEvaluation.goals offset");
116
+ ORBPRO_SOLVER_STATIC_ASSERT(offsetof(OrbProSolverEvaluation, objective) == 160,
117
+ "OrbProSolverEvaluation.objective offset");
118
+ ORBPRO_SOLVER_STATIC_ASSERT(offsetof(OrbProSolverEvaluation, constraints) == 168,
119
+ "OrbProSolverEvaluation.constraints offset");
120
+
121
+ typedef struct {
122
+ uint32_t iteration;
123
+ uint32_t evaluation_count;
124
+ uint32_t variable_count;
125
+ uint32_t goal_count;
126
+ double variables[ORBPRO_SOLVER_MAX_DIMENSION];
127
+ double values[ORBPRO_SOLVER_MAX_DIMENSION];
128
+ double residual_norm;
129
+ double step_norm;
130
+ double jacobian_condition;
131
+ double maximum_constraint_violation;
132
+ double kkt_residual;
133
+ uint8_t accepted;
134
+ uint8_t _reserved0[7];
135
+ } OrbProSolverIteration;
136
+
137
+ ORBPRO_SOLVER_STATIC_ASSERT(sizeof(OrbProSolverIteration) == 320,
138
+ "OrbProSolverIteration must be 320 bytes");
139
+
140
+ typedef struct {
141
+ uint8_t status;
142
+ uint8_t _reserved0[3];
143
+ uint32_t iteration_count;
144
+ uint32_t evaluation_count;
145
+ uint32_t variable_count;
146
+ uint32_t value_count;
147
+ double variables[ORBPRO_SOLVER_MAX_DIMENSION];
148
+ double values[ORBPRO_SOLVER_MAX_DIMENSION];
149
+ double objective;
150
+ double residual_norm;
151
+ double maximum_constraint_violation;
152
+ double kkt_residual;
153
+ } OrbProSolverResult;
154
+
155
+ ORBPRO_SOLVER_STATIC_ASSERT(sizeof(OrbProSolverResult) == 312,
156
+ "OrbProSolverResult must be 312 bytes");
157
+ ORBPRO_SOLVER_STATIC_ASSERT(offsetof(OrbProSolverResult, variables) == 24,
158
+ "OrbProSolverResult.variables offset");
159
+ ORBPRO_SOLVER_STATIC_ASSERT(offsetof(OrbProSolverResult, objective) == 280,
160
+ "OrbProSolverResult.objective offset");
161
+
162
+ static inline void orbpro_solver_zero(void* value, size_t size) {
163
+ size_t index;
164
+ for (index = 0; index < size; ++index) ((uint8_t*)value)[index] = 0;
165
+ }
166
+
167
+ int32_t plugin_solver_configure(const OrbProSolverSettings* settings,
168
+ const double* initial_variables,
169
+ const double* lower_bounds,
170
+ const double* upper_bounds,
171
+ const double* desired_values,
172
+ const double* perturbations);
173
+ int32_t plugin_solver_begin(void);
174
+ int32_t plugin_solver_next(OrbProSolverEvaluationRequest* request);
175
+ int32_t plugin_solver_supply(const OrbProSolverEvaluation* evaluation);
176
+ int32_t plugin_solver_result(OrbProSolverResult* result);
177
+ int32_t plugin_solver_iteration(uint32_t index, OrbProSolverIteration* result);
178
+
179
+ #ifdef __cplusplus
180
+ } /* extern "C" */
181
+ #endif
182
+
183
+ #endif /* ORBPRO_SOLVER_ABI_H */
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "space-data-module-sdk",
3
- "version": "0.8.16",
3
+ "version": "0.8.18",
4
4
  "license": "Apache-2.0",
5
5
  "description": "Module SDK for building, validating, signing, and deploying WebAssembly modules on the Space Data Network.",
6
6
  "type": "module",
@@ -97,6 +97,7 @@
97
97
  "gate:parity": "node ./bin/space-data-module.js parity-gate",
98
98
  "gate:parity-negative-control": "node ./bin/space-data-module.js parity-gate --gate-manifest ./parity/negative-control.json --expect-fail",
99
99
  "conformance:self-test": "node ./bin/space-data-module.js conformance propagator --self-test",
100
+ "conformance:estimation:self-test": "node ./bin/space-data-module.js conformance estimation --self-test",
100
101
  "test:stream-ingest": "node --test test/runtime-host-stream-ingest.test.js",
101
102
  "test:module-stream": "node --test test/module-flatbuffer-stream-pump.test.js",
102
103
  "benchmark:stream-1gib": "SPACE_DATA_MODULE_SDK_ENABLE_1GB_STREAM_TEST=1 node --test test/runtime-host-stream-ingest.test.js",
@@ -109,6 +110,7 @@
109
110
  "check:compliance": "node ./bin/space-data-module.js check --repo-root .",
110
111
  "check:generated-bindings": "node scripts/check-generated-bindings.mjs",
111
112
  "check:propagator-abi": "node scripts/check-propagator-abi.mjs",
113
+ "check:estimation-abi": "node scripts/check-estimation-abi.mjs",
112
114
  "check:reference-frame": "node scripts/check-reference-frame-uniqueness.mjs",
113
115
  "generate:propagator-abi": "node scripts/generate-propagator-abi.mjs",
114
116
  "generate:vectors": "node ./examples/single-file-bundle/generate-vectors.mjs",
@@ -123,7 +125,7 @@
123
125
  "flatsql": "^2.0.0",
124
126
  "hd-wallet-wasm": "2.0.28",
125
127
  "sdn-emception": "1.0.0",
126
- "spacedatastandards.org": "1.200.0"
128
+ "spacedatastandards.org": "1.206.0"
127
129
  },
128
130
  "devDependencies": {
129
131
  "esbuild": "^0.28.0",
@@ -0,0 +1,244 @@
1
+ include "Propagator.fbs";
2
+
3
+ namespace orbpro.estimation;
4
+
5
+ // Estimation family ABI. This schema is the single source of truth for the
6
+ // fixed-layout C boundary and the request/result wire. Propagation is an
7
+ // inverted port protocol: the guest emits state/STM requests and consumes the
8
+ // supplied Propagator.fbs answers. It imports no provider-specific function.
9
+
10
+ enum EstimatorKind : ubyte (abi, abi_c_name: "OrbProEstimatorKind", abi_c_prefix: "ORBPRO_ESTIMATOR_") {
11
+ BATCH_WEIGHTED_LEAST_SQUARES = 0,
12
+ EXTENDED_KALMAN_FILTER = 1,
13
+ UNSCENTED_KALMAN_FILTER = 2,
14
+ EXTENDED_KALMAN_FILTER_WITH_RTS = 3
15
+ }
16
+
17
+ enum MeasurementKind : ushort (abi, abi_c_name: "OrbProMeasurementKind", abi_c_prefix: "ORBPRO_MEASUREMENT_") {
18
+ RANGE = 0,
19
+ RANGE_RATE = 1,
20
+ DOPPLER = 2,
21
+ AZIMUTH_ELEVATION = 3,
22
+ X_EAST_Y_NORTH = 4,
23
+ X_SOUTH_Y_EAST = 5,
24
+ RIGHT_ASCENSION_DECLINATION = 6,
25
+ POSITION_VECTOR = 7,
26
+ SEQUENTIAL_RANGE = 8,
27
+ PSEUDONOISE_RANGE = 9,
28
+ TIME_CORRELATED_PHASE = 10,
29
+ RELAY_RANGE = 11,
30
+ RELAY_DOPPLER = 12,
31
+ RELAY_DIFFERENCED_DOPPLER = 13,
32
+ BISTATIC_RANGE = 14,
33
+ SKIN_RANGE = 15,
34
+ CROSSLINK_RANGE = 16,
35
+ CROSSLINK_RANGE_RATE = 17,
36
+ LASER_RANGE = 18,
37
+ TIME_DIFFERENCE_OF_ARRIVAL = 19,
38
+ FREQUENCY_DIFFERENCE_OF_ARRIVAL = 20
39
+ }
40
+
41
+ enum ProcessNoiseKind : ubyte (abi, abi_c_name: "OrbProProcessNoiseKind", abi_c_prefix: "ORBPRO_PROCESS_NOISE_") {
42
+ NONE = 0,
43
+ STATE_NOISE_COMPENSATION = 1,
44
+ DYNAMIC_MODEL_COMPENSATION = 2
45
+ }
46
+
47
+ enum TroposphereKind : ubyte (abi, abi_c_name: "OrbProTroposphereKind", abi_c_prefix: "ORBPRO_TROPOSPHERE_") {
48
+ NONE = 0,
49
+ HOPFIELD_SAASTAMOINEN = 1,
50
+ MARINI = 2
51
+ }
52
+
53
+ enum IonosphereKind : ubyte (abi, abi_c_name: "OrbProIonosphereKind", abi_c_prefix: "ORBPRO_IONOSPHERE_") {
54
+ NONE = 0,
55
+ TOTAL_ELECTRON_CONTENT = 1,
56
+ REFERENCE_PROFILE = 2
57
+ }
58
+
59
+ enum InitialOrbitKind : ubyte (abi, abi_c_name: "OrbProInitialOrbitKind", abi_c_prefix: "ORBPRO_IOD_") {
60
+ GAUSS = 0,
61
+ LAPLACE = 1,
62
+ GIBBS = 2,
63
+ HERRICK_GIBBS = 3
64
+ }
65
+
66
+ enum EstimationStatus : int (abi, abi_c_name: "OrbProEstimationStatus", abi_c_prefix: "ORBPRO_ESTIMATION_") {
67
+ INTERNAL = -20,
68
+ PROPAGATOR_PROTOCOL = -19,
69
+ BUFFER_TOO_SMALL = -18,
70
+ NOT_CONVERGED = -5,
71
+ BAD_INPUT = -4,
72
+ NULL_OUTPUT = -3,
73
+ NOT_CONFIGURED = -1,
74
+ OK = 0
75
+ }
76
+
77
+ struct EstimationEpoch (abi, abi_c_name: "OrbProEstimationEpoch", abi_c_helper_prefix: "orbpro_estimation_epoch_") {
78
+ jd_day:double;
79
+ seconds:double;
80
+ }
81
+
82
+ /// One observation in SI units. The first value_count lanes of value and
83
+ /// sigma are meaningful. station_position_m is in the request frame.
84
+ struct EstimationObservation (abi, abi_c_name: "OrbProEstimationObservation", abi_c_helper_prefix: "orbpro_estimation_observation_") {
85
+ epoch:EstimationEpoch;
86
+ value:[double:4];
87
+ sigma:[double:4];
88
+ station_position_m:[double:3];
89
+ station_velocity_mps:[double:3];
90
+ station_east:[double:3];
91
+ station_north:[double:3];
92
+ station_up:[double:3];
93
+ remote_position_m:[double:3];
94
+ remote_velocity_mps:[double:3];
95
+ frequency_hz:double;
96
+ transmitter_delay_seconds:double;
97
+ receiver_delay_seconds:double;
98
+ transponder_delay_seconds:double;
99
+ elevation_rad:double;
100
+ station_latitude_rad:double;
101
+ station_height_m:double;
102
+ pressure_hpa:double;
103
+ temperature_k:double;
104
+ relative_humidity:double;
105
+ wavelength_m:double;
106
+ total_electron_content:double;
107
+ total_electron_content_rate_per_second:double;
108
+ turnaround_numerator:uint;
109
+ turnaround_denominator:uint;
110
+ kind:MeasurementKind;
111
+ value_count:ubyte;
112
+ flags:ubyte;
113
+ transmitter_index:uint;
114
+ receiver_index:uint;
115
+ }
116
+
117
+ struct EstimationErrorModel (abi, abi_c_name: "OrbProEstimationErrorModel", abi_c_helper_prefix: "orbpro_estimation_error_model_") {
118
+ noise_sigma:double;
119
+ bias:double;
120
+ bias_sigma:double;
121
+ correlation_time_seconds:double;
122
+ minimum_value:double;
123
+ maximum_value:double;
124
+ sigma_edit_threshold:double;
125
+ random_seed:ulong;
126
+ measurement_kind:MeasurementKind;
127
+ troposphere:TroposphereKind;
128
+ ionosphere:IonosphereKind;
129
+ flags:ubyte;
130
+ }
131
+
132
+ /// Fixed configuration copied byte-for-byte in every runtime. initial_state
133
+ /// is Cartesian [x,y,z,vx,vy,vz] in metres and metres per second; covariance
134
+ /// is row-major 6 by 6 in matching SI units.
135
+ struct EstimationConfig (abi, abi_c_name: "OrbProEstimationConfig", abi_c_helper_prefix: "orbpro_estimation_config_") {
136
+ initial_epoch:EstimationEpoch;
137
+ initial_state:[double:6];
138
+ initial_covariance:[double:36];
139
+ process_noise_spectral_density:[double:6];
140
+ state_convergence_tolerance:double;
141
+ rms_convergence_tolerance:double;
142
+ sigma_edit_threshold:double;
143
+ dynamic_model_correlation_time_seconds:double;
144
+ maximum_iterations:uint;
145
+ reference_frame:orbpro.propagator.ReferenceFrame;
146
+ estimator:EstimatorKind;
147
+ process_noise:ProcessNoiseKind;
148
+ flags:ushort;
149
+ }
150
+
151
+ struct EstimationState (abi, abi_c_name: "OrbProEstimationState", abi_c_helper_prefix: "orbpro_estimation_state_") {
152
+ epoch:EstimationEpoch;
153
+ state:[double:6];
154
+ covariance:[double:36];
155
+ residual_rms:double;
156
+ recovered_noise_sigma:double;
157
+ iteration_count:uint;
158
+ accepted_count:uint;
159
+ rejected_count:uint;
160
+ reference_frame:orbpro.propagator.ReferenceFrame;
161
+ converged:ubyte;
162
+ smoothed:ubyte;
163
+ estimator:EstimatorKind;
164
+ }
165
+
166
+ struct FilterEpoch (abi, abi_c_name: "OrbProFilterEpoch", abi_c_helper_prefix: "orbpro_filter_epoch_") {
167
+ epoch:EstimationEpoch;
168
+ filtered_state:[double:6];
169
+ filtered_covariance:[double:36];
170
+ smoothed_state:[double:6];
171
+ smoothed_covariance:[double:36];
172
+ normalized_innovation_squared:double;
173
+ }
174
+
175
+ /// State and state-transition matrix supplied by the propagator port. The STM
176
+ /// maps deviations at the estimator epoch to this sample epoch.
177
+ struct EstimationPropagatorSample (abi, abi_c_name: "OrbProEstimationPropagatorSample", abi_c_helper_prefix: "orbpro_estimation_propagator_sample_") {
178
+ epoch:EstimationEpoch;
179
+ state:[double:6];
180
+ stm:[double:36];
181
+ }
182
+
183
+ struct InitialOrbitRequest (abi, abi_c_name: "OrbProInitialOrbitRequest", abi_c_helper_prefix: "orbpro_initial_orbit_request_") {
184
+ // Three inertial position vectors for Gibbs and Herrick-Gibbs.
185
+ positions_m:[double:9];
186
+ // Three observer positions followed by the three topocentric angle pairs
187
+ // used by Gauss and Laplace. The method selects which input set is read.
188
+ observer_positions_m:[double:9];
189
+ right_ascensions_rad:[double:3];
190
+ declinations_rad:[double:3];
191
+ epochs:EstimationEpoch;
192
+ interval_12_seconds:double;
193
+ interval_23_seconds:double;
194
+ gravitational_parameter_m3_s2:double;
195
+ method:InitialOrbitKind;
196
+ }
197
+
198
+ struct InitialOrbitResult (abi, abi_c_name: "OrbProInitialOrbitResult", abi_c_helper_prefix: "orbpro_initial_orbit_result_") {
199
+ epoch:EstimationEpoch;
200
+ state:[double:6];
201
+ iterations:uint;
202
+ reference_frame:orbpro.propagator.ReferenceFrame;
203
+ status:EstimationStatus;
204
+ }
205
+
206
+ /// Request/result wire. observations are decoded from $TDM/$CRD before they
207
+ /// cross this family boundary; their source record identifiers remain on the
208
+ /// request for a complete provenance trail.
209
+ table EstimationRequest {
210
+ config:EstimationConfig;
211
+ observations:[EstimationObservation];
212
+ error_models:[EstimationErrorModel];
213
+ source_record_ids:[string];
214
+ propagator_port_id:string (required);
215
+ propagator_capability:string (required);
216
+ trace_id:string;
217
+ }
218
+
219
+ table EstimationResult {
220
+ status:EstimationStatus = OK;
221
+ estimate:EstimationState;
222
+ filter_history:[FilterEpoch];
223
+ residuals:[double];
224
+ /// Row-major 6x6 covariance blocks, one per batch iteration, in iteration
225
+ /// order. Empty for sequential estimators.
226
+ iteration_covariances:[double];
227
+ rejected_observation_indices:[uint];
228
+ odr_record:[ubyte];
229
+ ocm_record:[ubyte];
230
+ error_message:string;
231
+ trace_id:string;
232
+ }
233
+
234
+ table EstimationEnvelope {
235
+ request:EstimationRequest;
236
+ result:EstimationResult;
237
+ propagator_samples:[EstimationPropagatorSample];
238
+ simulated_observations:[EstimationObservation];
239
+ initial_orbit_request:InitialOrbitRequest;
240
+ initial_orbit_result:InitialOrbitResult;
241
+ }
242
+
243
+ root_type EstimationEnvelope;
244
+ file_identifier "$EST";
@@ -165,6 +165,70 @@ enum PropagatorSourceKind : ubyte {
165
165
  SDP8 = 12
166
166
  }
167
167
 
168
+ /// The negative return codes every propagator export shares.
169
+ ///
170
+ /// These were documented in docs/propagator-abi.md and declared NOWHERE, so
171
+ /// every module hand-typed them as literals and the contract lived only in
172
+ /// prose. A propagator that returns -1 for everything is unconformable — the
173
+ /// host cannot tell a bad entity index from an uninitialized module, so it
174
+ /// cannot place the failure on the degradation ladder — and the cheapest way
175
+ /// to end up there is having no names to return.
176
+ ///
177
+ /// VALUES ARE FROZEN. New classes are appended downward.
178
+ enum ErrorCode : byte (abi, abi_c_name: "OrbProPropagatorError", abi_c_prefix: "ORBPRO_PROP_") {
179
+ OK = 0,
180
+ /// No elements or ephemeris ingested yet.
181
+ NOT_INITIALIZED = -1,
182
+ /// Entity index at or beyond the entity count.
183
+ BAD_ENTITY_INDEX = -2,
184
+ /// The caller passed a null output pointer.
185
+ NULL_OUTPUT = -3,
186
+ /// Malformed or short input buffer.
187
+ BAD_INPUT = -4,
188
+ /// The solve failed to converge.
189
+ NOT_CONVERGED = -5,
190
+ /// The elements describe no closed orbit, or the result is not a number.
191
+ UNPHYSICAL = -6,
192
+ /// The ephemeris container is not one this module reads, or AUTO could not
193
+ /// identify it, or its declared frame has no member on the ReferenceFrame
194
+ /// roster.
195
+ UNSUPPORTED_FORMAT = -7,
196
+ /// The requested epoch lies outside every segment the loaded ephemeris
197
+ /// covers. A refusal, never a silent extrapolation: a caller cannot detect
198
+ /// an extrapolated state from the value alone.
199
+ EPOCH_OUT_OF_RANGE = -8
200
+ }
201
+
202
+ /// The container an ephemeris-driven propagator was handed on
203
+ /// `plugin_init_ephemeris`. A format is DATA, not identity: one ephemeris
204
+ /// provider reads every member below behind this discriminator rather than
205
+ /// shipping one artifact per container, because the interpolation, the time
206
+ /// scale handling and the frame rotation are shared and splitting them
207
+ /// re-creates the five-mirror drift this file exists to end.
208
+ ///
209
+ /// AUTO is the honest default: every container here is self-identifying in its
210
+ /// first bytes (`DAF/SPK ` / `NAIF/DAF`, the OEM version keyword, the STK
211
+ /// `stk.v.` banner, the SP3 `#d` line, the Code-500 fixed header block), so a
212
+ /// caller that does not know what it fetched says so rather than guessing. A
213
+ /// module that cannot identify the bytes returns UNSUPPORTED_FORMAT; it never
214
+ /// falls back to a default container.
215
+ ///
216
+ /// VALUES ARE FROZEN AND ARE NEVER RENUMBERED. New containers are APPENDED.
217
+ enum EphemerisFormat : ubyte (abi, abi_c_name: "OrbProEphemerisFormat", abi_c_prefix: "ORBPRO_EPHEM_FORMAT_") {
218
+ /// Identify the container from its own leading bytes.
219
+ AUTO = 0,
220
+ /// CCSDS Orbit Ephemeris Message, keyword-value notation.
221
+ CCSDS_OEM_KVN = 1,
222
+ /// NAIF Double Precision Array File carrying SPK segments.
223
+ SPK_DAF = 2,
224
+ /// Fixed-record binary ephemeris, 500-word logical records.
225
+ CODE500 = 3,
226
+ /// Ephemeris interchange text with a scenario epoch and typed data blocks.
227
+ STK_EPHEMERIS = 4,
228
+ /// Precise orbit product, revision d.
229
+ SP3_D = 5
230
+ }
231
+
168
232
  /// Orbital state vector — 64 bytes, 8-byte aligned. Mirrors
169
233
  /// `OrbProStateVector` in orbpro-integration/sdk/include/orbpro_propagator.h
170
234
  /// byte for byte: