From ae5f322c03b36e4ed67e58647882bfa18d1872fe Mon Sep 17 00:00:00 2001 From: "Claude (auto-RE)" Date: Thu, 13 Aug 2026 17:26:27 +0000 Subject: [PATCH] =?UTF-8?q?re(flight):=20the=20linear=20factor=20is=20the?= =?UTF-8?q?=20CLOCK=20=E2=80=94=201.260=20measured=20against=201.267?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Cleanest linear measurement: neutral throttle (HUD = CruisingVelocity 350), sticks centred, 20 s of perfectly straight flight (displacement/path = 1.000): 8 900 world units in 20.1 s -> 443.6 /s -> 1.267x the HUD's 350 And the game's own mission timer across a wall-clock interval: TIME 00:08.79 -> 00:46.97 = 38.18 s of game time in 30.29 s wall = 1.260 Same number. So the linear discrepancy is not a unit difference: the mission clock runs ~1.26x faster than wall time under this emulator, and dividing world displacement by WALL seconds inflates speed by exactly that. World units and displayed speed share one unit; the definition velocities are per GAME second. This supersedes the previous "world-unit vs displayed-speed" reading. Left open (❔): settled turn rates measured 74.9/41.1 deg/s in wall time against AV_PitchMinus_Min/Max 75/40, but the clock argument predicts ~94 for the first. Either that agreement was luck inside a noisy sample (per-window rates spanned 61-96) or angular integration is frame-based where linear is time-based. The check is to re-measure pitch and convert wall->game seconds with the clock ratio. Co-Authored-By: Claude Opus 5 (1M context) Claude-Session: https://claude.ai/code/session_01NptfmpjdpNCKEez6d2xvA9 --- docs/re/flight-speed-law.md | 39 +++++++++++++++++++++++ tools/re-capture/cruise_ratio.py | 53 ++++++++++++++++++++++++++++++++ 2 files changed, 92 insertions(+) create mode 100644 tools/re-capture/cruise_ratio.py diff --git a/docs/re/flight-speed-law.md b/docs/re/flight-speed-law.md index 8fcc209..fb32d50 100644 --- a/docs/re/flight-speed-law.md +++ b/docs/re/flight-speed-law.md @@ -303,3 +303,42 @@ one of two moves: **let a held input vary** (the trigger's analogue range), or **bring in an independent oracle** (the HUD, the definitions, a longer settle). The wrong turn — the time base — came from explaining a number instead of first measuring the same quantity a second, cleaner way. + +--- + +# ✅ The linear factor IS the clock — measured against the game's own mission timer + +The cleanest possible version of the linear measurement: neutral throttle (HUD reads +exactly `CruisingVelocity` 350), sticks centred, **20 s of perfectly straight flight** +(`straightness = displacement/path = 1.000`, so no manoeuvring contaminates it) — +[`tools/re-capture/cruise_ratio.py`](../../tools/re-capture/cruise_ratio.py): + +``` +displacement 8 900 world units in 20.1 s -> 443.6 /s +ratio vs the HUD's 350 -> 1.267 +``` + +And the game's **own clock**, read off the HUD across a wall-clock interval: + +``` +mission TIME 00:08.79 -> 00:46.97 = 38.18 s of game time +wall clock = 30.29 s +ratio = 1.260 +``` + +**1.260 against 1.267 — the same number.** So the linear "discrepancy" was never a +unit difference: **the mission clock runs ~1.26× faster than wall time under this +emulator**, and a speed derived by dividing world displacement by *wall* seconds is +inflated by exactly that. World units and the displayed speed share one unit, and a +reimplementation should take `CruisingVelocity`/`MaximumVelocity` at face value — +per **game** second. + +This supersedes the previous section's "world-unit vs displayed-speed difference". + +❔ **One thing does not fit, and is left open.** The settled turn rates measured +74.9 and 41.1 °/s *in wall time* against `AV_PitchMinus_{Min,Max}` 75/40 — but if +game time runs 1.26× fast, a 75 °/game-second cap should have read ~94 °/wall-second. +Either that agreement was luck inside a noisy sample (the per-window rates spanned +61–96), or angular integration is frame-based where linear is time-based. The check: +re-measure pitch and convert wall→game seconds with the clock ratio, expecting ~94 +if the clock explanation is universal. diff --git a/tools/re-capture/cruise_ratio.py b/tools/re-capture/cruise_ratio.py new file mode 100644 index 0000000..502bdc1 --- /dev/null +++ b/tools/re-capture/cruise_ratio.py @@ -0,0 +1,53 @@ +#!/usr/bin/env python3 +"""Pin the world-unit / displayed-speed ratio at the one unambiguous point. + +At neutral throttle the HUD reads exactly `CruisingVelocity` (350 for the player), +so no digit-reading is needed to know the game's own number — only a clean +measurement of how far the craft actually travels in world units. + +Cleanliness matters more than length here: earlier ratios (1.19–1.29) were sampled +in a firefight where the craft is shoved around, and with a stick input the path is +longer than the displacement. So this flies straight, holds neutral throttle, and +takes ONE long displacement over a 20 s window, plus screenshots at both ends to +confirm the HUD never moved off 350. + +Usage: cruise_ratio.py [window_s] +""" +import math, os, subprocess, sys, time +sys.path.insert(0, os.path.dirname(os.path.abspath(__file__))) +import speed_law + +CRUISE = 350.0 # UN_f001_TCAF_DeltaSaber_T_Player CruisingVelocity + +def pad(*a): + subprocess.run(["vgamepad", *a], capture_output=True) + +def shot(name): + subprocess.run(["screenshot", f"/sylph-home/re/shots/{name}.png"], capture_output=True) + +def main(): + win = float(sys.argv[1]) if len(sys.argv) > 1 else 20.0 + w, off, nm = speed_law.find_player() + if not w: + sys.exit("player entity not found after retries") + print(f"# locked on {nm}") + pad("reset") + pad("trig", "RT", "0.0"); pad("trig", "LT", "0.0") + time.sleep(6.0) # settle at cruise, sticks centred + shot("cruise_start") + p0, t0 = speed_law.pos_at(w.fd, off), time.time() + samples = [(0.0, *p0)] + while time.time() - t0 < win: + time.sleep(0.25) + samples.append((round(time.time() - t0, 3), *speed_law.pos_at(w.fd, off))) + shot("cruise_end") + p1, t1 = samples[-1][1:], samples[-1][0] + disp = math.dist(p0, p1) + path = sum(math.dist(samples[i][1:], samples[i + 1][1:]) for i in range(len(samples) - 1)) + print(f"# window {t1:.1f}s displacement {disp:8.0f} path {path:8.0f} " + f"straightness {disp / path:.3f}") + print(f"# speed by displacement {disp / t1:7.1f}/s by path {path / t1:7.1f}/s") + print(f"# ratio vs HUD {CRUISE:.0f}: displacement {disp / t1 / CRUISE:.3f} path {path / t1 / CRUISE:.3f}") + +if __name__ == "__main__": + main()