Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
23 changes: 23 additions & 0 deletions CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,8 @@ add_library(adsc_core
src/flux.cpp
src/guidance.cpp
src/propagation.cpp
src/tether.cpp
src/twin.cpp
)
target_include_directories(adsc_core PUBLIC ${CMAKE_CURRENT_SOURCE_DIR}/include)
target_link_libraries(adsc_core PUBLIC Eigen3::Eigen)
Expand Down Expand Up @@ -99,6 +101,15 @@ target_link_libraries(sim_metrics PRIVATE adsc_core adsc_flags)
add_executable(adsc_ladder src/main_ladder.cpp)
target_link_libraries(adsc_ladder PRIVATE adsc_core adsc_flags)

# WP16 Digital Twin Phase 1 driver: regenerates generated/wp16_twin.{csv,md}
# and wp16_twin_schema.md -- a lumped-mass EDT tether model (tether.hpp/cpp)
# plus a twin-to-twin sync + 4-state EKF demo (twin.hpp/cpp). NO real asset;
# [DT-v1: lumped-mass tether, aligned dipole, twin-to-twin]. T7 (EDT
# libration dynamic-stability trade) stays OPEN; this does not touch any
# existing pinned artifact (wp5 campaign, decay, ladder).
add_executable(adsc_twin src/main_twin.cpp)
target_link_libraries(adsc_twin PRIVATE adsc_core adsc_flags)

# Tests.
enable_testing()

Expand Down Expand Up @@ -159,6 +170,18 @@ add_executable(test_flux tests/test_flux.cpp)
target_link_libraries(test_flux PRIVATE adsc_core adsc_flags)
add_test(NAME flux COMMAND test_flux)

# WP16 Digital Twin Phase 1: lumped-mass tether model (energy audit, slack
# invariant, dumbbell-limit validation, divergence guards, controllers,
# determinism) and the twin-to-twin EKF sync (covariance symmetric/PD,
# parameter convergence, determinism). No real asset; T7 stays OPEN.
add_executable(test_tether tests/test_tether.cpp)
target_link_libraries(test_tether PRIVATE adsc_core adsc_flags)
add_test(NAME tether COMMAND test_tether)

add_executable(test_twin tests/test_twin.cpp)
target_link_libraries(test_twin PRIVATE adsc_core adsc_flags)
add_test(NAME twin COMMAND test_twin)

# WP9a flight-software groundwork probe (software-only; TRL stays 4
# everywhere, WP9 PIL itself stays reserved -- docs/wp9_pil_plan.md):
# allocation-count determinism + a generous ceiling, bit-identical final
Expand Down
27 changes: 26 additions & 1 deletion evidence/adsc_evidence_pack.md
Original file line number Diff line number Diff line change
Expand Up @@ -536,7 +536,7 @@ table: `tools/evidence/make_evidence.py::classify_importance` (a small
explicit path+keyword table, not a formal per-line audit -- a handful of
comment lines may land one bucket over from a stricter reading).

Total marks: **143** (decision-critical: **56**, moderate: **46**, cosmetic: **41**)
Total marks: **168** (decision-critical: **56**, moderate: **71**, cosmetic: **41**)

| location | importance | line |
|---|---|---|
Expand Down Expand Up @@ -617,6 +617,21 @@ Total marks: **143** (decision-critical: **56**, moderate: **46**, cosmetic: **4
| `include/adsc/mission.hpp:135` | moderate | double range_bias_walk_m_per_sqrt_s = 1.0e-3; // PLACEHOLDER unestimated range-bias random-w... |
| `include/adsc/mission.hpp:266` | moderate | double min_impulse_bit_nms = 0.0; // PLACEHOLDER MIB angular-impulse quantum [N m s], per ax... |
| `include/adsc/propagation.hpp:84` | moderate | // ---- Physical constants (cited, not PLACEHOLDER) ---- |
| `include/adsc/tether.hpp:117` | moderate | // All PLACEHOLDER values are marked; none is a physically validated figure |
| `include/adsc/tether.hpp:129` | moderate | double m_tip_kg = 20.0; // PLACEHOLDER (= EdtConfig::kit_mass_kg) |
| `include/adsc/tether.hpp:130` | moderate | double lambda_tether_kg_per_m = 2.7e-3; // PLACEHOLDER tether linear density [kg/m] (BETs-sc... |
| `include/adsc/tether.hpp:132` | moderate | // --- segment stiffness / damping (PLACEHOLDER "design" softened |
| `include/adsc/tether.hpp:136` | moderate | double EA_design_N = 250.0; // PLACEHOLDER softened axial stiffness [N] |
| `include/adsc/tether.hpp:137` | moderate | double damping_c_Ns_per_m = 0.05; // PLACEHOLDER per-segment dashpot [N.s/m] |
| `include/adsc/tether.hpp:141` | moderate | double eta_I = 0.7; // PLACEHOLDER collection efficiency [-] in [0,1]; the effective curr... |
| `include/adsc/tether.hpp:151` | moderate | double gate_hysteresis = 0.02; // PLACEHOLDER PhaseGated (C1) hysteresis band applied to th... |
| `include/adsc/tether.hpp:157` | moderate | // PLACEHOLDER RK4 step [s] (Deliverable-3 recommended MC pair for |
| `include/adsc/tether.hpp:170` | moderate | double sim_orbits = 20.0; // PLACEHOLDER Phase-1 simulation horizon [orbits] -- deliberatel... |
| `include/adsc/twin.hpp:54` | moderate | // sensor-noise model. All PLACEHOLDER. |
| `include/adsc/twin.hpp:57` | moderate | double sigma_theta_deg = 0.5; // PLACEHOLDER angle-sensor noise (1-sigma) [deg] |
| `include/adsc/twin.hpp:58` | moderate | double sigma_tension_n = 0.05; // PLACEHOLDER tension-sensor noise (1-sigma) [N] |
| `include/adsc/twin.hpp:68` | moderate | // the truth-twin's actual EA/c/eta_I) plus PLACEHOLDER process-noise gains. |
| `include/adsc/twin.hpp:76` | moderate | // PLACEHOLDER process noise (random-walk white-noise scaling, per dt). |
| `src/campaign.cpp:286` | moderate | // Inter-target phasing to the next target (PLACEHOLDER flat cost). |
| `src/campaign.cpp:400` | moderate | // Under the current flat PLACEHOLDER Delta-v cost these coincide numerically |
| `src/campaign.cpp:426` | cosmetic | "includes PLACEHOLDER phasing/attach/depart time"); |
Expand Down Expand Up @@ -674,6 +689,16 @@ Total marks: **143** (decision-critical: **56**, moderate: **46**, cosmetic: **4
| `src/main_metrics.cpp:348` | moderate | // at a 1e-3 m/s PLACEHOLDER translation MIB and re-checking the |
| `src/main_metrics.cpp:353` | moderate | const double mib_m_s = 1.0e-3; // PLACEHOLDER translation MIB [m/s] |
| `src/main_metrics.cpp:357` | cosmetic | "contact velocity quantized at a 1e-3 m/s PLACEHOLDER translation " |
| `src/main_twin.cpp:156` | moderate | base.EA_design_N = 10000.0; // PLACEHOLDER rigid-limit stiffness (validation only) |
| `src/main_twin.cpp:247` | moderate | cfg.sim_orbits = 5.0; // PLACEHOLDER MC runtime-scoped horizon (see tether.hpp's sim_orbits ... |
| `src/main_twin.cpp:376` | moderate | tc.sigma_theta_deg = 0.5; // PLACEHOLDER |
| `src/main_twin.cpp:377` | moderate | tc.sigma_tension_n = 0.05; // PLACEHOLDER |
| `src/main_twin.cpp:383` | moderate | const double sim_orbits = 10.0; // PLACEHOLDER runtime-scoped horizon, long enough for the 5... |
| `src/twin.cpp:136` | moderate | // PLACEHOLDER initial parameter guesses: the virtual twin starts from a |
| `src/twin.cpp:146` | moderate | x0.P(0, 0) = (2.0 * kPi / 180.0) * (2.0 * kPi / 180.0); // PLACEHOLDER initial angle uncerta... |
| `src/twin.cpp:147` | moderate | x0.P(1, 1) = 1.0e-4 * 1.0e-4; // PLACEHOLDER initial rate uncertainty |
| `src/twin.cpp:148` | moderate | x0.P(2, 2) = 1.0 * 1.0; // PLACEHOLDER initial I_eff uncerta... |
| `src/twin.cpp:149` | moderate | x0.P(3, 3) = 0.1 * 0.1; // PLACEHOLDER initial c_hat uncerta... |
| `tools/docs/fill_docs_numbers.py:386` | moderate | L.append("PLACEHOLDER* %sv cost the two coincide numerically %s every aborting mission needs" |
| `tools/docs/fill_docs_numbers.py:407` | moderate | L.append("percentiles matching across the two presets is expected (a flat PLACEHOLDER cost") |
| `tools/docs/fill_docs_numbers.py:672` | moderate | L.append("/ catalog / sail kit mass [kg] / EDT kit mass [kg] (PLACEHOLDER) / " |
Expand Down
41 changes: 41 additions & 0 deletions generated/wp16_twin.csv
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
schema_version,record_type,controller,metric,estimate,wilson_low,wilson_high,p05,p50,p95,units,notes
1.0,dumbbell_validation,constant,max_angle_deg,15.457219,0.000000,0.000000,0.000000,0.000000,0.000000,deg,"T4a eps=0.106 BOUNDED band [3.0,20.0] deg (T7=9.26 deg); PASS; lumped-mass RK4 gives ~15.5 deg vs the T7 1-DOF DOP853 9.26 deg - model-family offset, both bounded"
1.0,dumbbell_validation,constant,o45_orbit,0.191590,0.000000,0.000000,0.000000,0.000000,0.000000,orbit,"T4a eps=0.490 TUMBLE band o45 [0.15,0.30] orbit (T7=0.20); -1 = never; PASS"
1.0,dumbbell_validation,constant,o45_orbit,0.141346,0.000000,0.000000,0.000000,0.000000,0.000000,orbit,"T4a eps=0.800 TUMBLE band o45 [0.10,0.20] orbit (T7=0.14); -1 = never; PASS"
1.0,dumbbell_validation,n/a,t4b_status,0.000000,0.000000,0.000000,0.000000,0.000000,0.000000,-,"T4b (3D pitch+roll pumping onset, o45 in [0.40,0.70] orbit, 80-deg event by orbit [3.5,5.5]) requires the Phase-2 out-of-plane model and is NOT attempted in this Phase-1 planar implementation -- stated up front, no overclaim."
1.0,controller_comparison,constant,diverged_angle_rate,0.000000,0.000000,0.018845,0.000000,0.000000,0.000000,fraction,"fraction hitting DivergeStatus::DivergedAngle (chord angle-from-vertical > 80 deg); Wilson 95% CI"
1.0,controller_comparison,constant,diverged_velocity_rate,0.000000,0.000000,0.018845,0.000000,0.000000,0.000000,fraction,"fraction hitting DivergeStatus::DivergedVelocity (any |v_i| > 10*n*L); Wilson 95% CI"
1.0,controller_comparison,constant,overstrain_rate,0.000000,0.000000,0.018845,0.000000,0.000000,0.000000,fraction,"fraction hitting DivergeStatus::Overstrain (any segment l_j/L0 > 1.5); Wilson 95% CI"
1.0,controller_comparison,constant,energy_spike_rate,0.000000,0.000000,0.018845,0.000000,0.000000,0.000000,fraction,"fraction hitting DivergeStatus::EnergySpike (recalibrated guard, tether.cpp -- genuine integrator blow-ups only); Wilson 95% CI"
1.0,controller_comparison,constant,nonconverged_rate,0.000000,0.000000,0.018845,0.000000,0.000000,0.000000,fraction,"combined fraction hitting ANY non-Ok status (sum of the four rows above); every non-Ok run is EXCLUDED from the amplitude/o45/eta/energy pools below, never silently mixed in -- see n_clean; Wilson 95% CI"
1.0,controller_comparison,constant,n_clean,200.000000,0.000000,0.000000,0.000000,0.000000,0.000000,count,"runs completing the full sim_orbits horizon at status==Ok; the max_angle/o45/eta_lib/energy_drift rows below are computed over ONLY these n_clean runs (n_clean = n_runs - n_nonconverged)"
1.0,controller_comparison,constant,max_angle_deg,10.153996,0.000000,0.000000,4.880367,9.263693,18.245678,deg,"peak chord angle-from-vertical over the run; CLEAN (status==Ok, n_clean) runs only -- truncated runs excluded, no silent corruption"
1.0,controller_comparison,constant,o45_never_crossed_rate,1.000000,0.981155,1.000000,0.000000,0.000000,0.000000,fraction,"fraction of CLEAN runs (denominator n_clean, NOT n_runs) that never reached 45 deg within sim_orbits; Wilson 95% CI"
1.0,controller_comparison,constant,eta_lib_effective,0.760491,0.000000,0.000000,0.520885,0.771011,0.982718,fraction,"time-average |I_applied|/I_cap actually delivered; CLEAN runs only; C2 gives duty_on=0.75 by construction, C1's is COMPUTED (the stability-per-unit-thrust headline)"
1.0,controller_comparison,constant,energy_drift_per_orbit,0.000000,0.000000,0.000000,0.000000,0.000000,0.000000,fraction,"last full-orbit |E_J drift - integrated (P_lorentz+P_damp)| / (mu*L^2*n^2); CLEAN runs only; sanity diagnostic, not a stability claim"
1.0,controller_comparison,c1_phase_gated,diverged_angle_rate,0.000000,0.000000,0.018845,0.000000,0.000000,0.000000,fraction,"fraction hitting DivergeStatus::DivergedAngle (chord angle-from-vertical > 80 deg); Wilson 95% CI"
1.0,controller_comparison,c1_phase_gated,diverged_velocity_rate,0.000000,0.000000,0.018845,0.000000,0.000000,0.000000,fraction,"fraction hitting DivergeStatus::DivergedVelocity (any |v_i| > 10*n*L); Wilson 95% CI"
1.0,controller_comparison,c1_phase_gated,overstrain_rate,0.000000,0.000000,0.018845,0.000000,0.000000,0.000000,fraction,"fraction hitting DivergeStatus::Overstrain (any segment l_j/L0 > 1.5); Wilson 95% CI"
1.0,controller_comparison,c1_phase_gated,energy_spike_rate,0.000000,0.000000,0.018845,0.000000,0.000000,0.000000,fraction,"fraction hitting DivergeStatus::EnergySpike (recalibrated guard, tether.cpp -- genuine integrator blow-ups only); Wilson 95% CI"
1.0,controller_comparison,c1_phase_gated,nonconverged_rate,0.000000,0.000000,0.018845,0.000000,0.000000,0.000000,fraction,"combined fraction hitting ANY non-Ok status (sum of the four rows above); every non-Ok run is EXCLUDED from the amplitude/o45/eta/energy pools below, never silently mixed in -- see n_clean; Wilson 95% CI"
1.0,controller_comparison,c1_phase_gated,n_clean,200.000000,0.000000,0.000000,0.000000,0.000000,0.000000,count,"runs completing the full sim_orbits horizon at status==Ok; the max_angle/o45/eta_lib/energy_drift rows below are computed over ONLY these n_clean runs (n_clean = n_runs - n_nonconverged)"
1.0,controller_comparison,c1_phase_gated,max_angle_deg,10.172872,0.000000,0.000000,4.880367,9.263693,18.245678,deg,"peak chord angle-from-vertical over the run; CLEAN (status==Ok, n_clean) runs only -- truncated runs excluded, no silent corruption"
1.0,controller_comparison,c1_phase_gated,o45_never_crossed_rate,1.000000,0.981155,1.000000,0.000000,0.000000,0.000000,fraction,"fraction of CLEAN runs (denominator n_clean, NOT n_runs) that never reached 45 deg within sim_orbits; Wilson 95% CI"
1.0,controller_comparison,c1_phase_gated,eta_lib_effective,0.760193,0.000000,0.000000,0.520885,0.771011,0.982718,fraction,"time-average |I_applied|/I_cap actually delivered; CLEAN runs only; C2 gives duty_on=0.75 by construction, C1's is COMPUTED (the stability-per-unit-thrust headline)"
1.0,controller_comparison,c1_phase_gated,energy_drift_per_orbit,0.000000,0.000000,0.000000,0.000000,0.000000,0.000000,fraction,"last full-orbit |E_J drift - integrated (P_lorentz+P_damp)| / (mu*L^2*n^2); CLEAN runs only; sanity diagnostic, not a stability claim"
1.0,controller_comparison,c2_fixed_duty,diverged_angle_rate,0.000000,0.000000,0.018845,0.000000,0.000000,0.000000,fraction,"fraction hitting DivergeStatus::DivergedAngle (chord angle-from-vertical > 80 deg); Wilson 95% CI"
1.0,controller_comparison,c2_fixed_duty,diverged_velocity_rate,0.000000,0.000000,0.018845,0.000000,0.000000,0.000000,fraction,"fraction hitting DivergeStatus::DivergedVelocity (any |v_i| > 10*n*L); Wilson 95% CI"
1.0,controller_comparison,c2_fixed_duty,overstrain_rate,0.000000,0.000000,0.018845,0.000000,0.000000,0.000000,fraction,"fraction hitting DivergeStatus::Overstrain (any segment l_j/L0 > 1.5); Wilson 95% CI"
1.0,controller_comparison,c2_fixed_duty,energy_spike_rate,0.120000,0.081980,0.172343,0.000000,0.000000,0.000000,fraction,"fraction hitting DivergeStatus::EnergySpike (recalibrated guard, tether.cpp -- genuine integrator blow-ups only); Wilson 95% CI"
1.0,controller_comparison,c2_fixed_duty,nonconverged_rate,0.120000,0.081980,0.172343,0.000000,0.000000,0.000000,fraction,"combined fraction hitting ANY non-Ok status (sum of the four rows above); every non-Ok run is EXCLUDED from the amplitude/o45/eta/energy pools below, never silently mixed in -- see n_clean; Wilson 95% CI"
1.0,controller_comparison,c2_fixed_duty,n_clean,176.000000,0.000000,0.000000,0.000000,0.000000,0.000000,count,"runs completing the full sim_orbits horizon at status==Ok; the max_angle/o45/eta_lib/energy_drift rows below are computed over ONLY these n_clean runs (n_clean = n_runs - n_nonconverged)"
1.0,controller_comparison,c2_fixed_duty,max_angle_deg,13.618305,0.000000,0.000000,6.453706,12.668035,22.818385,deg,"peak chord angle-from-vertical over the run; CLEAN (status==Ok, n_clean) runs only -- truncated runs excluded, no silent corruption"
1.0,controller_comparison,c2_fixed_duty,o45_never_crossed_rate,1.000000,0.978640,1.000000,0.000000,0.000000,0.000000,fraction,"fraction of CLEAN runs (denominator n_clean, NOT n_runs) that never reached 45 deg within sim_orbits; Wilson 95% CI"
1.0,controller_comparison,c2_fixed_duty,eta_lib_effective,0.557428,0.000000,0.000000,0.388971,0.553391,0.726231,fraction,"time-average |I_applied|/I_cap actually delivered; CLEAN runs only; C2 gives duty_on=0.75 by construction, C1's is COMPUTED (the stability-per-unit-thrust headline)"
1.0,controller_comparison,c2_fixed_duty,energy_drift_per_orbit,0.000000,0.000000,0.000000,0.000000,0.000000,0.000000,fraction,"last full-orbit |E_J drift - integrated (P_lorentz+P_damp)| / (mu*L^2*n^2); CLEAN runs only; sanity diagnostic, not a stability claim"
1.0,twin_sync,c1_phase_gated,converged_rate,0.000000,0.000000,0.018845,0.000000,0.000000,0.000000,fraction,"fraction TWIN-CONVERGED (param rel err < 10% and NIS in [0.05,7.38] for >=5 consecutive orbits); Wilson 95% CI"
1.0,twin_sync,c1_phase_gated,i_eff_rel_err,0.170946,0.000000,0.000000,0.016056,0.171134,0.344623,fraction,"final |I_eff_hat - I_eff_true| / I_eff_true"
1.0,twin_sync,c1_phase_gated,c_hat_rel_err,1.006815,0.000000,0.000000,0.082299,0.503818,3.148403,fraction,"final |c_hat - c_true| / c_true; c_hat is WEAKLY OBSERVABLE [DT-v1] (effective pitch damping, NOT the axial c_true) so this is reported for the record, NOT expected small -- I_eff is the robustly-identified parameter; see twin.hpp TwinSyncReport finding note + _tasks_local/wp16_xcheck.py"
1.0,twin_sync,c1_phase_gated,theta_rmse_deg,0.067650,0.000000,0.000000,0.052740,0.066494,0.083496,deg,"RMSE of (EKF theta estimate - truth chord angle) over the whole run"
1.0,twin_sync,c1_phase_gated,median_nis,2.758573,0.000000,0.000000,2.746042,2.758193,2.770790,-,"per-run median 2-dof NIS; 95% chi-square(2) band is [0.05, 7.38]"
1.0,twin_sync,c1_phase_gated,orbits_to_converge,-1.000000,0.000000,0.000000,0.000000,0.000000,0.000000,orbit,"no run converged within sim_orbits; -1 sentinel"
Loading
Loading