re(flight): polling faster than the guest updates manufactures a clean curve

Fitting rate against instantaneous speed produced a tidy "rate rises with speed"
relationship, with speeds up to 4795 when the craft's maximum is 1200. It is
entirely an artefact: 20 Hz polling is faster than the guest updates these fields,
so a per-read delta is either exactly zero (no update yet) or a whole frame's
worth divided by a fraction of a frame. 111 of 352 reads were zero on BOTH
channels -- position and attitude update on the same frame, so the two are
perfectly correlated, and dividing each by the short wall dt produced the
correlation out of nothing.

Fix: aggregate over windows spanning many frames (0.5 s). A sum of |delta| over
such a window is right however the updates fall inside it.

This does NOT affect the swept-total probes (roll_axis.py, rate_probe.py) -- they
already summed over the whole dwell, immune for the same reason. Only per-sample
instantaneous rates were ever wrong, so no earlier number moves.

The windowed re-run is NOT yet claimed as a result. It gives plausible magnitudes
but still shows rate rising with speed, against the definition's PitchPlus_Min 150
> _Max 70, and it has two disqualifiers: it ran on an instance where the craft was
already tumbling from the previous sweep, so pinning reported "WEAK -- craft may
not be level", and the sweep started mid-range rather than at maximum. A clean
answer needs a fresh flight with pinning CONFIDENT and nothing before it. Since
what is in doubt is precisely what _Min/_Max mean, a measurement through a
doubtful instrument cannot settle it.

Both datasets kept, the bad one labelled, because the aliased curve is a good
example of what a manufactured correlation looks like.
This commit is contained in:
2026-08-13 23:00:59 +00:00
parent 6c7025851e
commit 0a84c1358e
4 changed files with 550 additions and 0 deletions

View File

@@ -545,3 +545,43 @@ better and gives the whole rate-vs-speed curve rather than two points.
reimplementation that treats the throttle as setting a speed the craft simply holds
will be wrong during manoeuvres. Data:
[`captures/pitch-rate-speed-bleed.csv`](captures/pitch-rate-speed-bleed.csv).
## ⚠️ Polling faster than the guest updates manufactures a curve
Trying to fit rate against *instantaneous* speed (`rate_curve.py`, one long hold so
the speed-bleed sweeps the range) produced a beautifully clean result that is
entirely an artefact:
```
speed 0- 599 rate 29.4 speed 1199-1798 rate 279.8
speed 599-1199 rate 174.9 speed 1798-2398 rate 317.5
```
Rate rising with speed, and speeds to **4 795** when the craft's maximum is 1 200.
The cause: **20 Hz polling is faster than the guest updates these fields**, so a
per-read delta is either exactly zero (no update yet) or a whole frame's worth
divided by a fraction of a frame. In that run **111 of 352 reads were zero on BOTH
channels** — position and attitude update on the same frame, so the two are
perfectly correlated, and dividing each by the short wall `dt` produced a tidy
correlation out of nothing.
**Fix: aggregate over windows spanning many frames** (0.5 s here). The sum of
`|Δ|` over a window is right however the updates fall inside it.
**This does NOT affect the swept-total probes** (`roll_axis.py`, `rate_probe.py`):
they already summed over the whole dwell, which is immune for the same reason. Only
per-sample instantaneous rates were ever wrong.
🟡 **The windowed re-run is not yet a result.** It gives plausible magnitudes
(speed 320935, rate 80149 °/wall-s) but still shows rate *rising* with speed,
against the definition's `AV_PitchPlus_Min` 150 > `_Max` 70. Two disqualifiers: it
ran on an instance where the craft was already tumbling from the previous sweep, so
the row pinning reported **WEAK — craft may not be level**, and the starting speed
was mid-range rather than maximum. A clean answer needs a **fresh flight**, pinning
CONFIDENT, one sweep, nothing before it. Recorded as an open question rather than a
finding — the definitions' `_Min`/`_Max` meaning is exactly what is in doubt, so a
measurement taken through a doubtful instrument cannot settle it.
Data: [aliased, for reference](captures/rate-curve-aliased-BAD.csv) ·
[windowed](captures/rate-curve-windowed.csv).