measure: the split's own means are back as above/below/between
`top`, `bottom` and `amplitude` became the *flat levels* in e83ad86 -- the level the
signal dwells at, read from the density of the window's buckets -- and that change kept
the split's own two means as its internal fallback for a window the pyramid cannot
summarize. Those means are now three types of their own, so the two different questions
about one split can be asked side by side: `above %` and `below %` are the plain mean of
the samples on one side of a share -- the reading the old `top`/`bottom` gave -- and
`between % %` is the mean of the band between two shares, which no single split can
answer, because a band's two edges are two thresholds.
Nothing about the arithmetic is new, and nothing is a new pass. `Above`/`Below` are the
`sum[]`/`count[]` split `measure_accumulate()` already folds -- the very figures
`Top`/`Bottom` fall back to -- and `Between` is the **difference of two levels' upper
sides**, both of which come out of one pass two over one window. It rides the bucket
fast path unchanged: a bucket wholly inside the band is strictly above the lower level
and strictly below the upper one, so both accumulators fold it whole, and only the
buckets that straddle either edge are opened. `measure_level_pcts()` is the one place the
shares are read, and it clamps both and puts `between`'s pair **in order**, so "between
80 % and 20 %" is the band between 20 % and 80 % -- normalized rather than refused,
because the shares name two edges rather than a direction. Nothing to measure reads `--`,
as for every other type: a share at 100 % has no sample above it, and a band can hold
none at all.
Measured, `[bandavg-probe]`, fast mock at a 2 s window (`--rate 1300000 --batch 1000
--freq 1`):
sine `above 50` 0.636620 (2/pi), `below 50` -0.636620, `between 50 75` 0.255873
square `above 50` 0.986496 (30 harmonics) / 1.000000 (--square-harmonics 0),
`between 50 75` 0.302744 / --
ramp `between 50 75` 0.250000 and `above 50` 0.500000, `above 100` --
The first three are the figures the old `top`/`bottom` documented; the ramp's are what a
uniform density predicts (a band's mean is its own centre); the ideal square's empty band
is the nothing-to-measure rule. The pane offers the types and edits their percentages
through the dialog's second share -- which only `between` shows -- and a measurement's
pair survives add/edit/delete and the session file (`threshold2`), where a file written
before it existed loads at the default.
No raw pass: with the measurements probe adding one of every type at a 2 s window, `raw`
went from 113966 of 240719031 covered (0.0%) to 134978 of 255372033 (0.1%), 0.8 -> 1.1
ns a covered sample.
Docs: the band-average invariant (and the two assertions the flat-level change moved),
the probe readings for the new probe, the verification recipe, the manual's measurements
page and the README.
This commit is contained in:
1 parent
e83ad86b8f
commit
22e7a8efcc
14 files changed
+769
-98
No files matched your search
@@ -236,6 +236,8 @@ measurement.
|
||||
| `max` / `min` | the extremes | — | a ruler at the value **and** a marker where it happened |
|
||||
| `peak to peak` | the swing, `max - min` — the extremes, ripple and overshoot included | — | a ruler at each extreme |
|
||||
| `amplitude` | the two flat levels' delta, `top - bottom` | — | a ruler at each flat level |
|
||||
| `above` / `below` | the mean of the samples **above** / **below** a share — a mean *over a side*, not a level (see below) | split % | a ruler at the mean |
|
||||
| `between` | the mean of the samples **between** two shares | from %, to % | a ruler at the mean |
|
||||
| `pulse duration` | the mean width of the pulse-side runs | split %, which side is the pulse | markers at the pulse's two edges |
|
||||
| `period` / `frequency` | the spacing of the threshold crossings / its reciprocal, in Hz | — | markers at two edges of a cycle |
|
||||
|
||||
@@ -263,6 +265,39 @@ for it at all. Where the pyramid cannot summarize the window — an `hf`-filtere
|
||||
shorter than a bucket — there is no density estimate, and the types fall back to the old
|
||||
behaviour: the mean of each side of the split, and `max - min` for `amplitude`.
|
||||
|
||||
**`above`, `below` and `between` are those side means, exposed.** The flat-level change kept the
|
||||
split's own two means as its *fallback* for a window the pyramid cannot summarize; these three
|
||||
types are that fallback, named, so the two different questions about one split can be asked side by
|
||||
side. On a unit sine `above 50` reads `0.636620` — 2/π, exactly what `top` reported before it became
|
||||
a level — where `top` reads `0.957988`; on the mock's band-limited square `above 50` reads
|
||||
`0.986496`, where the plateau is 1 and `top` is `0.999983`, because the mean *over a side* carries
|
||||
the edges' ring and the level the signal dwells at does not. `between` is new arithmetic in one
|
||||
sense only: it is the samples above the lower edge **and not** above the upper one, so it is a
|
||||
*difference of two levels* — no wider split can answer a band, because a band's two edges are two
|
||||
thresholds — and it rides the same bucket walk (a bucket wholly inside the band folds into both
|
||||
accumulators whole), which is why `measure cost:`'s `raw` is unchanged by it. The readings, on the
|
||||
fast mock at a 2 s window, `[bandavg-probe]`: sine `above 50` `0.636620`, `below 50` `-0.636620`,
|
||||
`between 50 75` `0.255873` (3(2−√3)/π — neither the window's mean nor the band's edge); rippled
|
||||
square `above 50` `0.986496` and `between 50 75` `0.302744` (the two edges' transitions);
|
||||
`ramp` `between 50 75` `0.250000` and `above 50` `0.500000`, because a uniform density makes every
|
||||
band's mean that band's **own centre**; ideal square (`--square-harmonics 0`) `above 50` `1.000000`
|
||||
and `between 50 75` `--`, because every sample is exactly ±1 and the band holds none.
|
||||
|
||||
Three things to know before reading one of those numbers:
|
||||
|
||||
- **The pair is ordered on read, not refused.** "between 80 % and 20 %" is the band between 20 % and
|
||||
80 %: the two shares name two *edges* and the band does not depend on which was typed first, so a
|
||||
reversed pair is normalized rather than turned into a silent `--`.
|
||||
- **Nothing to measure reads `--`**, like every other type: a share at `100 %` has no sample above
|
||||
it (the level is the window's own maximum) and a band whose interior holds none — the ideal
|
||||
square above — is `invalid`/`--`, never `0`.
|
||||
- **The sixth decimal follows the window's boundary.** The live window is closed at both ends, so
|
||||
its oldest and newest sample share a phase, and one extra sample out of ~2.6 M moves the mean by
|
||||
about one unit in the sixth decimal: over one run `above 50` on the sine printed `0.636620` on
|
||||
most `[measure-trace]` lines and `0.636621` on a few, `above 50` on the square `0.986496` on most
|
||||
and `0.986495` on the rest. The old `top`/`bottom` spread exactly the same way — it is a property
|
||||
of a mean over a finite window, not of these types.
|
||||
|
||||
`period` and `frequency` deliberately take **no options**: the engine counts *rising*
|
||||
crossings of the *mid* level, one edge per cycle, and a split or a side to choose from could
|
||||
only make that count wrong — a split near either extreme leaves the hysteresis band below no room
|
||||
@@ -272,7 +307,7 @@ The split is a share of the **window's own** min..max, not volts: a measurement
|
||||
signal in this window, and a level in volts would have to be typed for every signal. For
|
||||
`top`/`bottom` it says **which side** the level is read from, so any split between the two
|
||||
plateaus reads the same number — it is no longer a mean *over* the side, which is the reading a
|
||||
ringing edge used to drag.
|
||||
ringing edge used to drag — and for `above`/`below` it is the level that mean is taken about.
|
||||
|
||||
Two more options ride on it, both at their old behaviour by default:
|
||||
|
||||
@@ -337,7 +372,9 @@ Each measurement's row carries **two badges**: its own colour (the same one its
|
||||
the plot) and the signal's chip, in the colour every other view names that signal with —
|
||||
through `RowSet::signal_color()`, so a signal the user re-coloured is re-coloured here too and
|
||||
not left at the palette entry. The dialog's fields and their wording follow the type — the split row is absent for
|
||||
`average`, `min` and `max`, the side row only for `pulse duration`, and the "show on plot"
|
||||
`average`, `min` and `max`, the side row only for `pulse duration`, the second share ("to % of the
|
||||
range") only for `between`, which is the one type whose two edges are both parameters, and the
|
||||
words on the split row name its side ("above % of the range" for `above`) — and the "show on plot"
|
||||
line says what would be drawn.
|
||||
|
||||
The values are **window statistics over exactly the visible range, at the stored rate**: the
|
||||
@@ -382,7 +419,8 @@ Both walks go through it:
|
||||
and one raw scan of that bucket alone then pins it to a sample — two buckets at most, whatever
|
||||
the window's size. The two stamps the scan needed are read at the end rather than at every
|
||||
chunk that moved an extreme, since a stamp is a ring read and an extreme moves many times.
|
||||
- **Pass two** (the crossing types — `pulse duration`, `period`, `frequency` — and, as a fallback
|
||||
- **Pass two** (the crossing types — `pulse duration`, `period`, `frequency` — the band averages,
|
||||
and, as a fallback
|
||||
for a window with no histogram, `top`/`bottom`)
|
||||
folds a bucket's sums whenever it lies *strictly* on one side of its level — then every sample
|
||||
in it falls in the same bin and none is *at* the level, so the fold is exact. It then asks
|
||||
@@ -396,12 +434,17 @@ samples produced since this frame's `acquire_all()` (bounded by one frame of pro
|
||||
for those opened buckets. Nothing is decimated or strided: `peak to peak` still reads
|
||||
exactly `2` on a unit sine, and the shared pass that carries it is untouched — `top` has no
|
||||
*exact* reading to protect any more, because it is a flat level read from a density rather than
|
||||
the half-wave mean it used to be (`0.636620` on a unit sine; it is `0.957988` now, near the peak,
|
||||
because a sine has no plateau). A window shorter than a bucket, or a signal
|
||||
the half-wave mean it used to be (that mean is now `above 50`, which reads `0.636620` on a unit
|
||||
sine where `top` reads `0.957988`, near the peak, because a sine has no plateau). A window shorter
|
||||
than a bucket, or a signal
|
||||
noisy enough to cross a threshold everywhere, degrades back towards the O(window) cost and nothing
|
||||
else changes. The dump's `measure cost:` line reports `covered`, `buckets` and `raw` for exactly
|
||||
this: `raw` near `covered` means the pyramid bought nothing — and `raw` is unchanged by the flat
|
||||
levels, which read the *same* bucket list a second time and never a sample.
|
||||
levels, which read the *same* bucket list a second time and never a sample, and by the band
|
||||
averages for the same reason (`between` is a **second level in the same walk**: with the
|
||||
measurements probe adding one of every type at a 2 s window, `raw` went from `113966` of
|
||||
`240719031` covered — `0.0%` — with ten types to `134978` of `255372033` — `0.1%` — with
|
||||
thirteen).
|
||||
|
||||
### What the math channels cost
|
||||
|
||||
|
||||
Reference in new issue
Block a user