Files
Syplheed-Reborn/tools/re-capture/flight_law3.py
Claude (auto-RE) f6974ff3f0 re(flight): settled turn rates match the definition exactly — withdraw the time-base claim
Re-measured with 5 s of settle per phase and the speed recorded at the moment the
turn starts (flight_law3.py):

  pitch @ 130/s    74.9 deg/s   vs AV_PitchMinus_Min 75
  pitch @ 1821/s   41.1         vs AV_PitchMinus_Max 40
  roll  @ 110/s   129.5         vs AV_Roll_Min 200
  roll  @ 1722/s  149.3         vs AV_Roll_Max 125

Pitch lands on the definition's own numbers with NO scale factor, so the ~1.2x I
attributed to the emulated time base two iterations ago was an artefact of
differentiating during the AA_* acceleration ramp with too little settle. That
explanation is withdrawn: AV_* can be used verbatim.

What remains is only on the linear side — settled speeds still read high and vary
between runs (RT full: 1342 in one flight, 1821 in another, vs MaximumVelocity 1200),
consistent with a craft being shoved around in a firefight. The HUD reads exactly
CruisingVelocity at neutral. A clean linear measurement needs a quiet map; no cause
is claimed until then.

Roll re-measured with proper settles confirms the axis difference: no speed
dependence, both regimes near AV_Roll_Max, where pitch moved 75 -> 40.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01NptfmpjdpNCKEez6d2xvA9
2026-08-13 16:46:33 +00:00

83 lines
3.4 KiB
Python

#!/usr/bin/env python3
"""Is the `_Min`/`_Max` pair a LERP on speed, and is roll really speed-independent?
Pitch measured 87 deg/s at minimum speed and 54 at maximum, against
`AV_PitchMinus_{Min,Max}` 75/40 — consistent with either a two-state switch or an
interpolation. A THIRD point settles it: at half throttle the craft sits midway
between cruise and maximum, so an interpolation must put the pitch rate between the
two, while a switch cannot.
Roll measured ~144 and ~150 in the two regimes, but only 2 s apart — not enough
settle for a 126 -> 1342 speed change. Here every phase settles 5 s.
Usage: flight_law3.py <out.csv> [dwell_s]
"""
import json, math, os, struct, subprocess, sys, time
sys.path.insert(0, os.path.dirname(os.path.abspath(__file__)))
import speed_law
SETTLE = 5.0
def pad(*a):
subprocess.run(["vgamepad", *a], capture_output=True)
def row_at(fd, off, cfg, row):
at = off + cfg["rot_delta"] + row * cfg["rot_stride"]
v = struct.unpack(">3f", os.pread(fd, 12, at))
n = math.sqrt(sum(c * c for c in v)) or 1.0
return tuple(c / n for c in v)
def ang(a, b):
return math.degrees(math.acos(max(-1.0, min(1.0, sum(a[i] * b[i] for i in range(3))))))
def main():
out_csv = sys.argv[1]
dwell = float(sys.argv[2]) if len(sys.argv) > 2 else 4.0
cfg = json.load(open("/tmp/nav-live.json"))
w, off, nm = speed_law.find_player()
if not w:
sys.exit("player entity not found after retries")
print(f"# locked on {nm}")
fwd, other = cfg.get("fwd_row", 0), (1 if cfg.get("fwd_row", 0) != 1 else 2)
rows = []
phases = [
# label, throttle, stick, matrix row to watch
("pitch_slow", ("LT", 1.0), ("LY", 1.0), fwd),
("pitch_mid", ("RT", 0.5), ("LY", 1.0), fwd),
("pitch_fast", ("RT", 1.0), ("LY", 1.0), fwd),
("roll_slow", ("LT", 1.0), ("LX", 1.0), other),
("roll_fast", ("RT", 1.0), ("LX", 1.0), other),
]
for label, (trig, tv), (axis, av), row in phases:
pad("trig", "RT", "0.0"); pad("trig", "LT", "0.0")
pad("axis", "LX", "0.0"); pad("axis", "LY", "0.0")
pad("trig", trig, str(tv))
time.sleep(SETTLE) # 5 s: a full 126 -> 1342 change needs ~2 s
# speed at the moment of the turn, so the regime is recorded not assumed
p0 = speed_law.pos_at(w.fd, off); time.sleep(0.6); p1 = speed_law.pos_at(w.fd, off)
v_at_turn = math.dist(p0, p1) / 0.6
pad("axis", axis, str(av))
seq, t0 = [], time.time()
while time.time() - t0 < dwell:
seq.append((round(time.time() - t0, 3), *row_at(w.fd, off, cfg, row)))
time.sleep(0.05)
pad("axis", axis, "0.0")
rows += [(label, *s) for s in seq]
rates = []
for t in range(int(dwell) - 1):
a = [s for s in seq if s[0] >= t][0]
b = [s for s in seq if s[0] <= t + 1][-1]
rates.append(ang(a[1:], b[1:]) / (b[0] - a[0]))
mean = sum(rates) / len(rates)
print(f"# {label:<11} speed {v_at_turn:6.0f}/s rate {mean:6.1f} deg/s " +
" ".join(f"{r:5.0f}" for r in rates))
pad("trig", "RT", "0.0"); pad("trig", "LT", "0.0"); pad("reset")
with open(out_csv, "w") as f:
f.write("phase,t,ax,ay,az\n")
for r in rows:
f.write(",".join(str(x) for x in r) + "\n")
print(f"# wrote {out_csv}")
if __name__ == "__main__":
main()