Generated: 2026-06-23 (EDT) ·
Method: 5-agent investigation workflow (3 parallel
code-readers → synthesis → adversarial refutation) + from-NPZ floor
cross-check Builds on: nu_e_residual_taskA_Jun23b.md
(TASK A: world-frame Δ tiny, EE tracks the pose velocity; EE-local
nu_e error 54° is an FF inconsistency)
Question: Why is the analytic feedforward twist
desired.nu_e ~54° off d/dt(desired.p_e) — bug
or different quantity? And what does it imply for the
p_e-above-floor gap?
analytic_desired_nu_e_feedforward, ee_guidance.py:267-306)
builds the closed-form velocity of the ideal standoff
trajectory — camera at r_cam from the
on-orbit-projected desired CoM des.p_c,
following the orbit aim point — via
p_ed_dot = v_cd + r_cam·u_dot (analytic_feedforward.py:32).
That is not d/dt(desired.p_e): the
committed pose desired.p_e is built about the
measured CoM (ee_guidance.py:687,690)
and pushed through a low-pass + rate-limit + reach
clamp (consistent_finalize_pose, ee_guidance.py:792-892)
that the FF skips entirely.an and fd share an identical pose
schedule — the analytic path writes only des.nu_e
(line 305), never
des.p_e (written by the finalizer at line 898, before
either FF runs). So the runs differ only in twist construction
(verified).des.p_c vs
the measured p_c baked into des.p_e; (2)
smoothing — the standoff-sweep term
r_cam·u_dot is raw in the FF but low-passed + rate-limited
inside des.p_e; (3) rotation frame — the
FF twist is logged in the desired EE frame
R_ed=des.R_e (analytic_feedforward.py:47-48)
while actual.nu_e is in the measured
R_te.axis_only_attitude leaves boresight roll free, part of the
54° azimuth lean could be the R_ed-vs-R_te
frame difference rather than the reference difference —
and the diagnostic compares logged-desired vs logged-actual, so it
cannot separate them. Classification = high confidence; per-term
mechanism = medium. The clean discriminating test
(compare both velocities in a common world frame) needs
R_ed logged or a code A/B — neither is in the current
NPZ.fd (consistent FF) and an (mis-aimed FF) reach
the same p_e (0.1059 vs 0.1074).
No FF lever lowers p_e.The analytic FF feeds forward a velocity for a different
trajectory than the loop tracks. The cruise-lag floor formula
x_ss = −(JᵀK)⁻¹[C·v_des + …] is fed that v_des
— so in analytic runs it predicts a phantom-low
floor.
v_des fed to floor |
floor_med | p_e (pe_med) |
ratio p_e/floor |
|
|---|---|---|---|---|
| fd (off) | d/dt(desired.p_e) — what the EE tracks |
0.123 | 0.106 | 0.86 (AT floor) |
| analytic (on) | the ideal-standoff FF twist — not tracked | 0.044 | 0.107 | 2.46 (phantom) |
We are AT the architectural cruise-lag floor. The honest floor (consistent
v_des, fd) is ~0.12 m andp_e ≈ 0.107sits just below it. The advertised 0.044 m was a mis-prediction from feeding the floor av_desthe loop never follows; even the perfectly-consistentfdFF reaches only 0.106, never 0.044. The 0.063 m “gap” was a ghost.
D1 — The nu_e tracking metric is ill-posed in
analytic runs. It compares desired.nu_e (in
R_ed, an idealized reference) against
actual.nu_e (in R_te, the realized motion) —
different reference and different frame. The honest tracking
question (“does the EE follow the commanded pose?”) is answered cleanly
by the world-frame p_e / Δ (TASK A: 1.6%).
Fix: judge EE tracking by p_e/pointing, or compare
the FF against the ideal-standoff reference it is derived from — not by
nu_e-vs-FD agreement.
D2 — Floor logging is misleading in analytic runs.
diagnostics.cruise_lag.floor_pe uses the analytic FF
v_des the loop doesn’t track → the “0.044 / 2.46×”
headline. Fix: log the floor with the consistent
(committed-pose) v_des, or report both and label which
v_des each uses.
D3 — Doc/code sign mismatch (one-line, harmless). current_sota.md eq 5.7
writes p_ed = p_c − r_cam·r̂ (outward); the code uses
p_ed = p_cd + r_cam·u (inward, analytic_feedforward.py:131).
The doc is internally inconsistent (its own z_ed = +r̂), and
the twist eq 5.10 already matches code. Flagged for the user to
verify and fix in the canonical sheet (the math is theirs to
own).
R_ed/R_te logged, then compare the FF twist
and d/dt(desired.p_e) in a common world
frame (agrees in world ⇒ frame; disagrees ⇒ reference). Cheap
code A/B: swap p_cd → measured p_c at ee_guidance.py:283 and
re-measure the angle. (Scientific completeness; does not change the
decision.)p_e: it is
not a feedforward lever (fd ≈ an). The remaining axis
is EE position stiffness K_e — a separate
study (raise K_e, watch the actuator-effort / pointing
trade and s_min margin).v_des) so the headline metric stops reporting a
phantom gap, document the limit, and ship the nominal.
The cruise-lag floor (~0.12 m) is then the stated architectural
p_e.nu_e-ff-inconsistency), parallel readers + synthesis +
adversarial refutation (supported=true, confidence downgraded
high→medium on the per-term split, frame hole flagged).validation/analytic_ff_floor_report.py (both floor npz,
run_PM0523): pe_med fd 0.1059 / an 0.1074; floor_med fd 0.1229 / an
0.0437; ratio 0.86 / 2.46.GNC/guidance/ee_guidance.py:234-242,267-306,283,687,792-892,898,305;
GNC/guidance/analytic_feedforward.py:18,32,47-48,131;
GNC/guidance/com_guidance.py:215,232-233;
GNC/breve_controller.py:92,108;
GNC/equations/current_sota.md eq 5.7/5.10. ```