visualdynamics.decimate¶
decimate
¶
Peak-keeping decimation: fewer points, every peak kept.
A million-sample record cannot go to a renderer point for point, and
plain striding is the wrong thinning: it walks straight past the one
spike that was the reason to look at the record. The peak-keeping
reading cuts the samples into equal slices and keeps each slice's
smallest and largest value at their own abscissa positions, so no
resonance, dropout or shock thins away — the same reading pyqtgraph's
peak downsampling gives the 2-D plot.
One implementation, used by the report (a document, not a scope) and by the 3-D waterfall (a scene with a point budget). The core is vectorized over whole records at once because the waterfall hands it hundreds of them: as a per-bin Python loop the same work took 10.6 s on a 320-record million-sample history, batched it is 1.3 s — both measured. numpy only.
Functions:
| Name | Description |
|---|---|
peak_decimate |
(x, y) thinned to about |
peak_decimate_rows |
|
Functions:¶
peak_decimate
¶
(x, y) thinned to about budget points that keep every extreme.
Real values; a caller reading complex data extracts its component first, because "the extremes" of a complex value is not a question with one answer. Input at or under the budget is returned as given.
NaN marks a gap (a specification is NaN outside its band) and never wins an extreme. A slice that is all gap keeps its first point, so the gap survives to be drawn as a gap.
Source code in src/visualdynamics/decimate.py
peak_decimate_rows
¶
peak_decimate for every record of one object at once.
The records share x going in but not coming out: each keeps its
own extremes at their own positions. One vectorized pass over the
whole (records, samples) block, which is what makes decimating a
320-record million-sample history cost tenths of a second rather
than tens.