Generated: 2026-06-23 (EDT) · Runs:
logs/logs_Jun23_26/full_control_floor_{an,fd}/run/npz/run_PM0523/*.npz
Script:
validation/nu_e_residual_diagnostic.py (world-frame FD of
the logged p_e pair, over _op; both runs)
Builds on: nu_e_orthogonality_Jun23.md (the
EE-local nu_e error = ~54°, matched magnitude)
Question: Is the EE velocity residual
Δ = actual − desired a feedback symptom of the
p_e lag (a), a velocity deficiency (b), reference FD-noise
(c), or dynamic phase-lag (d)?
nu_e error” is a
feedforward-vs-pose-schedule inconsistency, not a tracking
deficiency.‖Δ‖ = 0.0135 m/s = 1.6% of the 0.85 m/s cruise, and
orthogonal to the position error (angle
90.4°, cross-track fraction 0.994, along-track
≈ 0). The EE tracks d/dt(desired.p_e) almost perfectly. The
FD pipeline is validated exactly: v_fd = v_log = 0.8475 m/s
(world-FD speed == logged EE-local nu_e linear speed).p_e ≈ 0.107 m is a quasi-static position
offset with ~zero velocity error (Δ ⊥ p_e). It is
NOT a dynamic tracking failure.an)
and finite-difference (fd) runs differ only in how
desired.nu_e is computed. The EE-local nu_e
error is 0.772 m/s @ 53.6° (an) but collapses to
0.0135 m/s @ 0.91° (fd) — while the world-frame Δ is
~0.013 in both. In the fd run
desired.nu_e ≡ d/dt(desired.p_e) by construction;
its nu_e error is ~0. Therefore the analytic feedforward
twist desired.nu_e disagrees with
d/dt(desired.p_e) by ~54°.velocity_ff (along-track
speed error ≈ 0). The p_e gap above floor is a quasi-static
offset; the suspect is now guidance-internal: why does
analytic_desired_nu_e_feedforward produce a twist 54° off
the commanded pose trajectory’s derivative? Secondary lever: EE position
stiffness K_e.| metric | analytic (an) | FD (fd) | reading |
|---|---|---|---|
n_op |
9060 | 7430 | window size |
world ‖Δ‖ (m/s) |
0.0135 | 0.0120 | velocity residual — tiny both |
| angle(Δ, p_e) (deg) | 90.4 | 90.9 | Δ orthogonal to the lag |
| along-track Δ (m/s) | 0.0002 | −0.0002 | ~zero speed error |
| cross-track Δ (m/s) | 0.0134 | 0.0119 | residual is heading-only |
| cross-track fraction | 0.994 | 0.993 | — |
‖p_e‖ (m) |
0.107 | 0.106 | the standing offset |
v_fd / v_log (m/s) |
0.8475 / 0.8475 | 0.846 / 0.846 | FD validated (exact) |
EE-local nu_e error (m/s) |
0.772 | 0.0135 | the A/B that locks it |
EE-local nu_e angle (deg) |
53.6 | 0.91 | analytic FF mis-aim |
Pearson(‖Δ‖,‖p_e‖) |
0.45 | 0.45 | weak; not the symptom signature |
‖Δ‖ is frame-invariant — it cannot be both 0.77
(EE-local) and 0.0135 (world). The reconciliation:
v_fd = v_log to 4 dp ⇒ FD(actual.p_e) and
the logged actual.nu_e linear block are the same
vector (world vs EE-local view; utils/robot.py:162
nu_e = twist("cam","local")).‖FD(actual.p_e) − FD(desired.p_e)‖ = 0.0135 ⇒
FD(desired.p_e) is within 1.6% of
FD(actual.p_e) ≈ actual.nu_e.‖actual.nu_e − desired.nu_e‖ = 0.772 at
53.6°.⇒ desired.nu_e is 54° from
actual.nu_e ≈ FD(desired.p_e),
i.e. desired.nu_e ≠ d/dt(desired.p_e).
∎
Independent confirmation: in the fd
run, desired_nu_e_feedforward_consistent defines
desired.nu_e = (p_now − p_prev)/dt (GNC/guidance/ee_guidance.py:225-261).
There the nu_e error collapses to
0.91° / 0.0135 — exactly the world-frame Δ. Only the
analytic path (ee_guidance.py:267-306)
produces the 54° mis-aim.
✓ world ‖Δ‖/v < 5% AND angle(Δ,p_e) ≈ 90° AND EE-local nu_e error ≫ world Δ
-> (e) HEALTHY tracking + FF INCONSISTENCY: desired.nu_e ≠ d/dt(desired.p_e).
LEVER: analytic-FF <-> pose-schedule consistency; secondary EE stiffness K_e.
angle(Δ,p_e) small AND corr(‖Δ‖,‖p_e‖) high AND p_e leads Δ -> (a) feedback symptom
cross ≫ along AND corr(‖Δ‖,accel-demand) high -> (d) dynamic phase-lag
along dominates AND magnitude mismatch -> (b) speed deficiency
Δ larger & corr weaker on fd, accel p99/median huge -> (c) reference FD-noise
corr(‖Δ‖,accel-demand)=0.26 and
accel-demand p99/median=1.4 (smooth, not curvature-driven). (c) ruled
out: analytic FF (smoother) does not shrink Δ (−12.6%, both ~0.013). (b)
ruled out: along-track ≈ 0.F1 — EE velocity tracking is healthy (~1.6% residual,
cross-track only). Evidence: ‖Δ‖=0.0135, along≈0,
v_fd=v_log exact. Impact: the EE follows the commanded pose
trajectory’s velocity well; the velocity loop is not the problem.
F2 — p_e is a quasi-static offset, not a dynamic
lag. Evidence: Δ ⊥ p_e (90°), ‖Δ‖ ≪
demand. Impact: closing the 2.46×-above-floor p_e gap is a
steady-offset problem (stiffness / forcing balance), not a
tracking-bandwidth problem.
F3 — The 54° nu_e error is a feedforward
inconsistency (the A/B locks it). Evidence: EE-local
nu_e error 0.772@53.6° (an) vs 0.0135@0.91° (fd); only
desired.nu_e differs between runs; transitivity proof
above. Impact: the Jun-23 “heading error” does not measure tracking — it
measures desired.nu_e ≠ d/dt(desired.p_e). The
earlier framing (“EE-twist tracking is the lever”) is
corrected.
BODY: Trace whether
analytic_desired_nu_e_feedforward (ee_guidance.py:267,
built from the orbit/standoff geometry via
reduced_desired_twist) and the commanded pose trajectory
(set_ee_target / consistent_finalize_pose,
which sets desired.p_e) reference the same
trajectory. The 54° mis-aim means the feedforward velocity and the
position schedule are derived from different references. Determine
whether desired.nu_e should equal
d/dt(desired.p_e) (and is buggy) or is intentionally a
different quantity (and the nu_e metric is mis-posed).
Modify: none (investigation). Inspect:
ee_guidance.py (analytic FF + pose finalize),
analytic_feedforward.py
(reduced_desired_twist), current_sota.md §3
(POSE guidance). Validation: from-NPZ — overlay
d/dt(desired.p_e) vs desired.nu_e per axis;
the existing nu_e_residual_diagnostic.py already isolates
the gap.
p_e-above-floor
gap is the FF mis-aim vs stiffnessBODY: With velocity tracking healthy and
p_e quasi-static, test whether feeding a
consistent FF (the fd definition) lowers
p_e toward floor, and/or whether raising K_e
does. A/B an vs fd p_e is already
logged; compare. Modify: none yet (diagnostic A/B).
Validation: analytic_ff_floor_report.py
already reports pe_med per run — compare an vs fd.
validation/nu_e_residual_diagnostic.py
(canonical actual_desired_values; raw-array stats
analysis/statistics.py; _op window reused from
analytic_ff_floor_report.py; new primitive
analysis.data_analyzer.rows_angle).validation/nu_e_orthogonality.py <fd.npz> → 0.91° /
0.0135.logs/):
logs/logs_Jun23_26/full_control_floor_an/run/nu_e_residual_figures/nu_e_residual_taskA.png
— regen:
python validation/nu_e_residual_diagnostic.py.utils/robot.py:162,
GNC/guidance/ee_guidance.py:225-306,
utils/data_classes.py:280. ```