A batch of view and instrument work, with the probes and docs for each. - **Full screen per figure row**: a toggle on each row's top-right corner, revealed by pointer proximity (`kMaximizeRevealPx` around its placed rect, per row, read from an overlay-level motion controller so a revealed button under the pointer cannot flicker); the plot menu offers the same as *Full screen this figure* / *Restore the layout*. The arrangement is saved and restored through `RowState`, so nothing plotted moves. A layout of one figure carries no toggle. - **Second window**: `open_scope_window()` copies a figure (cells, width shares, signals in their colours) or opens an empty one, with its own `RowSet` and `PlotArea`; the main window's tick binds, acquires and repaints it, mirroring the time window and pin. Entries: the plot menu's *Open this plot in a new window* and the overflow menu's *New scope window*. - **Layout editor from the plot**: the plot menu gains *Edit the layout...* / *Done editing the layout*, flipping the app's one toggle. - **Measurements gate**: `MeasureOptions::gate` restricts a measurement to the held/pause snapshot (live falls back to the live ring), persisted with the session and shown in the measure dialog. - **Crosshair axis badges**: a preference (`crosshair_axis_labels`, on by default) and the plotter's badges where the lines meet the axes, in the axes' own formats; the plot menu and the probe read them. - **Event cache per configuration**: `EventStore` is keyed `<source>/<configuration>/`, `retarget_event_store()` follows every configuration switch, and a pre-configuration cache (loose files) is adopted into the configuration's folder on first start. - **GTK4 lifecycle**: the main window's handlers move from the non-existent `"destroy"` signal to `close-request`; scope windows are closed with it and the application quits explicitly (the exit run's hang). The exit probe closes with `gtk_window_close()`. - Probes: `[maximize-probe]` (single-figure rule and the corner reveal), `[scope-probe]`, `[split-probe]` cell crosshair leg, `[prefs-probe]` store keying, `[configs]` store key, `[rowmenu]` layout-editor entry; docs, help pages, README and AGENT.md updated. Also fixes a probe-only use-after-free: `toggle_maximize_figure_row` replaces the figure object, so the area must be re-pointed (the button's path does; the probe's raw call did not).
190 lines
13 KiB
Plaintext
190 lines
13 KiB
Plaintext
<page xmlns="http://projectmallard.org/1.0/"
|
|
type="topic" style="task"
|
|
id="measurements">
|
|
|
|
<info>
|
|
<link type="guide" xref="index#analysis"/>
|
|
<link type="seealso" xref="cursors"/>
|
|
<desc>A measurement is a statistic of one signal over the window the pane is about — the
|
|
visible range, or the frozen frame while a view is pinned — with optional
|
|
on-plot marks and a per-measurement statistics line.</desc>
|
|
<credit type="author copyright">
|
|
<name>Martino Ferrari</name>
|
|
</credit>
|
|
</info>
|
|
|
|
<title>Measurements</title>
|
|
|
|
<p>A measurement is a statistic of one signal over the window the pane is about, recomputed as
|
|
that window moves. The pane lists them with their values; each can also draw its result on
|
|
the plot.</p>
|
|
|
|
<p>That window is the <em>visible range</em> — so on a live view the numbers follow what you
|
|
pan and zoom to. On a <em>still frame</em> — a held event, a paused stream, an opened file — it
|
|
is the frame's own extent instead, so panning or zooming inside it changes nothing: the data
|
|
being measured has not changed and you are only looking closer.</p>
|
|
|
|
<section id="reach">
|
|
<title>How to reach it</title>
|
|
<steps>
|
|
<item>
|
|
<p>Press <key>m</key>, or <gui>Edit</gui> beside <gui>Measurements</gui> in the dock. Either opens the
|
|
<gui>Measurements</gui> page over the plot; the dock itself shows each measurement's value,
|
|
and a click on one opens its dialog.</p>
|
|
</item>
|
|
<item>
|
|
<p>The page's <gui>+</gui> adds one; clicking a row opens the dialog where the signal,
|
|
the type, the threshold share or shares and the on-plot marks are set, with
|
|
<gui>Save</gui> and <gui>Delete</gui>.</p>
|
|
</item>
|
|
</steps>
|
|
</section>
|
|
|
|
<section id="knowing">
|
|
<title>Worth knowing</title>
|
|
<list>
|
|
<item><p>The types are average, top, bottom, min, max, peak to peak, amplitude, above,
|
|
below, between, pulse duration, period and frequency. <gui>top</gui> and <gui>bottom</gui> are the waveform's
|
|
<em>flat</em> high and low levels: the level the signal dwells at, taken from the densest
|
|
band of the window on each side of the split. A band-limited edge overshoots and rings —
|
|
a nominal 2 V square reaches about ±1.18 at its edges — and a ripple or an overshoot is
|
|
therefore <em>not</em> what these read. <gui>amplitude</gui> is the delta between those two
|
|
levels, and <gui>peak to peak</gui> is the swing between the extremes (so on a rippled
|
|
square <gui>amplitude</gui> reads 2 V where <gui>peak to peak</gui> reads 2.36 V).</p></item>
|
|
<item><p><gui>above</gui>, <gui>below</gui> and <gui>between</gui> are the opposite kind of
|
|
number: the plain <em>mean of the samples</em> above a share, below it, or between two
|
|
shares. That is a different question from <gui>top</gui>/<gui>bottom</gui> even about the
|
|
same split, and it is the older one — on a unit sine <gui>above 50%</gui> reads 0.64 V
|
|
(2/π, the mean of a half cycle) where <gui>top</gui> reads 0.96 V (near the peak, which is
|
|
where a sine dwells most), and on a band-limited square <gui>above 50%</gui> reads 0.99 V
|
|
where <gui>top</gui> reads the plateau, 1.00 V: the edge's ring is inside the first and not
|
|
inside the second. <gui>between</gui> takes <em>two</em> shares — <gui>from %</gui> and
|
|
<gui>to %</gui> — and reports the mean of the samples inside that band, which no single
|
|
split can answer; the order you type them in does not matter, since a band between 80 % and
|
|
20 % is the band between 20 % and 80 %.</p></item>
|
|
<item><p>A mean over a side carries whatever is on that side, so these three are the right
|
|
numbers when you want the <em>energy</em> or the <em>offset</em> of part of the waveform,
|
|
and the wrong ones when you want the level a plateau sits at. Like every other measurement,
|
|
one with nothing to measure reads <code>--</code> rather than a made-up number: a share at
|
|
100 % has no sample above it, and a band can hold none at all — on an ideal
|
|
(non-ringing) square every sample is exactly ±1, so a band between 50 % and 75 % is
|
|
empty.</p></item>
|
|
<item><p><gui>top</gui> and <gui>bottom</gui> also read <em>near the peak</em> on a
|
|
waveform that has no flat part, which is the honest reading rather than a failure: a unit
|
|
sine has no plateau, so the densest band is at its peak and these read about ±0.96 — not
|
|
the 0.64 a mean over each half would give, and not ±1 either. Only a level the signal
|
|
actually dwells at is a level.</p></item>
|
|
<item><p>The <em>split</em> says which side a level is read from, so any share between the
|
|
two levels reads the same number; it is not a boundary the value depends on. The one case
|
|
where it is read directly is a window the scope cannot summarize by level — a window
|
|
shorter than a level's own resolution, or one read through <gui>hf</gui> — where
|
|
<gui>top</gui>/<gui>bottom</gui> fall back to the mean of each side of the split and
|
|
<gui>amplitude</gui> to the window's peak to peak.</p></item>
|
|
<item><p>Each row names the <em>channel</em> it measures: its number among the active
|
|
channels (1., 2., … the same number the signal's badge in the bar carries), its name, and
|
|
the type — <code>1. sine · average</code>. The measurement dialog's signal dropdown
|
|
numbers its entries the same way. A channel list that changes (a signal switched off, a
|
|
new one enabled) renumbers, because the number is the answer to "which active channel is
|
|
this".</p></item>
|
|
<item><p>The on-plot marks come in two kinds and the mix is the reading: a <em>level</em>
|
|
mark is a ruler at a value — its value written in a small box on the ruler, the way the
|
|
axis writes its own ticks — and a <em>time</em> mark is a marker at a position, with the
|
|
position's own badge beside it. A level ruler's badge carries its number; a time
|
|
marker's carries its time. Marks whose badges meet share one panel with one line each,
|
|
so a column of close readings is one boxed readout rather than a smear of texts; and a
|
|
box over a noisy trace is what keeps the number readable. An average
|
|
draws one level mark; a max draws a level mark <em>and</em> a time mark at the first
|
|
sample that reached it; <gui>peak to peak</gui> draws a ruler at each extreme and
|
|
<gui>amplitude</gui> a ruler at each of its two flat levels — the pair is the span, so
|
|
the two rulers <em>are</em> the measurement.</p></item>
|
|
<item><p>Marks cannot be dragged. A measurement mark says what the measurement measured,
|
|
so it is created unselectable — as is the trigger marker.</p></item>
|
|
<item><p>A pass is throttled to a cadence rather than run every frame, so a ruler over a
|
|
live view is <em>stepped</em>. The number and the ruler come from the same pass, so they
|
|
always agree.</p></item>
|
|
<item><p>An invalid pass keeps its <em>level</em> marks and drops its <em>time</em>
|
|
marks. A level is a property of the signal and outlives the window; a position inside
|
|
the window does not. That is what stops the rulers blinking off at a mode change.</p></item>
|
|
<item><p>A crossing is counted with <em>hysteresis</em>, not on a bare level: the
|
|
thresholds are a tenth of the window's peak to peak either side of the share, and an
|
|
edge is counted only once the signal has passed the far one. Period, frequency and pulse
|
|
duration all depend on it. The mid level is exactly where a waveform moves fastest, so
|
|
any interferer faster than the fundamental recrosses a single level several times per
|
|
real crossing — a 5 Hz sine with a 500 Hz tone at a tenth of the amplitude reads 39 Hz
|
|
without the band and 5 Hz with it. The band holds to an interferer a third of the
|
|
waveform's own size.</p></item>
|
|
<item><p>The band is clamped to stay inside the data, which is what keeps a threshold set
|
|
near an extreme usable: a fixed band there would sit above every sample and the
|
|
measurement would read nothing. A share near an extreme still leaves the band little
|
|
room, so it rejects less — which is one reason period and frequency offer no share to
|
|
set.</p></item>
|
|
<item><p>A window with too few crossings reads <code>invalid</code> / <code>--</code>
|
|
rather than a plausible invented number. Frequency over a window holding one edge is the
|
|
usual case.</p></item>
|
|
<item><p><gui>frequency</gui> is reported in Hz and <gui>period</gui>/<gui>pulse
|
|
duration</gui> in seconds; every other type carries the channel's own unit. A value is
|
|
written with a <em>metric prefix</em> so its digits sit in <code>1..999</code> —
|
|
<code>636.62 mV</code>, not <code>0.64 V</code> — including when the stream declares no
|
|
unit at all, which is always the case for a math channel: there the prefix goes tight
|
|
against the number (<code>636.62m</code>), since two decimals of an unprefixed small
|
|
value is <code>0.00</code>.</p></item>
|
|
<item><p>Cost is bounded by reading the summary pyramid the producer already maintains,
|
|
not the raw window: a bucket's sum is a sum, so the mean, the extremes and a level's own
|
|
mean are exact. <gui>top</gui>, <gui>bottom</gui> and <gui>amplitude</gui> read the
|
|
<em>density</em> of the window out of that same summary — which is what tells a flat level
|
|
from a ripple — so those three cost a second read of the summary and never of a sample, and
|
|
<gui>between</gui>'s second share is one more level in the same summary walk rather than a
|
|
walk of its own.</p></item>
|
|
<item><p><gui>Statistics</gui> adds a second line to every measurement showing
|
|
<code>n</code>, the mean, the standard deviation and the range. Each observation is one
|
|
<em>recompute</em> of the pane, so <code>n</code> counts windows measured, not samples —
|
|
a mean frequency over many windows is what that claims to be. <gui>Reset</gui> clears
|
|
every accumulator and starts fresh. A change of display window, a CONFIG or a
|
|
measurement edit also resets; a pause, a resume, a zoom, a pan and the toggle itself do
|
|
not, so turning the line off to read the plot and back on again keeps the history. On a
|
|
still frame a pan or a zoom changes nothing for the history to record in the first place —
|
|
the values do not move there at all.</p></item>
|
|
</list>
|
|
</section>
|
|
|
|
<section id="gate">
|
|
<title>The gate</title>
|
|
<p>A measurement's dialog carries <gui>Gate enabled</gui>. Every measurement
|
|
with it set reads only the samples inside one shared band — violet, labelled <em>gate</em>,
|
|
carried by its own two draggable edges on the plots, which are not the cursors (those keep
|
|
meaning what the cursors pane reads). Measurements without it are untouched: they read the
|
|
whole window and share the walks they always shared.</p>
|
|
<p>The band is shown exactly while some measurement is gated — gate one and it appears,
|
|
gate or delete the last one and it goes — because it is one area that all of the gated
|
|
measurements share, not a property of any one of them. Drag an edge to resize it, grab the
|
|
middle to move it.</p>
|
|
<p>The band lives in the same relative time the axis labels use, so it stays where it was
|
|
put in both modes: live, a band at 300 ms to 100 ms ago stays put on screen while the data
|
|
streams beneath it — the gated read of the newest data a bench scope gives — and on a held
|
|
event it names a fixed slice of the frozen frame. A band with no samples in it — dragged
|
|
outside the view, or over a gap — reads <code>--</code> like any empty window. The band's
|
|
position and each measurement's gate flag are saved with the session.</p>
|
|
</section>
|
|
|
|
<section id="example">
|
|
<title>Example</title>
|
|
<p>On a 1 Hz ±1 sine: <code>average=0</code>, <code>top=0.957988</code>,
|
|
<code>bottom=-0.957988</code> (the flat levels, near the peaks — a sine has no plateau),
|
|
<code>max=1</code>, <code>min=-1</code>,
|
|
<code>peak to peak=2</code>, <code>amplitude=1.915983</code>, <code>pulse duration=0.5 s</code>
|
|
(duty 0.5), <code>period=1 s</code>, <code>frequency=1 Hz</code>. On the same stream's
|
|
band-limited <code>square</code>, whose edges ring out to ±1.179: <code>top=0.999983</code>,
|
|
<code>bottom=-0.999983</code>, <code>amplitude=1.999966</code> against
|
|
<code>peak to peak=2.358701</code> — the levels are the plateau's and the extremes are the
|
|
edges'. Over a 2 M-sample window those passes read about 0.1% of the samples.</p>
|
|
<p>The mean-over-a-side types on the same two windows: on the sine
|
|
<code>above 50=0.636620</code>, <code>below 50=-0.636620</code> and
|
|
<code>between 50 75=0.255873</code>; on the rippled square <code>above 50=0.986496</code> and
|
|
<code>between 50 75=0.302744</code>, against <code>1.000000</code> for the same
|
|
<code>above 50</code> on an ideal (non-ringing) square. A <code>ramp</code>, whose density is
|
|
uniform, is the shape that names what a band mean <em>is</em>: <code>above 50=0.500000</code>
|
|
and <code>between 50 75=0.250000</code>, each band's own centre.</p>
|
|
</section>
|
|
|
|
</page>
|