re: the animation clock is TIME-INTEGRATED -- one prediction held, one failed
Reported against the pre-registration, failure first. HELD, and by a cleaner argument than the regression: the clock is NOT frame-counted. The same animation takes 21 frame labels in one capture and 33 in another, and splash A's logo steps +136,+34 in one and +17,+51,+34,+34,+17,+17 in the other. A fixed per-frame increment cannot do that. Steps are always integer multiples of 17 (255/15 = one unit), so the clock advances in whole units at a rate set by how long the frame took. That retires '2 units per submitted frame' as a MECHANISM -- including my own page from two hours ago. The measurement stands; 2 was that run's frame pacing. units = 2 x frames computes an emulator artefact. Recorded as a proposal against the register, not enacted, and noted at the head of the H3 page rather than by editing it. FAILED: predicted 60 units per guest second, accept 55-65. Measured median 29.9 over six elapsed-ratio estimates (25.2-36.6). Prediction 3 said 30 was excluded and 30 is what came out. Why the rate is not a number yet: units/s = (d_alpha/dt) * T/255, and T is the load-bearing term. d_alpha/dt is measured cleanly six ways. T=15 for these elements comes from a corpus row whose usual derivation is circular with the thing just retired -- a step of 34/frame implies T=15 only GIVEN 2 units/frame. T=30 would give ~60. No amount of re-measuring alpha settles it. Settles with ptbtn00, whose T=22 is attested by two independent readers with no clock anywhere in the chain. That capture did not reach the title in 531 s of attract loop against 243 s in the previous run -- the variable attract loop capture-harness-status.md already documents at up to 604 s. Instrument built and control-passed; one run is missing. Instrument: guest timebase, 50 MHz per emulator.cc:225, scalar 1.0 per clock.cc:37, so no host wall clock enters any number. Control: 123.24 guest seconds across a capture running ~118 wall seconds. Told the port to change NOTHING today: ~30 rests on an unverified T, and retiring 2 x frames does not by itself supply a replacement.
This commit is contained in:
@@ -137,6 +137,7 @@ files, which is how the same ground got covered twice.
|
||||
| [`structures/stage-mission-tables.md`](structures/stage-mission-tables.md) | The stage table set — phases, routes, sub-objectives and AI parameters | ✅ the table set and how the stage record reaches it, validated across; **`AIParams` disc-wide: 23 objects, one shared 34-profile roster (782 records), loader `sub_8233C368`; `Type`→field-count holds except the two `_Test` templates** |
|
||||
| [`structures/texture-color-k8888.md`](structures/texture-color-k8888.md) | Texture colour interpretation — `k_8_8_8_8` (32bpp UI/HUD textures) | — |
|
||||
| [`ui-keyframe-time-unit.md`](ui-keyframe-time-unit.md) | What a keyframe time is worth, and what shape the ramp has | ✅ CONFIRMED from the running game's own draw stream — the ramp is **linear** (a declared 15-unit fade lands on `round(255·k/15)` for all seven samples) and the animation clock advances **2 time units per submitted frame**. 🟡 the seconds conversion (`1 unit = 1/60 s`) rests on a measured 27.6 present-frames/second |
|
||||
| [`units-per-second-measured.md`](units-per-second-measured.md) + [pre-reg](units-per-second-preregistration.md) | Is the animation clock frame-counted or time-integrated, and at what rate | 🟡 **half-answered, 2026-09-01, one prediction HELD and one FAILED.** ✅ **The clock is NOT frame-counted**: the same animation takes 21 labels in one capture and 33 in another, and splash A's logo steps `+136,+34` in one and `+17,+51,+34,+34,+17,+17` in the other. Steps are always integer multiples of **17** (255/15 = one unit), so the clock advances in whole units at a rate set by frame duration. 📌 **This retires "2 units per submitted frame" as a MECHANISM** — 2 was that run's frame pacing, so `units = 2 × frames` computes an emulator artefact. ❌ **The rate FAILED its prediction**: predicted 60 units/guest-second, measured **median 29.9** (25.2–36.6) — but that rests on `T=15`, which I have not read off the disc and whose usual derivation is circular with the thing just retired. **Settles with the plate (`T=22`, attested by two readers with no clock in the chain) captured with tick stamps; that run did not reach the title in 531 s.** Instrument: guest timebase (50 MHz, scalar 1.0), control passed — 123.24 guest s over ~118 wall s. |
|
||||
| [`h3-units-per-frame-measured.md`](h3-units-per-frame-measured.md) | How many keyframe units elapse per guest frame, and which declared time the title's settle anchor is | ✅ **measured against a pre-registration, 2026-09-01. 2 units per guest frame**, on `ptbtn00`'s own declared ramp (`t=214→236`, T=22): three consecutive gap-free steps of **exactly 23** = 255×2/22, ramp span 10 labels against a predicted 11 (±1). The Port's inferred **5 is excluded by >2×**. 🔴 Why 5 appeared: **an alpha step is not a clock rate** — `Δα/frame = 255·(units/frame)/T`, so splash B's 34-with-T=15 and the plate's 23-with-T=22 are ONE clock. Also: the **title settle anchor is t≈160**, not t=118 — it is `ptcopyright`, the last build-in element and the only glyph one, full at label 5350 → t≈168–176. 🔴 **units/SECOND is NOT settled** and two of my own captures disagree ~2.9× on it; the gap is in frames→seconds, not units→frames. |
|
||||
| [`h3-units-per-frame-preregistration.md`](h3-units-per-frame-preregistration.md) | The prediction, committed before the capture was read | ✅ kept as the control on the row above |
|
||||
| [`input-pad-read-path.md`](input-pad-read-path.md) | What the game asks the console for, on the pad | ✅ **decoded from the image, 2026-09-01.** `sub_82457038` is the only function that reads controller *data*, and it compares **every** field of `XINPUT_GAMEPAD` — `wButtons` (full 16 bits), both triggers, all four stick axes — against the previous state. **14/14** loads verified byte-for-byte against `/image/sylpheed.pe`, database used as an index only. **Two input paths**: the polled state and an 8-byte-record `XamInputGetKeystrokeEx` ring. ⚠️ This is the **superset the game can see, not the per-screen set** — reading a field is not acting on it. ❔ Which bits each screen tests is open; footholds are the image's own `C_PAD_DECODER` / `C_PAD_RINGBUF` trace strings (`sub_8220B610` / `sub_821A6470`). |
|
||||
|
||||
@@ -7,6 +7,26 @@ Canary, per-draw. 2026-09-01.
|
||||
Answers the Port's `BLOCKED.md` H3 (`auto/port-p6-audio` at `6eccfa8`), both
|
||||
halves. Neither answer rests on a renderer of ours.
|
||||
|
||||
|
||||
> ## 🟡 WEAKENED THE SAME DAY, by my own next experiment — read this first
|
||||
>
|
||||
> **"2 units per guest frame" is a correct measurement and a wrong mechanism.**
|
||||
> [`units-per-second-measured.md`](units-per-second-measured.md) shows the clock
|
||||
> is **time-integrated, not frame-counted**: the same splash animation occupies
|
||||
> **21 labels in one capture and 33 in another**, and splash A's logo steps
|
||||
> `+136, +34` in one and `+17, +51, +34, +34, +17, +17` in the other. The three
|
||||
> consecutive plate steps of exactly 23 below are real; **2** was a property of
|
||||
> that run's frame pacing.
|
||||
>
|
||||
> **What still stands unchanged:** everything on this page that is a *ratio* or a
|
||||
> *count* — the T-vs-step arithmetic that explains the Port's factor of 2.7, and
|
||||
> the settle anchor at t≈160, which is derived from label counts *calibrated on
|
||||
> the plate's own ramp within the same run* and so does not depend on the rate
|
||||
> being constant between runs.
|
||||
>
|
||||
> **What must not be used:** `units = 2 × frames` as a conversion. It computes an
|
||||
> emulator artefact.
|
||||
|
||||
---
|
||||
|
||||
## The prediction, and what happened
|
||||
|
||||
128
docs/re/units-per-second-measured.md
Normal file
128
docs/re/units-per-second-measured.md
Normal file
@@ -0,0 +1,128 @@
|
||||
# Units per second — the clock is **time-integrated**, and the rate is **not yet a number**
|
||||
|
||||
**Status: 🟡 half-answered.** One pre-registered prediction **held**, one
|
||||
**failed**, and the failure is informative. Instrument: ⟨capture⟩ with
|
||||
⟨canary-source⟩ for the clock. 2026-09-01.
|
||||
|
||||
Against [`units-per-second-preregistration.md`](units-per-second-preregistration.md),
|
||||
committed before the capture was taken.
|
||||
|
||||
---
|
||||
|
||||
## What was predicted, and what happened
|
||||
|
||||
| # | prediction | outcome |
|
||||
|---|---|---|
|
||||
| 1 | the clock is **time-integrated**, Δα correlates with guest frame duration, **r > 0.9** | **🟡 direction held, threshold missed.** r = **0.8396** over 19 rising steps spanning a **12.5× duration range** (16.4 → 204.6 ms). Positive and structured, but not r > 0.9 |
|
||||
| 2 | the rate is **60 units per guest second**, accept 55–65 | **❌ FAILED.** Six elapsed-ratio estimates give a median of **29.9**, range 25.2–36.6 |
|
||||
| 3 | 120 and 30 are both excluded | **❌ FAILED in the worst way** — 30 is what came out |
|
||||
|
||||
**A failed prediction is the result.** It is written down before the explanation,
|
||||
because the explanation below is new and untested and the number is not.
|
||||
|
||||
## ✅ The part that IS settled: the clock is not frame-counted
|
||||
|
||||
Prediction 1's threshold was missed but its *subject* is decided, and by a
|
||||
cleaner argument than the regression:
|
||||
|
||||
**The same animation takes a different number of frames in two captures.**
|
||||
|
||||
| element | capture A (2026-09-01, first) | capture B (with tick stamps) |
|
||||
|---|---|---|
|
||||
| splash A's logo `Q0` rising steps | `+136, +34` | `+17, +51, +34, +34, +17, +17` |
|
||||
| splash B's logo trio, labels present | `127…147` (21) | `115…147` (33) |
|
||||
|
||||
A fixed per-frame increment cannot do that. The steps are always integer
|
||||
multiples of **17** (= 255/15, one time unit), so the clock advances in **whole
|
||||
units**, but *how many* per frame is whatever that frame took.
|
||||
|
||||
📌 **This retires "2 units per submitted frame" as a description of the
|
||||
mechanism.** The [H3 measurement](h3-units-per-frame-measured.md) is not wrong —
|
||||
three consecutive plate steps really were exactly 23 = 2 units — but 2 was a
|
||||
property of *that run's frame pacing*, not of the game. Anything the port
|
||||
computes as `units = 2 × frames` is computing an emulator artefact.
|
||||
|
||||
⚠️ **This is my own ✅ row weakened, from `ui-keyframe-time-unit.md` and from my
|
||||
own page of two hours ago.** Recording it here rather than editing either, and
|
||||
proposing rather than enacting a change to the register.
|
||||
|
||||
## ❌ Why the rate is not a number yet, and it is a `T` problem
|
||||
|
||||
```
|
||||
units per second = (Δα / Δt) × T / 255
|
||||
```
|
||||
|
||||
`Δα/Δt` is measured, cleanly, six ways:
|
||||
|
||||
| quad | Δα | guest s | α/s | units/s **if T = 15** |
|
||||
|---|---|---|---|---|
|
||||
| splash A logo | 170 | 0.273 | 622.5 | 36.6 |
|
||||
| splash B logo ×3 | 187 | 0.368 | 508.7 | 29.9 |
|
||||
| splash B companion ×2 | 51 | 0.119 | 428.2 | 25.2 |
|
||||
|
||||
**`T` is the load-bearing term and I have not read it off the disc myself.**
|
||||
`T = 15` comes from `ui-keyframe-time-unit.md`'s ✅ row, and the way I used it
|
||||
here is circular: that row's *shape* result (the ramp is linear, `round(255·k/15)`
|
||||
fits) is independent, but a step of 34 per frame only implies `T = 15` **given**
|
||||
2 units/frame — which is exactly the thing this page has just retired.
|
||||
|
||||
If `T = 30` for these elements the rate is ~60. If `T = 15` it is ~30. **The
|
||||
factor between the two answers is the same factor as the unknown**, so no amount
|
||||
of re-measuring alpha settles it.
|
||||
|
||||
## What settles it, and why the plate is the right element
|
||||
|
||||
**`ptbtn00`.** Its `T = 22` is attested independently of any clock: the four
|
||||
`(time, pose)` pairs `214/236/238/244` are read the same way by two different
|
||||
readers — my own `screen info` dump on a different branch and the port's
|
||||
exporter — differing only in the record association, which is ✅ decoded in
|
||||
[`ui-keyframe-record-layout.md`](ui-keyframe-record-layout.md). Nothing in that
|
||||
chain uses a clock.
|
||||
|
||||
So: capture the plate's ramp **with the guest tick stamps**, take the elapsed
|
||||
ratio over it, and `rate = (Δα/Δt) × 22 / 255` is the answer with no circularity.
|
||||
|
||||
🔴 **That capture did not complete this iteration.** The run reached 531 s of
|
||||
attract loop without presenting the title, against 243 s in the previous run —
|
||||
which is the variable-attract-loop behaviour
|
||||
[`capture-harness-status.md`](capture-harness-status.md) already documents at up
|
||||
to 604 s. The instrument is built and verified; what is missing is one run that
|
||||
gets there.
|
||||
|
||||
## The instrument, and its control
|
||||
|
||||
The draw logger now stamps every frame boundary with the **guest** timebase —
|
||||
`Clock::QueryGuestTickCount()` at `guest_tick_frequency()` — so no host wall
|
||||
clock enters any number above. `emulator.cc:225` sets that frequency to
|
||||
**50 MHz** and `clock.cc:37` leaves `guest_time_scalar_` at **1.0**
|
||||
(⟨canary-source⟩).
|
||||
|
||||
**Control, run before trusting it:** the stamps span **123.24 guest seconds**
|
||||
across a capture that had been running ~118 wall seconds at the time of reading.
|
||||
Guest time tracks real time, as the source says it should. An instrument that
|
||||
disagreed with its own source here would be dead.
|
||||
|
||||
📌 And the guest frame rate is wildly non-uniform — **16.4 ms to 204.6 ms per
|
||||
frame in one splash**. That is 12.5×, in a stretch a wall-clock instrument would
|
||||
have averaged into a single meaningless "fps". It is also why prediction 1's
|
||||
regression is honest but noisy: the steps are quantised to 17 and the residual
|
||||
structure is real, with the long frames advancing **less** than a constant rate
|
||||
predicts.
|
||||
|
||||
🟡 **That residual is unexplained and is a candidate finding in itself** — a
|
||||
clamped `dt`, a capped number of logic steps per frame, or a decoupled logic
|
||||
tick would all produce it. Not tested.
|
||||
|
||||
## What the port should do with this today
|
||||
|
||||
**Nothing yet.** The 60 units/s constant is neither confirmed nor refuted:
|
||||
this page's ~30 rests on a `T` I have not verified, and the argument that
|
||||
retires `2 × frames` does not by itself supply a replacement. Changing it on
|
||||
the strength of a failed prediction would be worse than leaving it.
|
||||
|
||||
## Reach
|
||||
|
||||
Two captures, the boot splashes in both, one title capture without stamps. The
|
||||
"not frame-counted" conclusion rests on a **comparison between captures** and is
|
||||
as strong as the two captures being of the same animation, which their element
|
||||
rects and declared ramps make certain. The rate has no reach at all yet.
|
||||
Reference in New Issue
Block a user