Re-running roll with 5 s settles and in-run clock brackets:
this run's clock: TIME 00:34.93 -> 00:45.97 = 11.04 s game in 7.98 s wall = 1.383
min speed: 90.6 deg/wall-s /1.383 -> 65.5 deg/game-s (AV_Roll_Min 200)
max speed: 59.1 /1.383 -> 42.7 (AV_Roll_Max 125)
The corrected numbers are within a few per cent of the PITCH run's 67.8 and 40.9 —
two different stick axes cannot produce the same rates, so the probe is not
separating them. Cause: watching a non-forward matrix row sees any rotation that
moves that row, and pitch moves it as much as roll. The correct measure is rotation
ABOUT the forward axis (project the row onto the plane perpendicular to forward and
track that angle).
So "roll shows no speed dependence, unlike pitch" is withdrawn: it rested on 2 s
settles and a row that mixes axes, and the two runs disagree with each other
(144/150 then, 90.6/59.1 now). AV_Roll_{Min,Max} are not confirmed and the axis
question is open.
The clock ratio is now measured three times in three flights: 1.260, 1.311, 1.383 —
a property of the moment, not the machine, so every rate probe must bracket its own
phases.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01NptfmpjdpNCKEez6d2xvA9
75 lines
3.3 KiB
Python
75 lines
3.3 KiB
Python
#!/usr/bin/env python3
|
|
"""Is the clock factor universal, or does it apply only to linear motion?
|
|
|
|
The mission clock runs ~1.26x wall time, which fully explains the linear
|
|
measurements. Applied to the angular ones it predicts a wall-time pitch rate of
|
|
~94 deg/s for `AV_Roll_Min` 75 — but the settled measurement read 74.9.
|
|
Either that was luck inside a noisy sample or angular integration is frame-based.
|
|
|
|
The flaw in comparing across runs is that the emulator's speed depends on scene
|
|
load, so the clock ratio is not a constant of the machine. This measures BOTH in
|
|
the same run: a HUD screenshot brackets each turn phase, so the mission clock's
|
|
own advance over that phase converts wall seconds to game seconds.
|
|
|
|
Usage: roll_gametime.py <out.csv> [dwell_s] (then read the HUD TIME off the shots)
|
|
"""
|
|
import json, math, os, struct, subprocess, sys, time
|
|
sys.path.insert(0, os.path.dirname(os.path.abspath(__file__)))
|
|
import speed_law
|
|
|
|
def pad(*a):
|
|
subprocess.run(["vgamepad", *a], capture_output=True)
|
|
|
|
def shot(n):
|
|
subprocess.run(["screenshot", f"/sylph-home/re/shots/{n}.png"], 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 8.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}")
|
|
# Roll turns the craft about its FORWARD axis, so the forward row barely moves —
|
|
# watch another row of the rotation matrix instead.
|
|
fwd = 1 if cfg.get("fwd_row", 0) != 1 else 2
|
|
rows = []
|
|
for label, (trig, tv) in (("slow", ("LT", 1.0)), ("fast", ("RT", 1.0))):
|
|
pad("trig", "RT", "0.0"); pad("trig", "LT", "0.0"); pad("axis", "LX", "0.0")
|
|
pad("trig", trig, str(tv))
|
|
time.sleep(5.0)
|
|
shot(f"roll_{label}_a") # HUD TIME at the start of the phase
|
|
t0 = time.time()
|
|
pad("axis", "LY", "1.0") # nose down = Roll
|
|
seq = []
|
|
while time.time() - t0 < dwell:
|
|
seq.append((round(time.time() - t0, 3), *row_at(w.fd, off, cfg, fwd)))
|
|
time.sleep(0.05)
|
|
pad("axis", "LX", "0.0")
|
|
wall = seq[-1][0]
|
|
shot(f"roll_{label}_b") # HUD TIME at the end
|
|
rows += [(label, *s) for s in seq]
|
|
total = sum(ang(seq[i][1:], seq[i + 1][1:]) for i in range(len(seq) - 1))
|
|
print(f"# {label:<5} wall {wall:5.2f}s swept {total:7.1f}deg "
|
|
f"rate {total / wall:6.1f} deg/wall-s "
|
|
f"(x1.26 -> {total / wall * 1.26:6.1f} deg/game-s if the clock applies)")
|
|
pad("trig", "RT", "0.0"); pad("trig", "LT", "0.0"); pad("reset")
|
|
with open(out_csv, "w") as f:
|
|
f.write("phase,t,fx,fy,fz\n")
|
|
for r in rows:
|
|
f.write(",".join(str(x) for x in r) + "\n")
|
|
print("# read HUD TIME off roll_slow_a/b and roll_fast_a/b to get the run's own ratio")
|
|
|
|
if __name__ == "__main__":
|
|
main()
|