Only learn the hoops shot from flights that actually show it - #7
Merged
Merged
Conversation
The README carried this as an open question: per-shot curvature ranging 1.71-3.01, a +/-30% swing from shots taken the same way, and "either the shot genuinely varies or the single-shot fit is noisy". It is the fit. Fitting x(t) and y(t) separately across 15 flights read out of the running game over the DevTools protocol -- which needs no release instant, and cannot degenerate the way y-as-a-function-of-x does -- puts the horizontal release speed at 536-541 px/s on every well-tracked flight. The shot is the same shot to half a percent. The fixed three-parameter model was right all along; what was wrong is what got fed into it. Two things were being learned from that should never have been: SHORT TRACKS. fitXY returns a curve from 40px of horizontal spread, and curvature error goes as 1/spread^2, so a fit over a short arc is a guess wearing a number. The three wildest calibrations in the sample -- 2.941, 1.865 and 2.716 against a true 2.23 -- are exactly the three shortest tracks, spans of 200, 143 and 140px. BOUNCES. Coming off the backboard or the far lip of the rim are both ordinary ways to score, and both send the ball back over x it has already crossed. The curve is fitted as y of x, so that is not a hard fit but an impossible one, two y for one x. This is where curvature reached 55. A projectile's x is monotonic, so a retreat from the furthest point reached detects it outright; the margin is 1% of width because the tracker's own x jitter measured 3-7px rms. Sweeping the span gate over those flights, as commits kept and spread of the committed curvature: none (shipped) 15 commits 47.4% 1.865-2.941 0.15 W 10 commits 8.2% + bounce cut 4.3% 0.20 W 10 commits 7.7% + bounce cut 4.2% 0.25 W 10 commits 7.2% + bounce cut 4.0% 0.30 W 10 commits 5.1% 0.35 W 7 commits 2.0% 0.40 W 2 commits 0.9% Commits hold flat from .15 to .30 and fall off a cliff above, so .20 is the middle of the plateau rather than an edge. 47.4% to 4.2%, for two commits out of ten, and a commit is cheap because the calibration averages. The 40px floor stays in fitXY so the live arc still draws early in a flight; only learning waits. calVer 6, because anything learned under the old policy is contaminated rather than stale -- a live config caught mid-session held 2.486 -- and averaging more shots into it does not wash it out. The seed moves to the medians of the 8 flights that pass both screens: A 2.233 (was 2.103, 6% low), L -0.119 (was -0.179), R 0.547 (was 0.557, which the old five-shot seed already had right). R is also the only one of the three the tracked points actually cover; the upward crossing sits behind where tracking starts, so every estimate of it is an extrapolation and its spread across shots is a quarter of its value. Noted as unsettled rather than fixed.
The anchor is stable and precisely detected -- width 177px in 2565 of
2566 logged frames, x never observed to move at all -- and it is still
the biggest error left, because anchoring to it does not produce a
shot-invariant frame the way the model assumes.
shotL and shotR describe the shot, so they should not care where the
platform is. Measured over two independent runs off the live game:
corr(platY, shotL) corr(platY, shotR)
8 flights -0.79 +0.71
5 flights -0.86 +0.77
Curvature barely moves, which is the tell. shotA is set by g/2vx^2 and
neither cares how high the platform is, while shotL and shotR are where
the arc meets platform HEIGHT. That is half the variance in the two
weakest numbers, ~40px each, the same order as the leave-one-out landing
error -- so the anchor is the next thing to fix, not the fitting.
Three explanations measured, none survived, all written down so the next
person does not spend the afternoon re-testing them:
- Stale anchor. flightPlat is sampled a frame or two after release and
the platform IS moving then (26 of 32 releases, ~135px/s, biased
upward). But recomputing L and R against the platform at release+dt
across -200..+400ms produces no minimum; the spread falls
monotonically and is still falling at -200ms, before release.
- The detector picking a different row as the platform moves. The
detected width was 177px in 2565 of 2566 frames.
- The ball inheriting the platform's velocity. platV correlates worse
than platY, -0.68 against -0.86 for L, though on an oscillating
platform the two are confounded and five flights cannot separate
them.
Also recorded: the anchor y snaps to a 5.5px grid because findPlatform
runs on the downscaled readback, which works out at ~4% of the observed
spread and is not worth chasing; and the platform has never been seen to
move horizontally, so that half of the anchor is untested and first
matters when the platform starts looping.
No behaviour change. Numbers only.
The last commit called the platform anchor "the biggest error left" on the strength of shotL and shotR correlating with platform height. That correlation is real and replicates, but the conclusion drawn from it was wrong, and it would have sent the next person down a dead end. Modelling shotL as linear in platform height does predict it much better out of sample -- leave-one-out mean error 51.6px to 29.6px, a 43% gain, with shotR going 40.8 to 37.7px. So the correction works on the parameters. But the number that decides a make is the height of the arc where it crosses the RIM, and measured there: constant, as shipped mean 54.7px worst 117.5px linear in platform height mean 53.0px worst 113.9px Three percent. The errors in A, L and R are correlated and very nearly cancel by the time the curve reaches the rim, so a correction that plainly improves two of three parameters is worth almost nothing where it counts. Not shipped: an unexplained empirical correction fitted on 11 flights from one player has to clear more than 3%. What this does establish is where the ceiling actually is. ~55px of arc height at the rim, and it is per-shot noise in the two crossings, not the anchor. Averaging across shots is what removes it, which is what the commit weighting already does -- so the useful advice is the one the README already gives: do not reset between shots.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
The README carried this as an open question: per-shot curvature ranging 1.71–3.01, a ±30% swing from shots taken the same way, and "either the shot genuinely varies or the single-shot fit is noisy".
It is the fit. Fitting
x(t)andy(t)separately across 15 flights read out of the running game over the DevTools protocol — which needs no release instant, and cannot degenerate the wayyas a function ofxdoes — puts the horizontal release speed at 536–541 px/s on every well-tracked flight. The shot is the same shot to half a percent. The fixed three-parameter model was right; what was wrong is what got fed into it.Two things were being learned from that shouldn't have been:
Short tracks.
fitXYreturns a curve from 40px of horizontal spread, and curvature error goes as 1/spread², so a fit over a short arc is a guess wearing a number. The three wildest calibrations in the sample — 2.941, 1.865, 2.716 against a true 2.23 — are exactly the three shortest tracks, spans of 200, 143 and 140px.Bounces. Coming off the backboard or the far lip of the rim are both ordinary ways to score, and both send the ball back over
xit has already crossed. The curve is fitted asyofx, so that isn't a hard fit but an impossible one — twoyfor onex. This is where curvature reached 55. A projectile'sxis monotonic, so a retreat from the furthest point reached detects it outright.Span gate swept over those flights:
Commits hold flat from .15 to .30 and fall off a cliff above, so .20 is the middle of the plateau rather than an edge. 47.4% → 4.2%, for two commits out of ten — and a commit is cheap because the calibration averages. The 40px floor stays inside
fitXYso the live arc still draws early in a flight; only learning waits.calVer6, because anything learned under the old policy is contaminated rather than stale (a live config caught mid-session held 2.486) and averaging more shots into it doesn't wash it out. The seed moves to the medians of the 8 flights passing both screens: A 2.233 (was 2.103), L −0.119 (was −0.179), R 0.547 (was 0.557 — which the old five-shot seed already had right). R is also the only one of the three the tracked points actually cover; the upward crossing sits behind where tracking starts, so every estimate of it is an extrapolation, and its spread across shots is a quarter of its value. Left flagged as unsettled rather than claimed as fixed.node --checkpasses on both files; suite regenerated from the standalone script (hoops 1.8 → 1.9, suite 1.6 → 1.7). Shipped build injected into a live session loads and runs clean.Not yet observed end-to-end: the gating is verified by replaying the live rule over 15 recorded trajectories, but I haven't watched a fresh session commit under the new code and confirm the values stay in 2.19–2.29.