aero-agent-roles 1.0.0
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.
- package/NOTICE +18 -0
- package/README.md +49 -0
- package/bin/aero-agent-roles.js +127 -0
- package/lib/catalog.js +97 -0
- package/lib/install.js +48 -0
- package/lib/mcp.js +199 -0
- package/manifest.json +516 -0
- package/package.json +44 -0
- package/roles/aerodynamics-engineer/ROLE.md +153 -0
- package/roles/aerodynamics-engineer/SOURCES.md +12 -0
- package/roles/aerodynamics-engineer/cli.py +143 -0
- package/roles/aerodynamics-engineer/core/aerodynamics_core.py +1218 -0
- package/roles/aerodynamics-engineer/templates/aero-design-report-template.md +72 -0
- package/roles/aerodynamics-engineer/tests/test_aerodynamics_core.py +227 -0
- package/roles/aerodynamics-engineer/tests/test_role_aerodynamics.py +94 -0
- package/roles/aircraft-design-engineer/ROLE.md +138 -0
- package/roles/aircraft-design-engineer/SOURCES.md +12 -0
- package/roles/aircraft-design-engineer/cli.py +152 -0
- package/roles/aircraft-design-engineer/core/aircraft_design_core.py +1278 -0
- package/roles/aircraft-design-engineer/templates/concept-design-template.md +99 -0
- package/roles/aircraft-design-engineer/tests/test_aircraft_design_core.py +269 -0
- package/roles/aircraft-design-engineer/tests/test_role_aircraft_design_engineer.py +106 -0
- package/roles/airworthiness-compliance-engineer/ROLE.md +122 -0
- package/roles/airworthiness-compliance-engineer/SOURCES.md +16 -0
- package/roles/airworthiness-compliance-engineer/cli.py +146 -0
- package/roles/airworthiness-compliance-engineer/core/airworthiness_core.py +894 -0
- package/roles/airworthiness-compliance-engineer/templates/compliance-matrix-template.md +46 -0
- package/roles/airworthiness-compliance-engineer/tests/test_airworthiness_core.py +224 -0
- package/roles/airworthiness-compliance-engineer/tests/test_role_airworthiness.py +85 -0
- package/roles/as9100-quality-auditor/ROLE.md +128 -0
- package/roles/as9100-quality-auditor/SOURCES.md +16 -0
- package/roles/as9100-quality-auditor/cli.py +136 -0
- package/roles/as9100-quality-auditor/core/as9100_core.py +857 -0
- package/roles/as9100-quality-auditor/templates/findings-report-template.md +119 -0
- package/roles/as9100-quality-auditor/tests/test_as9100_cli_profile.py +105 -0
- package/roles/as9100-quality-auditor/tests/test_as9100_core.py +204 -0
- package/roles/as9100-quality-auditor/tests/test_role_as9100.py +90 -0
- package/roles/data-bus-avionics-engineer/ROLE.md +146 -0
- package/roles/data-bus-avionics-engineer/SOURCES.md +23 -0
- package/roles/data-bus-avionics-engineer/cli.py +311 -0
- package/roles/data-bus-avionics-engineer/core/data_bus_avionics_core.py +1121 -0
- package/roles/data-bus-avionics-engineer/templates/bus-assessment-template.md +134 -0
- package/roles/data-bus-avionics-engineer/tests/test_bundle_protocol.py +137 -0
- package/roles/data-bus-avionics-engineer/tests/test_data_bus_avionics_core.py +261 -0
- package/roles/data-bus-avionics-engineer/tests/test_role_data_bus_avionics_engineer.py +121 -0
- package/roles/do160-environmental-engineer/ROLE.md +136 -0
- package/roles/do160-environmental-engineer/SOURCES.md +30 -0
- package/roles/do160-environmental-engineer/cli.py +147 -0
- package/roles/do160-environmental-engineer/core/do160_environmental_core.py +1246 -0
- package/roles/do160-environmental-engineer/templates/environmental-qualification-plan-template.md +114 -0
- package/roles/do160-environmental-engineer/tests/test_do160_environmental_core.py +312 -0
- package/roles/do160-environmental-engineer/tests/test_role_do160_environmental_engineer.py +281 -0
- package/roles/do178c-cert-engineer/ROLE.md +120 -0
- package/roles/do178c-cert-engineer/SOURCES.md +16 -0
- package/roles/do178c-cert-engineer/cli.py +129 -0
- package/roles/do178c-cert-engineer/core/do178c_core.py +411 -0
- package/roles/do178c-cert-engineer/templates/psac-template.md +74 -0
- package/roles/do178c-cert-engineer/tests/test_do178c_cert_engineer_core.py +91 -0
- package/roles/do178c-cert-engineer/tests/test_role_do178c.py +109 -0
- package/roles/do254-hardware-engineer/ROLE.md +127 -0
- package/roles/do254-hardware-engineer/SOURCES.md +19 -0
- package/roles/do254-hardware-engineer/cli.py +308 -0
- package/roles/do254-hardware-engineer/core/do254_hardware_core.py +761 -0
- package/roles/do254-hardware-engineer/templates/phac-template.md +87 -0
- package/roles/do254-hardware-engineer/tests/test_do254_bundle_profile.py +152 -0
- package/roles/do254-hardware-engineer/tests/test_do254_hardware_core.py +200 -0
- package/roles/do254-hardware-engineer/tests/test_role_do254_hardware.py +108 -0
- package/roles/engineering-analysis-engineer/ROLE.md +154 -0
- package/roles/engineering-analysis-engineer/SOURCES.md +15 -0
- package/roles/engineering-analysis-engineer/cli.py +151 -0
- package/roles/engineering-analysis-engineer/core/engineering_analysis_engineer_core.py +866 -0
- package/roles/engineering-analysis-engineer/templates/analysis-memo-template.md +73 -0
- package/roles/engineering-analysis-engineer/tests/test_engineering_analysis_engineer_core.py +367 -0
- package/roles/engineering-analysis-engineer/tests/test_role_engineering_analysis_engineer.py +113 -0
- package/roles/flight-management-engineer/ROLE.md +160 -0
- package/roles/flight-management-engineer/SOURCES.md +30 -0
- package/roles/flight-management-engineer/cli.py +258 -0
- package/roles/flight-management-engineer/core/flight_management_core.py +1473 -0
- package/roles/flight-management-engineer/templates/route-assessment-template.md +94 -0
- package/roles/flight-management-engineer/tests/test_flight_management_core.py +437 -0
- package/roles/flight-management-engineer/tests/test_role_flight_management_engineer.py +123 -0
- package/roles/flight-mechanics-engineer/ROLE.md +162 -0
- package/roles/flight-mechanics-engineer/SOURCES.md +51 -0
- package/roles/flight-mechanics-engineer/cli.py +149 -0
- package/roles/flight-mechanics-engineer/core/flight_mechanics_core.py +1507 -0
- package/roles/flight-mechanics-engineer/templates/perf-sc-report-template.md +82 -0
- package/roles/flight-mechanics-engineer/tests/test_flight_mechanics_core.py +277 -0
- package/roles/flight-mechanics-engineer/tests/test_role_flight_mechanics_engineer.py +141 -0
- package/roles/flight-test-engineer/ROLE.md +137 -0
- package/roles/flight-test-engineer/SOURCES.md +24 -0
- package/roles/flight-test-engineer/cli.py +135 -0
- package/roles/flight-test-engineer/core/flight_test_core.py +931 -0
- package/roles/flight-test-engineer/templates/flight-test-template.md +143 -0
- package/roles/flight-test-engineer/tests/test_flight_test_engineer_core.py +227 -0
- package/roles/flight-test-engineer/tests/test_role_flight_test_engineer.py +150 -0
- package/roles/flight-test-performance-engineer/ROLE.md +165 -0
- package/roles/flight-test-performance-engineer/SOURCES.md +20 -0
- package/roles/flight-test-performance-engineer/cli.py +319 -0
- package/roles/flight-test-performance-engineer/core/flight_test_performance_core.py +1398 -0
- package/roles/flight-test-performance-engineer/templates/performance-report-template.md +105 -0
- package/roles/flight-test-performance-engineer/tests/test_flight_test_performance_engineer_core.py +308 -0
- package/roles/flight-test-performance-engineer/tests/test_role_flight_test_performance_engineer.py +165 -0
- package/roles/gnc-engineer/ROLE.md +141 -0
- package/roles/gnc-engineer/SOURCES.md +35 -0
- package/roles/gnc-engineer/cli.py +141 -0
- package/roles/gnc-engineer/core/gnc_core.py +1074 -0
- package/roles/gnc-engineer/templates/gnc-report-template.md +105 -0
- package/roles/gnc-engineer/tests/test_gnc_engineer_core.py +238 -0
- package/roles/gnc-engineer/tests/test_role_gnc_engineer.py +142 -0
- package/roles/guidance-engineer/ROLE.md +156 -0
- package/roles/guidance-engineer/SOURCES.md +43 -0
- package/roles/guidance-engineer/cli.py +280 -0
- package/roles/guidance-engineer/core/guidance_core.py +820 -0
- package/roles/guidance-engineer/templates/guidance-report-template.md +70 -0
- package/roles/guidance-engineer/tests/test_guidance_engineer_core.py +269 -0
- package/roles/guidance-engineer/tests/test_role_guidance_engineer.py +146 -0
- package/roles/high-speed-aerodynamics-engineer/ROLE.md +161 -0
- package/roles/high-speed-aerodynamics-engineer/SOURCES.md +18 -0
- package/roles/high-speed-aerodynamics-engineer/cli.py +282 -0
- package/roles/high-speed-aerodynamics-engineer/core/high_speed_aero_core.py +1566 -0
- package/roles/high-speed-aerodynamics-engineer/templates/high-speed-memo-template.md +75 -0
- package/roles/high-speed-aerodynamics-engineer/tests/test_bundle_protocol.py +103 -0
- package/roles/high-speed-aerodynamics-engineer/tests/test_high_speed_aero_core.py +280 -0
- package/roles/high-speed-aerodynamics-engineer/tests/test_role_high_speed_aerodynamics.py +125 -0
- package/roles/ndt-engineer/ROLE.md +157 -0
- package/roles/ndt-engineer/SOURCES.md +18 -0
- package/roles/ndt-engineer/cli.py +316 -0
- package/roles/ndt-engineer/core/ndt_core.py +1590 -0
- package/roles/ndt-engineer/templates/ndt-plan-template.md +109 -0
- package/roles/ndt-engineer/tests/test_ndt_cli_bundle.py +183 -0
- package/roles/ndt-engineer/tests/test_ndt_core.py +437 -0
- package/roles/ndt-engineer/tests/test_role_ndt_engineer.py +148 -0
- package/roles/numerical-analysis-engineer/ROLE.md +158 -0
- package/roles/numerical-analysis-engineer/SOURCES.md +19 -0
- package/roles/numerical-analysis-engineer/cli.py +414 -0
- package/roles/numerical-analysis-engineer/core/numerical_analysis_core.py +1220 -0
- package/roles/numerical-analysis-engineer/templates/verification-memo-template.md +120 -0
- package/roles/numerical-analysis-engineer/tests/test_bundle_protocol.py +157 -0
- package/roles/numerical-analysis-engineer/tests/test_numerical_analysis_core.py +337 -0
- package/roles/numerical-analysis-engineer/tests/test_role_numerical_analysis_engineer.py +117 -0
- package/roles/propulsion-engineer/ROLE.md +163 -0
- package/roles/propulsion-engineer/SOURCES.md +15 -0
- package/roles/propulsion-engineer/cli.py +168 -0
- package/roles/propulsion-engineer/core/propulsion_core.py +1291 -0
- package/roles/propulsion-engineer/templates/propulsion-report-template.md +92 -0
- package/roles/propulsion-engineer/tests/test_propulsion_engineer_core.py +294 -0
- package/roles/propulsion-engineer/tests/test_role_propulsion_engineer.py +106 -0
- package/roles/space-systems-engineer/ROLE.md +161 -0
- package/roles/space-systems-engineer/SOURCES.md +49 -0
- package/roles/space-systems-engineer/cli.py +173 -0
- package/roles/space-systems-engineer/core/space_systems_core.py +980 -0
- package/roles/space-systems-engineer/templates/space-systems-template.md +88 -0
- package/roles/space-systems-engineer/tests/test_role_space_systems_engineer.py +117 -0
- package/roles/space-systems-engineer/tests/test_space_systems_engineer_core.py +247 -0
- package/roles/state-estimation-engineer/ROLE.md +154 -0
- package/roles/state-estimation-engineer/SOURCES.md +27 -0
- package/roles/state-estimation-engineer/cli.py +326 -0
- package/roles/state-estimation-engineer/core/state_estimation_core.py +958 -0
- package/roles/state-estimation-engineer/templates/nav-state-estimator-design-template.md +76 -0
- package/roles/state-estimation-engineer/tests/test_bundle_protocol.py +110 -0
- package/roles/state-estimation-engineer/tests/test_role_state_estimation_engineer.py +127 -0
- package/roles/state-estimation-engineer/tests/test_state_estimation_engineer_core.py +231 -0
- package/roles/structures-loads-engineer/ROLE.md +171 -0
- package/roles/structures-loads-engineer/SOURCES.md +44 -0
- package/roles/structures-loads-engineer/cli.py +219 -0
- package/roles/structures-loads-engineer/core/structures_loads_core.py +1112 -0
- package/roles/structures-loads-engineer/templates/loads-strength-report-template.md +96 -0
- package/roles/structures-loads-engineer/tests/test_bundle_protocol.py +101 -0
- package/roles/structures-loads-engineer/tests/test_role_structures_loads_engineer.py +147 -0
- package/roles/structures-loads-engineer/tests/test_structures_loads_core.py +261 -0
|
@@ -0,0 +1,88 @@
|
|
|
1
|
+
# Spacecraft Mission and Subsystem Design Report
|
|
2
|
+
|
|
3
|
+
**Spacecraft:** Aurora-1 Earth Observation Microsatellite
|
|
4
|
+
**Mission:** 600 km circular sun-synchronous Earth observation microsatellite, 5-year design life, 10:30 LTDN.
|
|
5
|
+
**Status:** draft-for-review
|
|
6
|
+
|
|
7
|
+
## 1. Mission and orbit
|
|
8
|
+
|
|
9
|
+
- Orbit: circular, altitude 600.0 km, inclination 97.8 deg (sun-synchronous), e = 0.000.
|
|
10
|
+
- Orbit radius: 6978 km; period 96.7 min (5801 s); 14.9 orbits/day; circular velocity 7558 m/s.
|
|
11
|
+
- Launch: rideshare, direct injection; design life 5 years.
|
|
12
|
+
|
|
13
|
+
## 2. Transfer / maneuvers and delta-v budget
|
|
14
|
+
|
|
15
|
+
- Injection: direct insertion (rideshare, direct injection); no interplanetary C3 or launch-window constraint applies (LEO circular mission).
|
|
16
|
+
- Delta-v contributions (m/s):
|
|
17
|
+
- Injection dispersion correction: 20.0
|
|
18
|
+
- Orbit maintenance (drag, 5 yr): 15.0
|
|
19
|
+
- Collision avoidance (2 maneuvers): 10.0
|
|
20
|
+
- End-of-life disposal (perigee lowering): 141.7
|
|
21
|
+
- Disposal leg is a single retrograde burn lowering perigee from 600 km to 100 km (Hohmann half-transfer, 141.7 m/s).
|
|
22
|
+
- Nominal total delta-v: 186.7 m/s; budgeted with 15% margin: **214.8 m/s**.
|
|
23
|
+
- Propellant (Isp 220 s, Tsiolkovsky): **15.7 kg**; wet mass 165.7 kg (9.5% propellant fraction).
|
|
24
|
+
|
|
25
|
+
## 3. Environment
|
|
26
|
+
|
|
27
|
+
- Eclipse (worst case, beta = 0): shadow fraction 36.7%; eclipse time 35.5 min per orbit.
|
|
28
|
+
- Perturbations at 600 km SSO: J2 nodal precession used for the sun-synchronous plane; drag is the long-term orbit maintenance driver (budgeted above); three-body effects negligible at this altitude.
|
|
29
|
+
- Radiation/debris: 600 km SSO sits in the inner belt proton/electron environment; parts list to a 25-50 krad(Si) total dose class (ECSS-Q-ST-60-15C practice); conjunction screening budgeted as 2 avoidance maneuvers over life.
|
|
30
|
+
|
|
31
|
+
## 4. ADCS
|
|
32
|
+
|
|
33
|
+
- Determination: star tracker (knowledge ~5 arcsec 1-sigma), sun sensors, 3-axis rate gyro, magnetometer; TRIAD/QUEST batch solutions on the C&DH.
|
|
34
|
+
- Control: 3 orthogonal wheels + 1 redundant reaction wheels, momentum capacity **1.0 N m s** each at 6000 rpm (wheel inertia 1.59 x 1e-3 kg m^2, h = J*omega); torque class 0.02 N m; magnetorquers for momentum desaturation.
|
|
35
|
+
- Sizing: slew 90 deg in 90 s -> slew momentum 0.349 N m s (J = 20 kg m^2 x omega 17.5 x 1e-3 rad/s); disturbance accumulation 0.0348 N m s/orbit; required with margin 0.58 N m s < capacity 1.0 N m s.
|
|
36
|
+
- Pointing error budget (3-sigma RSS): **0.048 deg** vs requirement 0.1 deg (margin x 2.1, meets).
|
|
37
|
+
- attitude determination (star tracker): 0.020 deg
|
|
38
|
+
- control error (deadband + PD residual): 0.030 deg
|
|
39
|
+
- wheel-induced jitter: 0.020 deg
|
|
40
|
+
- sensor/actuator alignment: 0.020 deg
|
|
41
|
+
- thermal distortion: 0.015 deg
|
|
42
|
+
|
|
43
|
+
## 5. Power and thermal
|
|
44
|
+
|
|
45
|
+
| Item | Day power (W) | Eclipse power (W) |
|
|
46
|
+
|---|---|---|
|
|
47
|
+
| Payload (optical imager) | 60 | 0 |
|
|
48
|
+
| Avionics / C&DH | 30 | 30 |
|
|
49
|
+
| ADCS | 15 | 15 |
|
|
50
|
+
| Comms (S-band Rx + X-band Tx duty) | 20 | 10 |
|
|
51
|
+
| Thermal (heater duty) | 15 | 25 |
|
|
52
|
+
| **Total** | **140** | **80** |
|
|
53
|
+
|
|
54
|
+
- Orbit-average load: 118.0 W over a 96.7 min orbit (36.7% eclipse).
|
|
55
|
+
- Battery: 80 W x 35.5 min eclipse at 30% DoD / 90% efficiency requires **175.2 Wh**; sized **215 Wh** Li-ion (margin 23%).
|
|
56
|
+
- Solar array: daylight power 248.5 W; EOL specific power 315.1 W/m^2 (AM0 1367 W/m^2, 30% cells, packing 0.85, 2%/yr x 5 yr) -> array area **0.79 m^2**.
|
|
57
|
+
- Thermal balance: 55 W continuous dissipation rejected by a radiator at 20 deg C (eps 0.90) -> **0.15 m^2**; eclipse heater duty 25 W is in the load table.
|
|
58
|
+
|
|
59
|
+
## 6. Comms
|
|
60
|
+
|
|
61
|
+
- Slant range at 5 deg elevation: 2329 km.
|
|
62
|
+
- Downlink (X-band 8.2 GHz, 150 Mbps): EIRP 31.0 dBW, path loss 178.1 dB, C/N0 98.8 dB-Hz, Eb/N0 17.0 dB vs 10.5 dB required -> **margin 6.5 dB**.
|
|
63
|
+
- Uplink (S-band 2.1 GHz, 4 kbps command): **margin 34.3 dB**.
|
|
64
|
+
- Data: 11.2 GB per 10 min pass x 6 passes/day = **67.5 GB/day** capacity vs 30 GB/day imaging need (margin x 2.2); on-board storage 256 GB.
|
|
65
|
+
|
|
66
|
+
## 7. Propulsion and C&DH
|
|
67
|
+
|
|
68
|
+
- Propulsion: 15.7 kg hydrazine (Isp 220 s) at 1008 kg/m^3 -> 15.6 L propellant, 16.6 L spherical Ti tank (radius 15.8 cm, wall 0.33 mm, shell 0.51 kg, pressurant 3.9 g He); 4 x 1 N thrusters.
|
|
69
|
+
- C&DH: single rad-tolerant computer (LEON-class) with watchdog + triple-redundant command path; ECSS-E-ST-40 / ECSS-Q-ST-80 software and product assurance context; on-board storage solid-state recorder with EDAC.
|
|
70
|
+
|
|
71
|
+
## 8. System budgets
|
|
72
|
+
|
|
73
|
+
| Budget | Value | Margin policy | Closes |
|
|
74
|
+
|---|---|---|---|
|
|
75
|
+
| mass (dry) | 150 kg (subsystems sum to stated 150 kg) | 20% at subsystem level in stated rows | YES |
|
|
76
|
+
| mass (wet) | 165.7 kg | propellant on top of dry budget | YES |
|
|
77
|
+
| power | 140 W day / 80 W eclipse | battery 23%, array 20% | YES |
|
|
78
|
+
| delta-v | 186.7 m/s nominal / 214.8 m/s budgeted | 15% | YES |
|
|
79
|
+
| pointing | 0.048 deg (3-sigma) | vs 0.1 deg requirement | YES |
|
|
80
|
+
| link margin | down 6.5 dB / up 34.3 dB | >= 3 dB | YES |
|
|
81
|
+
|
|
82
|
+
## 9. Conclusions and open items
|
|
83
|
+
|
|
84
|
+
- Budgets close? **YES - all budgets close** (delta-v True, power True, pointing True, link True, mass True).
|
|
85
|
+
- Open items for detailed phase: refined disturbance torque model with beta-angle profile; flight-like array incidence/cosine losses; thermal model with component-level margins; star tracker alignment campaign; launch-vehicle interface agreement and actual dispersion.
|
|
86
|
+
|
|
87
|
+
---
|
|
88
|
+
*Generated by Aero Agent Roles space-systems-engineer core (2026-09-05). DRAFT for human space systems lead review. Not launch readiness. Not an approval document.*
|
|
@@ -0,0 +1,117 @@
|
|
|
1
|
+
#!/usr/bin/env python3
|
|
2
|
+
"""Role test: space-systems-engineer."""
|
|
3
|
+
import os
|
|
4
|
+
import re
|
|
5
|
+
import unittest
|
|
6
|
+
|
|
7
|
+
ROLES_REPO = os.path.dirname(os.path.dirname(os.path.dirname(os.path.dirname(
|
|
8
|
+
os.path.abspath(__file__)))))
|
|
9
|
+
AEROSKILLS = os.environ.get("AEROSKILLS_DEV", os.path.expanduser("~/AeroSkills"))
|
|
10
|
+
HAS_SKILLS = os.path.isdir(os.path.join(AEROSKILLS, "skills"))
|
|
11
|
+
ROLE_DIR = os.path.join(ROLES_REPO, "roles", "space-systems-engineer")
|
|
12
|
+
TEMPLATE = os.path.join(ROLE_DIR, "templates", "space-systems-template.md")
|
|
13
|
+
|
|
14
|
+
EXPECTED_BOUND = [
|
|
15
|
+
"space-systems/mission-design/mission-delta-v-budget",
|
|
16
|
+
"space-systems/mission-design/launch-window-analysis",
|
|
17
|
+
"space-systems/mission-design/c3-departure-energy",
|
|
18
|
+
"space-systems/mission-design/entry-descent-landing",
|
|
19
|
+
"space-systems/mission-design/radiation-debris",
|
|
20
|
+
"space-systems/orbit-mechanics/keplerian-elements",
|
|
21
|
+
"space-systems/orbit-mechanics/kepler-orbit-propagation",
|
|
22
|
+
"space-systems/orbit-mechanics/hohmann-transfer",
|
|
23
|
+
"space-systems/orbit-mechanics/bi-elliptic-transfer",
|
|
24
|
+
"space-systems/orbit-mechanics/plane-change-maneuver",
|
|
25
|
+
"space-systems/orbit-mechanics/lambert-transfer",
|
|
26
|
+
"space-systems/orbit-mechanics/gravity-assist-swingby",
|
|
27
|
+
"space-systems/orbit-mechanics/low-thrust-spiral",
|
|
28
|
+
"space-systems/orbit-mechanics/orbital-perturbations",
|
|
29
|
+
"space-systems/orbit-mechanics/sun-synchronous-inclination",
|
|
30
|
+
"space-systems/orbit-mechanics/ground-track-repeat",
|
|
31
|
+
"space-systems/orbit-mechanics/eclipse-time",
|
|
32
|
+
"space-systems/orbit-mechanics/satellite-coverage",
|
|
33
|
+
"space-systems/orbit-mechanics/walker-delta-constellation",
|
|
34
|
+
"space-systems/orbit-mechanics/geostationary-station-keeping",
|
|
35
|
+
"space-systems/orbit-mechanics/conjunction-assessment",
|
|
36
|
+
"space-systems/orbit-mechanics/three-body-libration",
|
|
37
|
+
"space-systems/orbit-mechanics/orbital-decay",
|
|
38
|
+
"space-systems/orbit-mechanics/clohessy-wiltshire",
|
|
39
|
+
"space-systems/adcs/attitude-determination-triad",
|
|
40
|
+
"space-systems/adcs/attitude-determination-quest",
|
|
41
|
+
"space-systems/adcs/star-tracker",
|
|
42
|
+
"space-systems/adcs/sun-pointing",
|
|
43
|
+
"space-systems/adcs/reaction-wheel-control",
|
|
44
|
+
"space-systems/adcs/control-moment-gyro",
|
|
45
|
+
"space-systems/adcs/magnetorquer-control",
|
|
46
|
+
"space-systems/adcs/attitude-control-sizing",
|
|
47
|
+
"space-systems/adcs/pointing-error-budget",
|
|
48
|
+
"space-systems/adcs/gyro-allan-variance",
|
|
49
|
+
"space-systems/subsystems/communication-link-budget",
|
|
50
|
+
"space-systems/subsystems/antenna-aperture-sizing",
|
|
51
|
+
"space-systems/subsystems/power-thermal-budget",
|
|
52
|
+
"space-systems/subsystems/solar-array-sizing",
|
|
53
|
+
"space-systems/subsystems/spacecraft-battery-sizing",
|
|
54
|
+
"space-systems/subsystems/thermal-design",
|
|
55
|
+
"space-systems/subsystems/propellant-tank-sizing",
|
|
56
|
+
"space-systems/subsystems/command-data-handling",
|
|
57
|
+
"space-systems/ecss/systems-engineering",
|
|
58
|
+
"space-systems/ecss/software-engineering",
|
|
59
|
+
"space-systems/ecss/software-verification"
|
|
60
|
+
]
|
|
61
|
+
|
|
62
|
+
STAGES = [
|
|
63
|
+
"1. Mission delta-v",
|
|
64
|
+
"2. Transfers",
|
|
65
|
+
"3. Launch window",
|
|
66
|
+
"4. Constellation/coverage",
|
|
67
|
+
"5. Environment",
|
|
68
|
+
"6. Rendezvous",
|
|
69
|
+
"7. ADCS determination",
|
|
70
|
+
"8. ADCS control",
|
|
71
|
+
"9. Power/thermal",
|
|
72
|
+
"10. Comms",
|
|
73
|
+
"11. Propulsion/C&DH",
|
|
74
|
+
"12. ECSS context",
|
|
75
|
+
"13. Report"
|
|
76
|
+
]
|
|
77
|
+
|
|
78
|
+
|
|
79
|
+
def role_text():
|
|
80
|
+
p = os.path.join(ROLE_DIR, "ROLE.md")
|
|
81
|
+
return open(p).read() if os.path.exists(p) else None
|
|
82
|
+
|
|
83
|
+
|
|
84
|
+
class TestSpaceSystemsEngineerRole(unittest.TestCase):
|
|
85
|
+
|
|
86
|
+
def test_bound_skills_resolve(self):
|
|
87
|
+
if not HAS_SKILLS:
|
|
88
|
+
self.skipTest("skills checkout absent (cross-repo dev check)")
|
|
89
|
+
for leaf in EXPECTED_BOUND:
|
|
90
|
+
self.assertTrue(
|
|
91
|
+
os.path.exists(os.path.join(AEROSKILLS, "skills", leaf, "SKILL.md")),
|
|
92
|
+
f"bound skill missing: {leaf}")
|
|
93
|
+
|
|
94
|
+
def test_stages_ordered(self):
|
|
95
|
+
role = role_text()
|
|
96
|
+
self.assertIsNotNone(role)
|
|
97
|
+
wf = role[role.find("## Workflow"):role.find("## Evidence gates")]
|
|
98
|
+
idx = [wf.find(s) for s in STAGES]
|
|
99
|
+
self.assertTrue(all(i >= 0 for i in idx), "stage missing in workflow")
|
|
100
|
+
self.assertEqual(idx, sorted(idx), "stage order not deterministic")
|
|
101
|
+
|
|
102
|
+
def test_template_present(self):
|
|
103
|
+
self.assertTrue(os.path.exists(TEMPLATE), "deliverable template missing")
|
|
104
|
+
|
|
105
|
+
def test_boundaries(self):
|
|
106
|
+
role = role_text()
|
|
107
|
+
self.assertIsNotNone(role)
|
|
108
|
+
for phrase in ["sign_off_required: true", "forbidden"]:
|
|
109
|
+
self.assertIn(phrase, role)
|
|
110
|
+
|
|
111
|
+
def test_sources(self):
|
|
112
|
+
self.assertTrue(os.path.exists(os.path.join(ROLE_DIR, "SOURCES.md")),
|
|
113
|
+
"SOURCES.md missing")
|
|
114
|
+
|
|
115
|
+
|
|
116
|
+
if __name__ == "__main__":
|
|
117
|
+
unittest.main()
|
|
@@ -0,0 +1,247 @@
|
|
|
1
|
+
#!/usr/bin/env python3
|
|
2
|
+
"""Test space_systems_core: the executable engine of the Space Systems role.
|
|
3
|
+
|
|
4
|
+
Proves the role can DO its job standalone (no AeroSkills needed): orbit
|
|
5
|
+
mechanics, delta-v budgeting and propellant sizing, reaction wheel
|
|
6
|
+
sizing, power/thermal closure, comms link budget, report generation,
|
|
7
|
+
and evidence-gate checks. Anchor values come from the bound AeroSkills
|
|
8
|
+
space-systems leaves (hohmann-transfer, mission-delta-v-budget,
|
|
9
|
+
power-thermal-budget, solar-array-sizing, eclipse-time,
|
|
10
|
+
reaction-wheel-control, communication-link-budget).
|
|
11
|
+
"""
|
|
12
|
+
import os
|
|
13
|
+
import sys
|
|
14
|
+
import unittest
|
|
15
|
+
|
|
16
|
+
sys.path.insert(0, os.path.join(os.path.dirname(os.path.abspath(__file__)), "..", "core"))
|
|
17
|
+
from space_systems_core import ( # noqa: E402
|
|
18
|
+
MU_EARTH, RE_EARTH, apply_margin,
|
|
19
|
+
battery_capacity_required, build_report, check_report,
|
|
20
|
+
check_report_markdown, circular_velocity, comms_link_budget,
|
|
21
|
+
eclipse_geometry, eol_specific_power, example_mission,
|
|
22
|
+
example_report_markdown, free_space_path_loss, hohmann_burn_delta_v,
|
|
23
|
+
mission_delta_v_budget, orbit_period_seconds, perigee_lowering_delta_v,
|
|
24
|
+
pointing_error_budget, power_and_thermal, propellant_mass,
|
|
25
|
+
radiator_area, reaction_wheel_sizing, render_report_markdown,
|
|
26
|
+
slant_range_m, solar_array_daylight_power, sum_delta_v, wet_mass,
|
|
27
|
+
)
|
|
28
|
+
|
|
29
|
+
|
|
30
|
+
class TestOrbitMechanics(unittest.TestCase):
|
|
31
|
+
"""Domain rules: vis-viva, periods, Hohmann and disposal burns."""
|
|
32
|
+
|
|
33
|
+
def test_circular_velocity_anchors(self):
|
|
34
|
+
# hohmann-transfer leaf anchors: LEO 6878 km -> ~7613 m/s,
|
|
35
|
+
# GEO 42164 km -> ~3075 m/s.
|
|
36
|
+
self.assertAlmostEqual(circular_velocity(6878e3), 7612.7, delta=1.0)
|
|
37
|
+
self.assertAlmostEqual(circular_velocity(42164e3), 3074.7, delta=1.0)
|
|
38
|
+
|
|
39
|
+
def test_geostationary_period(self):
|
|
40
|
+
self.assertAlmostEqual(orbit_period_seconds(42164e3) / 3600.0,
|
|
41
|
+
23.934, delta=0.05)
|
|
42
|
+
|
|
43
|
+
def test_hohmann_leo_to_geo_total(self):
|
|
44
|
+
# Leaf reference: LEO(Re+500 km) -> GEO totals about 3816 m/s.
|
|
45
|
+
dv = hohmann_burn_delta_v(RE_EARTH + 500e3, 42164e3)
|
|
46
|
+
self.assertAlmostEqual(dv["total_m_s"], 3816.0, delta=60.0)
|
|
47
|
+
self.assertEqual(dv["total_m_s"],
|
|
48
|
+
dv["dv1_m_s"] + dv["dv2_m_s"])
|
|
49
|
+
|
|
50
|
+
def test_disposal_burn_positive_and_bounded(self):
|
|
51
|
+
dv = perigee_lowering_delta_v(600.0, 100.0)
|
|
52
|
+
v_circ = circular_velocity(RE_EARTH + 600e3)
|
|
53
|
+
self.assertGreater(dv, 0.0)
|
|
54
|
+
self.assertLess(dv, v_circ)
|
|
55
|
+
# 600 km -> 100 km perigee is a ~140 m/s class burn.
|
|
56
|
+
self.assertAlmostEqual(dv, 141.7, delta=3.0)
|
|
57
|
+
|
|
58
|
+
|
|
59
|
+
class TestDeltaVAndPropellant(unittest.TestCase):
|
|
60
|
+
"""Domain rules: rocket equation, margins (mission-delta-v-budget)."""
|
|
61
|
+
|
|
62
|
+
def test_propellant_mass_anchor(self):
|
|
63
|
+
# Leaf anchor: dv 2941.995 m/s, 1000 kg dry, 300 s -> ~1718.28 kg.
|
|
64
|
+
self.assertAlmostEqual(propellant_mass(2941.995, 1000.0, 300.0),
|
|
65
|
+
1718.28, delta=0.5)
|
|
66
|
+
self.assertAlmostEqual(wet_mass(2941.995, 1000.0, 300.0),
|
|
67
|
+
2718.28, delta=0.5)
|
|
68
|
+
|
|
69
|
+
def test_zero_dv_zero_propellant(self):
|
|
70
|
+
self.assertEqual(propellant_mass(0.0, 1000.0, 300.0), 0.0)
|
|
71
|
+
|
|
72
|
+
def test_sum_and_margin(self):
|
|
73
|
+
self.assertEqual(sum_delta_v([100.0, 200.0, 50.0]), 350.0)
|
|
74
|
+
self.assertAlmostEqual(apply_margin(350.0, 0.15), 402.5, places=6)
|
|
75
|
+
self.assertEqual(apply_margin(350.0, 0.0), 350.0)
|
|
76
|
+
|
|
77
|
+
def test_example_budget_structure(self):
|
|
78
|
+
budget = mission_delta_v_budget(example_mission())
|
|
79
|
+
self.assertAlmostEqual(
|
|
80
|
+
budget["nominal_dv_m_s"],
|
|
81
|
+
sum(budget["contributions"].values()), places=6)
|
|
82
|
+
self.assertAlmostEqual(budget["budgeted_dv_m_s"],
|
|
83
|
+
budget["nominal_dv_m_s"] * 1.15, places=6)
|
|
84
|
+
self.assertGreater(budget["propellant_mass_kg"], 0.0)
|
|
85
|
+
self.assertLess(budget["propellant_fraction"], 0.2)
|
|
86
|
+
# disposal dominates a 600 km mission budget (realism marker)
|
|
87
|
+
self.assertGreater(
|
|
88
|
+
budget["contributions"]["End-of-life disposal (perigee lowering)"],
|
|
89
|
+
budget["contributions"]["Injection dispersion correction"])
|
|
90
|
+
|
|
91
|
+
|
|
92
|
+
class TestEclipseAndPower(unittest.TestCase):
|
|
93
|
+
"""Domain rules: eclipse geometry, battery and solar array sizing."""
|
|
94
|
+
|
|
95
|
+
def test_eclipse_geometry_600km(self):
|
|
96
|
+
g = eclipse_geometry(600.0)
|
|
97
|
+
self.assertAlmostEqual(g["period_s"], 5801.0, delta=20.0)
|
|
98
|
+
self.assertAlmostEqual(g["shadow_fraction"], 0.367, delta=0.005)
|
|
99
|
+
self.assertAlmostEqual(g["eclipse_time_min"], 35.5, delta=0.4)
|
|
100
|
+
self.assertAlmostEqual(g["daylight_fraction"],
|
|
101
|
+
1.0 - g["shadow_fraction"], places=9)
|
|
102
|
+
|
|
103
|
+
def test_battery_capacity_required(self):
|
|
104
|
+
# 80 W over a 35.5 min eclipse at 30% DoD / 90% efficiency.
|
|
105
|
+
wh = battery_capacity_required(80.0, 35.5, 0.30, 0.90)
|
|
106
|
+
self.assertAlmostEqual(wh, 175.3, delta=0.2)
|
|
107
|
+
|
|
108
|
+
def test_solar_array_daylight_power_anchor(self):
|
|
109
|
+
# power-thermal-budget leaf anchor: 500 W, f=0.35, no margin.
|
|
110
|
+
self.assertAlmostEqual(solar_array_daylight_power(500.0, 0.35, 1.0),
|
|
111
|
+
769.23, delta=0.5)
|
|
112
|
+
self.assertAlmostEqual(solar_array_daylight_power(500.0, 0.35, 1.0, 0.20),
|
|
113
|
+
923.08, delta=0.5)
|
|
114
|
+
|
|
115
|
+
def test_eol_specific_power_anchor(self):
|
|
116
|
+
# solar-array-sizing leaf anchor: 1367*0.30*0.85*0.98^10.
|
|
117
|
+
self.assertAlmostEqual(eol_specific_power(1367.0, 0.30, 0.85, 0.02, 10),
|
|
118
|
+
284.82, delta=0.05)
|
|
119
|
+
|
|
120
|
+
def test_radiator_area(self):
|
|
121
|
+
# 55 W at 293.15 K, eps 0.9 -> ~0.15 m^2.
|
|
122
|
+
self.assertAlmostEqual(radiator_area(55.0, 293.15, 3.0, 0.90),
|
|
123
|
+
0.146, delta=0.01)
|
|
124
|
+
|
|
125
|
+
def test_example_power_closes(self):
|
|
126
|
+
pw = power_and_thermal(example_mission())
|
|
127
|
+
self.assertGreaterEqual(pw["battery_margin"], 0.20)
|
|
128
|
+
self.assertAlmostEqual(pw["array_area_m2"], 0.79, delta=0.03)
|
|
129
|
+
self.assertAlmostEqual(pw["battery_sized_wh"], 215.0, delta=1.0)
|
|
130
|
+
|
|
131
|
+
|
|
132
|
+
class TestAdcs(unittest.TestCase):
|
|
133
|
+
"""Domain rules: wheel sizing h = J*omega and pointing RSS."""
|
|
134
|
+
|
|
135
|
+
def test_slew_momentum_is_j_times_omega(self):
|
|
136
|
+
ad = reaction_wheel_sizing(example_mission(), 5801.0)
|
|
137
|
+
omega = (3.141592653589793 / 2.0) / 90.0
|
|
138
|
+
self.assertAlmostEqual(ad["omega_slew_rad_s"], omega, places=9)
|
|
139
|
+
self.assertAlmostEqual(ad["slew_momentum_nms"], 20.0 * omega,
|
|
140
|
+
places=4)
|
|
141
|
+
|
|
142
|
+
def test_wheel_inertia_from_momentum_capacity(self):
|
|
143
|
+
ad = reaction_wheel_sizing(example_mission(), 5801.0)
|
|
144
|
+
# h = J_w * omega_max: 1.0 N m s at 6000 rpm.
|
|
145
|
+
self.assertAlmostEqual(ad["wheel_inertia_kgm2"], 1.0 / 628.3185,
|
|
146
|
+
delta=1e-6)
|
|
147
|
+
self.assertGreater(ad["required_momentum_nms"], 0.3)
|
|
148
|
+
self.assertLess(ad["required_momentum_nms"],
|
|
149
|
+
ad["wheel_momentum_capacity_nms"])
|
|
150
|
+
|
|
151
|
+
def test_pointing_budget_meets(self):
|
|
152
|
+
pt = pointing_error_budget(example_mission())
|
|
153
|
+
self.assertAlmostEqual(pt["rss_deg"], 0.0482, delta=0.001)
|
|
154
|
+
self.assertTrue(pt["meets"])
|
|
155
|
+
self.assertGreater(pt["margin"], 2.0)
|
|
156
|
+
|
|
157
|
+
|
|
158
|
+
class TestComms(unittest.TestCase):
|
|
159
|
+
"""Domain rules: Friis path loss and link margins."""
|
|
160
|
+
|
|
161
|
+
def test_slant_range_600km_5deg(self):
|
|
162
|
+
self.assertAlmostEqual(slant_range_m(600.0, 5.0) / 1000.0,
|
|
163
|
+
2329.0, delta=10.0)
|
|
164
|
+
|
|
165
|
+
def test_free_space_path_loss_x_band(self):
|
|
166
|
+
fsl = free_space_path_loss(2329e3, 8.2e9)
|
|
167
|
+
self.assertAlmostEqual(fsl, 178.1, delta=0.5)
|
|
168
|
+
|
|
169
|
+
def test_example_links_close(self):
|
|
170
|
+
cm = comms_link_budget(example_mission())
|
|
171
|
+
self.assertGreaterEqual(cm["downlink"]["margin_db"], 3.0)
|
|
172
|
+
self.assertGreaterEqual(cm["uplink"]["margin_db"], 3.0)
|
|
173
|
+
self.assertGreater(cm["daily_capacity_gb"],
|
|
174
|
+
cm["imaging_data_gb_per_day"])
|
|
175
|
+
|
|
176
|
+
|
|
177
|
+
class TestReportBuilderAndGates(unittest.TestCase):
|
|
178
|
+
|
|
179
|
+
def test_example_model_values(self):
|
|
180
|
+
model = build_report(example_mission())
|
|
181
|
+
self.assertEqual(model["status"], "draft-for-review")
|
|
182
|
+
self.assertEqual(model["orbit"]["altitude_km"], 600.0)
|
|
183
|
+
dv = model["delta_v"]
|
|
184
|
+
self.assertGreater(dv["nominal_dv_m_s"], 180.0)
|
|
185
|
+
self.assertAlmostEqual(dv["budgeted_dv_m_s"],
|
|
186
|
+
dv["nominal_dv_m_s"] * 1.15, places=6)
|
|
187
|
+
self.assertGreater(dv["propellant_mass_kg"], 15.0)
|
|
188
|
+
self.assertAlmostEqual(model["adcs"]["wheel_momentum_capacity_nms"],
|
|
189
|
+
1.0, places=3)
|
|
190
|
+
self.assertLess(model["power"]["array_area_m2"], 1.0)
|
|
191
|
+
self.assertTrue(model["pointing"]["meets"])
|
|
192
|
+
self.assertTrue(model["comms"]["downlink_meets"])
|
|
193
|
+
self.assertTrue(model["mass"]["closes"])
|
|
194
|
+
self.assertTrue(all(model["verdicts"].values()), model["verdicts"])
|
|
195
|
+
|
|
196
|
+
def test_render_has_all_sections_and_markers(self):
|
|
197
|
+
md = example_report_markdown()
|
|
198
|
+
for n in range(1, 10):
|
|
199
|
+
self.assertIn(f"## {n}.", md, f"section {n} missing")
|
|
200
|
+
low = md.lower()
|
|
201
|
+
self.assertIn("draft", low)
|
|
202
|
+
self.assertIn("not an approval", low)
|
|
203
|
+
self.assertIn("not launch readiness", low)
|
|
204
|
+
self.assertGreater(len(md), 4000)
|
|
205
|
+
|
|
206
|
+
def test_core_gates_all_pass(self):
|
|
207
|
+
model = build_report(example_mission())
|
|
208
|
+
gates = check_report(model)
|
|
209
|
+
self.assertTrue(gates["all_pass"], gates)
|
|
210
|
+
|
|
211
|
+
def test_markdown_gates_all_pass(self):
|
|
212
|
+
md = example_report_markdown()
|
|
213
|
+
gates = check_report_markdown(md)
|
|
214
|
+
self.assertTrue(gates["all_pass"], gates)
|
|
215
|
+
|
|
216
|
+
def test_gate_fails_on_approval_status(self):
|
|
217
|
+
model = build_report(example_mission())
|
|
218
|
+
model["status"] = "approved"
|
|
219
|
+
gates = check_report(model)
|
|
220
|
+
self.assertFalse(gates["sign_off_honest"])
|
|
221
|
+
self.assertFalse(gates["all_pass"])
|
|
222
|
+
|
|
223
|
+
def test_gate_fails_when_pointing_exceeds(self):
|
|
224
|
+
model = build_report(example_mission())
|
|
225
|
+
model["pointing"]["requirement_deg"] = 0.01
|
|
226
|
+
model["pointing"]["meets"] = False
|
|
227
|
+
gates = check_report(model)
|
|
228
|
+
self.assertFalse(gates["pointing_meets"])
|
|
229
|
+
self.assertFalse(gates["all_pass"])
|
|
230
|
+
|
|
231
|
+
def test_deterministic_build(self):
|
|
232
|
+
a = build_report(example_mission())
|
|
233
|
+
b = build_report(example_mission())
|
|
234
|
+
self.assertEqual(a["delta_v"]["nominal_dv_m_s"],
|
|
235
|
+
b["delta_v"]["nominal_dv_m_s"])
|
|
236
|
+
|
|
237
|
+
def test_standalone_no_skills_repo(self):
|
|
238
|
+
# Core must work with no AeroSkills present.
|
|
239
|
+
os.environ["AEROSKILLS_DEV"] = "/nonexistent"
|
|
240
|
+
model = build_report(example_mission())
|
|
241
|
+
self.assertGreater(model["delta_v"]["budgeted_dv_m_s"], 0.0)
|
|
242
|
+
md = render_report_markdown(model)
|
|
243
|
+
self.assertGreater(len(md), 4000)
|
|
244
|
+
|
|
245
|
+
|
|
246
|
+
if __name__ == "__main__":
|
|
247
|
+
unittest.main()
|
|
@@ -0,0 +1,154 @@
|
|
|
1
|
+
---
|
|
2
|
+
type: role
|
|
3
|
+
name: state-estimation-engineer
|
|
4
|
+
title: "State Estimation Engineer"
|
|
5
|
+
status: draft
|
|
6
|
+
domain: gnc-autonomy
|
|
7
|
+
deliverable_type: "navigation state estimator design report"
|
|
8
|
+
standards_bound:
|
|
9
|
+
- id: arp4754a
|
|
10
|
+
tier: TIER-2
|
|
11
|
+
reference-only: true
|
|
12
|
+
skills_bound:
|
|
13
|
+
- gnc-autonomy/estimation-filtering/alpha-beta-filter
|
|
14
|
+
- gnc-autonomy/estimation-filtering/complementary-filter
|
|
15
|
+
- gnc-autonomy/estimation-filtering/extended-kalman-filter
|
|
16
|
+
- gnc-autonomy/estimation-filtering/interacting-multiple-model-filter
|
|
17
|
+
- gnc-autonomy/estimation-filtering/particle-filter
|
|
18
|
+
- gnc-autonomy/estimation-filtering/rts-smoother
|
|
19
|
+
- gnc-autonomy/estimation-filtering/unscented-kalman-filter
|
|
20
|
+
tools_allowed: [stdlib, offline-file-processing]
|
|
21
|
+
forbidden:
|
|
22
|
+
- "release navigation/flight software"
|
|
23
|
+
- "authorize flight"
|
|
24
|
+
- "claim certification approval"
|
|
25
|
+
- "reproduce proprietary standard text"
|
|
26
|
+
- "assert estimator performance without a checkable noise model"
|
|
27
|
+
sign_off_required: true
|
|
28
|
+
license: Apache-2.0
|
|
29
|
+
compatibility: "agentskills.io ROLE.md; any SKILL.md host"
|
|
30
|
+
metadata:
|
|
31
|
+
version: 0.1.0
|
|
32
|
+
author: ashfordeOU
|
|
33
|
+
skills_release: "v1.3.0+"
|
|
34
|
+
---
|
|
35
|
+
|
|
36
|
+
# State Estimation Engineer
|
|
37
|
+
|
|
38
|
+
## Role identity
|
|
39
|
+
|
|
40
|
+
This role designs and analyzes navigation state estimators for aerospace
|
|
41
|
+
vehicles: the estimators that fuse inertial, GNSS, attitude-reference,
|
|
42
|
+
and aiding sensors into the continuous attitude, position, velocity, and
|
|
43
|
+
bias states a guidance or control loop consumes. Use when a project must
|
|
44
|
+
select and size an estimator (attitude observer, GNSS/INS navigation
|
|
45
|
+
filter, nonlinear tracking filter), choose process/measurement noise
|
|
46
|
+
models, verify observability and consistency, or design offline
|
|
47
|
+
post-processing. Do NOT use for pure control design (see GNC Engineer
|
|
48
|
+
role), for sensor hardware selection, or when the vehicle has no
|
|
49
|
+
navigation/estimation need. Bind the gnc-autonomy/estimation-filtering
|
|
50
|
+
cluster.
|
|
51
|
+
|
|
52
|
+
## Deliverable contract
|
|
53
|
+
|
|
54
|
+
The role produces the **Navigation State Estimator Design Report** for a
|
|
55
|
+
reference item (an INS/GPS or attitude estimator), containing:
|
|
56
|
+
|
|
57
|
+
1. **Architecture** — estimator class, channels (attitude complementary
|
|
58
|
+
filter; position/velocity Kalman recursion; nonlinear EKF/UKF
|
|
59
|
+
updates), sensor set, frames, sample rates, and design inputs
|
|
60
|
+
(noise model: process intensity q, measurement variance r).
|
|
61
|
+
2. **Design numbers** — complementary-filter gains and drift/lag
|
|
62
|
+
anchors; discrete constant-velocity Kalman covariance/gain recursion
|
|
63
|
+
results; alpha-beta companion gains (Benedict-Bordner, Kalata);
|
|
64
|
+
EKF linearization (Jacobian, innovation, gain, corrected state);
|
|
65
|
+
NEES and particle ESS verification figures; RTS smoother covariance
|
|
66
|
+
reduction; observability determinant/rank.
|
|
67
|
+
3. **Verification evidence + open items** — evidence-gate summary and
|
|
68
|
+
what the human navigation engineer must still resolve before
|
|
69
|
+
implementation.
|
|
70
|
+
|
|
71
|
+
## Workflow (stages → bound skills)
|
|
72
|
+
|
|
73
|
+
| Stage | Loads skill | Produces |
|
|
74
|
+
|---|---|---|
|
|
75
|
+
| 1. Architecture + noise model | (all estimation-filtering leaves) | estimator class, channels, design inputs |
|
|
76
|
+
| 2. Attitude channel | complementary-filter | gains, drift/lag anchors, innovation tolerance |
|
|
77
|
+
| 3. Navigation channel | rts-smoother + interacting-multiple-model-filter | CV Kalman recursion numbers, model matrices |
|
|
78
|
+
| 4. Fixed-gain companion | alpha-beta-filter | Benedict-Bordner + Kalata gains from the tracking index |
|
|
79
|
+
| 5. Nonlinear updates | extended-kalman-filter + unscented-kalman-filter | linearized Jacobian, innovation, gain, corrected state, NEES |
|
|
80
|
+
| 6. Fallbacks | particle-filter + interacting-multiple-model-filter | SIR ESS rule, IMM maneuvering bank |
|
|
81
|
+
| 7. Offline post-processing | rts-smoother | fixed-interval smoothing covariance reduction |
|
|
82
|
+
| 8. Observability | (all) | observability matrix rank/verdict, bias-observability note |
|
|
83
|
+
| 9. Report | (all above) | the Navigation State Estimator Design Report |
|
|
84
|
+
|
|
85
|
+
## Evidence gates
|
|
86
|
+
|
|
87
|
+
- Stage 2 done = complementary-filter gains numeric + drift/lag anchors
|
|
88
|
+
present.
|
|
89
|
+
- Stage 3 done = Kalman recursion produced gains and covariances over
|
|
90
|
+
the design horizon.
|
|
91
|
+
- Stage 4 done = alpha-beta gains computed from the tracking index and
|
|
92
|
+
consistent with the converged Kalman gain.
|
|
93
|
+
- Stage 5 done = EKF Jacobian/innovation/gain present and NEES finite.
|
|
94
|
+
- Stage 8 done = observability determinant/rank computed with a verdict.
|
|
95
|
+
- FINAL = every section has a number from the role core grounded in the
|
|
96
|
+
bound leaf equations or the leaf documentation; nothing asserted
|
|
97
|
+
without a checkable basis; output marked DRAFT.
|
|
98
|
+
|
|
99
|
+
## Boundary / forbidden
|
|
100
|
+
|
|
101
|
+
- NEVER release navigation or flight software, and NEVER authorize
|
|
102
|
+
flight — implementation and flight release are human engineering
|
|
103
|
+
decisions.
|
|
104
|
+
- NEVER claim certification or regulatory approval.
|
|
105
|
+
- NEVER assert estimator performance without a checkable noise model
|
|
106
|
+
(the report's noise values are inputs that trace to sensor
|
|
107
|
+
datasheets).
|
|
108
|
+
- NEVER reproduce proprietary standard text (summary-not-copy).
|
|
109
|
+
- Output is a DRAFT for human review — mark it draft.
|
|
110
|
+
|
|
111
|
+
## Verification
|
|
112
|
+
|
|
113
|
+
The role runs STANDALONE: `core/state_estimation_core.py` is an
|
|
114
|
+
executable engine that computes the complementary-filter design anchors,
|
|
115
|
+
runs the discrete constant-velocity Kalman recursion (same F/Q/H model
|
|
116
|
+
as the bound rts-smoother and IMM leaves), the alpha-beta
|
|
117
|
+
(Benedict-Bordner/Kalata) gains, the EKF linearization, NEES/ESS
|
|
118
|
+
consistency metrics, the RTS smoother reduction, and the observability
|
|
119
|
+
analysis, BUILDS the report, and gate-checks deliverables. No AeroSkills
|
|
120
|
+
checkout required.
|
|
121
|
+
|
|
122
|
+
Run the role:
|
|
123
|
+
```bash
|
|
124
|
+
python3 cli.py build --out report.md # example item
|
|
125
|
+
python3 cli.py build --out report.md --bundle # + evidence bundle
|
|
126
|
+
python3 cli.py build --dt 0.5 --steps 120 --r 1.0 # variant facts
|
|
127
|
+
python3 cli.py build --profile program.json # program header
|
|
128
|
+
python3 cli.py check --file report.md # gate-check
|
|
129
|
+
```
|
|
130
|
+
|
|
131
|
+
Tests:
|
|
132
|
+
- tests/test_state_estimation_engineer_core.py: domain rules (gains,
|
|
133
|
+
recursion, linearization, metrics, observability) + builder + gates +
|
|
134
|
+
standalone (no skills repo)
|
|
135
|
+
- tests/test_role_state_estimation_engineer.py: bound-skill resolution
|
|
136
|
+
(skips if the skills repo is absent) + workflow + template + boundaries
|
|
137
|
+
- tests/test_bundle_protocol.py: build --bundle emits the evidence
|
|
138
|
+
bundle, gates all pass, dispatch cross-checks agree when AeroSkills
|
|
139
|
+
is present, standalone is honest
|
|
140
|
+
|
|
141
|
+
Bound skills in Aero Agent Skills deepen individual stages when the
|
|
142
|
+
library is present (attitude filter logic, Kalman recursion,
|
|
143
|
+
alpha-beta gains, EKF Jacobian, NEES, ESS); the core engine does not
|
|
144
|
+
depend on them. With the library present, `--bundle` dispatches the
|
|
145
|
+
bound leaf logic and records core/skill agreement (delta) in
|
|
146
|
+
provenance.json — two independent implementations of the same
|
|
147
|
+
equations agreeing.
|
|
148
|
+
|
|
149
|
+
## Compliance
|
|
150
|
+
|
|
151
|
+
- arp4754a TIER-2 reference-only per standards-map; no verbatim.
|
|
152
|
+
- SOURCES.md records acquisition/extraction/verification status.
|
|
153
|
+
- Estimator mathematics referenced in SOURCES.md are public-domain
|
|
154
|
+
educational texts and the bound leaf logic files.
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
# SOURCES.md - State Estimation Engineer
|
|
2
|
+
|
|
3
|
+
Standards and references this role draws on. Summary-not-copy: see
|
|
4
|
+
[STANDARDS.md](../../STANDARDS.md) for the full rule and purchase links.
|
|
5
|
+
No proprietary text is reproduced anywhere in this role.
|
|
6
|
+
|
|
7
|
+
| Source | Role use | Gated |
|
|
8
|
+
|---|---|---|
|
|
9
|
+
| SAE ARP4754A | development-assurance context for aircraft systems (reference-only; the estimator supports system functions whose assurance is managed at system level) | true |
|
|
10
|
+
| gnc-autonomy/estimation-filtering leaves (AeroSkills) | the role's equations are grounded in the leaf logic files: alpha-beta-filter (Benedict-Bordner beta = alpha^2/(2-alpha); Kalata gains from tracking index lambda = sigma_w*dt^2/sigma_v), rts-smoother (CV model F = [[1, dt],[0, 1]], discretized Q; forward Kalman recursion; backward smoothing gain G_k = P_filt F^T P_pred^-1; covariance-reduction verdict), extended-kalman-filter (central-difference Jacobians; EKF predict/update recursion; bearing/range measurement model), unscented-kalman-filter (scaled unscented transform; NEES = (x-p)^T P^-1 (x-p) with expected value n), particle-filter (bootstrap/SIR; ESS = (sum w)^2 / sum(w^2); resample when ESS < n/2), complementary-filter (Mahony-style explicit complementary filter on SO(3): cross-product innovation e = m x v, corrected rate omega_c = omega_m - b + k_p*e, bias step b <- b - k_i*e*dt, RK4 quaternion kinematics + renormalization; module gain defaults k_p = 2.0 1/s, k_i = 0.4 1/s^2; trailing-window innovation-norm tolerance 1e-3 rad), interacting-multiple-model-filter (two-mode CV/CA bank, Markov mode mixing, Bayesian mode-probability refresh) | false |
|
|
11
|
+
| Kalman, R. E., "A New Approach to Linear Filtering and Prediction Problems", ASME J. Basic Engineering 82 (1960) | the linear Kalman recursion the report is built on (public) | false |
|
|
12
|
+
| R. G. Brown & P. Y. C. Hwang, Introduction to Random Signals and Applied Kalman Filtering (Wiley) | discrete CV/CA modeling, Q discretization, steady-state behavior (public educational text) | false |
|
|
13
|
+
| Mahony, Hamel & Pflimlin, "Nonlinear Complementary Filters on the Special Orthogonal Group", IEEE Trans. Automatic Control 53(5), 2008 | explicit complementary filter / bias observability with two non-parallel reference vectors (public) | false |
|
|
14
|
+
| Kalata, P. R., "The Tracking Index: A Generalized Parameter for alpha-beta and alpha-beta-gamma Target Trackers", IEEE Trans. AES 20(2), 1984 | tracking-index gain selection (public) | false |
|
|
15
|
+
|
|
16
|
+
The complementary-filter gain defaults (k_p = 2.0 1/s, k_i = 0.4
|
|
17
|
+
1/s^2), the steady-state innovation tolerance (1e-3 rad), the
|
|
18
|
+
uncompensated-bias drift anchor |b|*t, the discrete sampling-lag bound
|
|
19
|
+
|omega|*dt, the SIR ESS threshold n/2, and the NEES expected-value n
|
|
20
|
+
criterion are documented module defaults and worked-example anchors of
|
|
21
|
+
the bound leaf SKILL.md files - reproduced as numbers, not as text.
|
|
22
|
+
Noise-model values in the report (q, r, bias vector, rates) are DESIGN
|
|
23
|
+
INPUTS that trace to the item's sensor datasheets; the report labels
|
|
24
|
+
them as inputs.
|
|
25
|
+
|
|
26
|
+
The report template in `templates/` is an original structure produced
|
|
27
|
+
by the role core for the reference item.
|