The plotter now deposits every acquisition -- the newest included -- into one grid per trace and
draws no solid trace over it, each grid in that trace's colour and with a one-sweep ceiling (its own
commit, **1b8b55d**). This side needed almost no change of its own, because the colour was already
the trace's and the trace's colour is `RowSet::signal_color()` -- the invariants' one route -- but the
figures it reads back are now per trace:
- **The ceiling is left at the library's default of one sweep**, no longer derived from the fade.
Deriving it from the steady state is the gain offset the user reported between the latest
acquisition and the persistent image; a signal crossing the same place every acquisition now settles
at the trace's colour, at full strength, and the newest sweep reads as the trace it is a picture of.
- **`cells`/`grid_bytes` are the sum over the row's traces** -- one grid each, a trace with no series
holding none -- and both the probe and the exit dump carry `traces=` beside `rows=`. That is what
makes the per-signal memory figure read: **556 537 cells and 2.2 MB per signal**, at 8904600 bytes
over the four one-signal rows of the probe's run.
The probes, re-read on this build (the `verification.md` command, `--rate 500000 --batch 1000`):
[density-probe] off enabled=0 ... rows=0 traces=0 cells=0 ink=0.0 peak=0.0000
[density-probe] on enabled=1 ... rows=4 traces=4 cells=2226150 ink=226786.0 peak=1.0000
[density-probe] step-acquisitions ... peak=1.5000
[density-probe] time-before ... peak=2.1359
[density-probe] step-time ... ratio=0.367879
[density-probe] frame cost: tick 0.62 -> 6.96 ms (184/23 frames), draw 2.02 -> 6.16 ms (177/18)
[udpscope] density: frames=748 rows=4 traces=4 cells=2226150 grid_bytes=8904600 ink=489400.2 peak=2.2 upload_bytes=2226150
`on` `peak=1.0000`, `step-acquisitions` `peak=1.5000` and `step-time` `ratio=0.367879` are the legs
that were expected, unchanged; the *draw* mean is now **below** the run before the split (2.02 -> 6.16
against 2.09 -> 20.91), because the solid traces are no longer drawn over the image.
Docs updated with it: the trigger manual page (`persistence` is the trace, one image per signal, the
newest included), the README's persistence section, `invariants-trigger-and-pinning.md` (five rules,
the ceiling and the no-stroke rule among them), `verification.md` and `probe-readings.md` (the lines
above), the trigger panel's comment and tooltips, and the plotter submodule.
`cmake --build build --clean-first -j4`: **0 errors, the documented three warnings** (two
`MathNode::source`, one `-Woverlength-strings` at 12352); `make -C build test-ui` **13 ok**;
`make -C build test-help` **green** (15 pages); the self-check **0 `Gtk-WARNING`/`Gtk-CRITICAL`** and
`gtk warnings: 0`, two `buffer allocated:` lines.
284 lines
16 KiB
Plaintext
284 lines
16 KiB
Plaintext
<page xmlns="http://projectmallard.org/1.0/"
|
|
type="topic" style="task"
|
|
id="trigger">
|
|
|
|
<info>
|
|
<link type="guide" xref="index#viewing"/>
|
|
<link type="seealso" xref="pause"/>
|
|
<desc>The trigger's four shapes, arming, forcing an acquisition and hold-off, the event cache with its replay,
|
|
compare and accumulate, and searching the buffer for a condition.</desc>
|
|
<credit type="author copyright">
|
|
<name>Martino Ferrari</name>
|
|
</credit>
|
|
</info>
|
|
|
|
<title>Trigger</title>
|
|
|
|
<p>The trigger watches one signal for a condition and captures a window around it. The
|
|
<gui>Shape</gui> dropdown chooses what counts as an event; the arming, hold-off, pre/post
|
|
window and Normal/Single mode are the same for all four shapes. The captured window is
|
|
frozen on screen until you re-arm.</p>
|
|
|
|
<section id="reach">
|
|
<title>How to reach it</title>
|
|
<steps>
|
|
<item>
|
|
<p>The trigger button in the toolbar (<key>t</key>) reveals the trigger panel: the
|
|
signal, the level, the shape, the edge (rising, falling, either), the mode (Normal or
|
|
Single) and the pre-trigger share.</p>
|
|
</item>
|
|
<item>
|
|
<p><gui>Arm</gui> starts watching; <key>a</key> arms and disarms from the keyboard.
|
|
When the pane is locked with its <gui>[edit]</gui> button — so that it states what the
|
|
trigger is set to instead of showing the controls — <gui>Arm/Disarm</gui> is in its
|
|
heading, and the trigger can be armed or disarmed without unfolding the panel. It is
|
|
offered only while trigger mode is on, because a trigger that is off has no engine to
|
|
arm.</p>
|
|
</item>
|
|
<item>
|
|
<p><gui>Force</gui> takes one acquisition <em>now</em>, with the event window above,
|
|
without waiting for the condition to hold — for when the event you are waiting for is not
|
|
coming and you want to see what the signal is doing this instant. The capture runs out its
|
|
post-trigger share and then freezes, exactly like a latch: the marker sits at the instant
|
|
you pressed. In <gui>Normal</gui> mode the trigger goes back to waiting afterwards; in
|
|
<gui>Single</gui> mode it disarms, because one acquisition is the whole of what that mode
|
|
means either way. It needs a signal to be acquired — the trigger cannot watch one that is
|
|
switched off — and pressing it while a capture is already filling leaves that capture
|
|
alone, since it is the acquisition you asked for.</p>
|
|
</item>
|
|
<item>
|
|
<p><gui>Search the buffer</gui> is at the foot of the same panel.</p>
|
|
</item>
|
|
</steps>
|
|
|
|
<figure>
|
|
<title>A held capture</title>
|
|
<desc><gui>event held</gui> in the status bar, the axis pinned to the event, and the
|
|
trigger marker at x = 0.</desc>
|
|
<media type="image" mime="image/png" src="figures/trigger-capture.png" width="1280" height="800">
|
|
<p>The pre-trigger share is drawn to the left of the marker.</p>
|
|
</media>
|
|
</figure>
|
|
</section>
|
|
|
|
<section id="shapes">
|
|
<title>The four shapes</title>
|
|
<terms>
|
|
<item>
|
|
<title>Edge</title>
|
|
<p>A crossing of the level in the chosen direction, the classic behaviour.</p>
|
|
</item>
|
|
<item>
|
|
<title>Pulse width</title>
|
|
<p>A crossing and its return, qualified by how long the excursion lasted: less than,
|
|
greater than, within or outside a pair of widths; the event is timed at the closing
|
|
edge.</p>
|
|
</item>
|
|
<item>
|
|
<title>Window</title>
|
|
<p>The signal entering or leaving a band between two levels; the panel keeps the two
|
|
levels at least one increment apart, because a zero-width band is not a band: the
|
|
condition becomes an exact float-equality test against the level, which an ordinary
|
|
signal never satisfies and a signal sitting at the level satisfies on every
|
|
transition.</p>
|
|
</item>
|
|
<item>
|
|
<title>Dropout</title>
|
|
<p>The absence of a crossing for longer than a timeout; one event per outage, re-arms
|
|
when a crossing returns.</p>
|
|
</item>
|
|
</terms>
|
|
|
|
<p>The shape's own rows are the only ones shown; the rest are hidden, so the panel never
|
|
offers a pulse width to a window trigger.</p>
|
|
</section>
|
|
|
|
<section id="multiple-events">
|
|
<title>Multiple events: keeping the last few acquisitions</title>
|
|
<p><gui>multiple events</gui> decides how many of the most recent triggered acquisitions stay on
|
|
screen at once. It is <em>1</em> by default, which is the event alone — the display you get
|
|
when you ask for no persistence — and it can be raised to 8. Each older acquisition is drawn
|
|
at half the brightness of the one before it (1, 0.5, 0.25, 0.125, …), and they are all aligned
|
|
on their own trigger edge, so the pre-trigger part of the event lines up from acquisition to
|
|
acquisition and whatever changes between them — jitter, ringing, the occasional glitch — shows
|
|
as a faint ghost behind the current trace. That is what a phosphor display does with
|
|
successive sweeps.</p>
|
|
|
|
<p>The older acquisitions are drawn <em>behind</em> the current one and nothing else changes
|
|
because of them: the axis still frames the event on screen, the trigger marker still marks
|
|
<em>its</em> edge, and the measurements still describe the current frame. Lowering
|
|
<gui>multiple events</gui> back to 1 remembers nothing and frees the retained acquisitions
|
|
immediately.</p>
|
|
|
|
<p>Two things bound how many are drawn, and the panel tells you when one of them bites.</p>
|
|
<list>
|
|
<item><p><em>Room in the plot.</em> Each older acquisition is an extra trace in the row that
|
|
plots its signal, so it needs a free trace slot there. A row holding four signals — the
|
|
layout the app starts with — has room for one older acquisition of each of them; a row per
|
|
signal has room for all seven.</p></item>
|
|
<item><p><em>Memory.</em> A retained acquisition is a whole window copied out of the ring,
|
|
so persistence may hold at most as much again as the buffer (<gui>--buffer-mb</gui>) does.
|
|
On a long window at a high sample rate that bound is reached before the eighth layer.</p></item>
|
|
</list>
|
|
<section id="persistence">
|
|
<title>Persistence: how often the trace has been here</title>
|
|
<p><gui>persistence</gui> — the switch in the trigger panel's <gui>Advanced</gui> block — keeps
|
|
an <em>image</em> of the last acquisitions instead of their traces. Every acquisition is
|
|
accumulated into it, the one on screen included, so a cell's brightness means how many of them
|
|
passed through it: the sweep on screen is the brightest, the ones behind it add on top, and
|
|
where several agree the ink is brighter still. There is no stroke drawn over the image — the
|
|
acquisition on screen <em>is</em> its newest ink — so it fades with the rest in both modes. Each
|
|
signal is kept as its own image in that signal's own colour, so where two signals cross the same
|
|
place you see both, not one blended line. It is off by default.</p>
|
|
|
|
<p>Two things make it different from <gui>multiple events</gui> beside it, and the panel offers
|
|
both because they answer different questions. <em>It never runs out of room</em>: each signal's
|
|
image is the size of the plot on screen, so a display of a thousand acquisitions costs what a
|
|
display of one costs — one image per signal, whatever the plot's trace slots — and there is no
|
|
count to choose. <em>And it fades</em>, in one of two ways — <gui>fades by</gui> picks them:</p>
|
|
<list>
|
|
<item><p><gui>acquisitions</gui>: every acquisition keeps
|
|
<gui>per acquisition</gui> of what was there before it (0.5, the default, is the schedule a
|
|
phosphor's afterglow has: 1, 0.5, 0.25, …). The display then shows the last few sweeps
|
|
whatever the trigger rate.</p></item>
|
|
<item><p><gui>time</gui>: the image fades by <gui>time constant s</gui> as the display runs —
|
|
one constant is the time for it to fall to a third of its ink — so a slow trigger leaves
|
|
faint sweeps and a fast one leaves bright ones, and the picture is the same whichever the
|
|
stream is doing.</p></item>
|
|
</list>
|
|
|
|
<p>Persistence is a <em>trigger mode</em> display, like the trigger itself: it is drawn while a
|
|
captured acquisition is on screen and goes away with the trigger, on a pause, and when you open
|
|
a stored waveform. Nothing about it moves the framing — the axis is still the current event's,
|
|
the older sweeps only add ink — and it reserves no space in the plot and cannot be clicked, so
|
|
it is never in the way of a cursor or a drop.</p>
|
|
|
|
<p>Both displays live in the trigger panel's <gui>Advanced</gui> block, together with the
|
|
trigger's other settings that are set up once and left alone.</p>
|
|
</section>
|
|
|
|
|
|
<p>If a depth cannot be shown in full, a notice says how many layers fit, and the panel's
|
|
tooltip carries the same rule. Persistence is a display of what has already been captured: it
|
|
changes neither what is acquired nor what is measured, and it does nothing while the trigger
|
|
is off.</p>
|
|
</section>
|
|
|
|
<section id="cache">
|
|
<title>The event cache, replay and compare</title>
|
|
<p><em>Every triggered acquisition is kept.</em> Latches are written to the event cache
|
|
(<file>~/.cache/udpscope/events/<source>/</file>) as a <file>.npy</file> of the
|
|
event, a <file>.txt</file> of what it was, and a <file>.bmp</file> picture drawn from the
|
|
samples. The <gui>Events</gui> pane on the left — opened from the toolbar's
|
|
event-history button, which appears while recording is enabled, and collapsed until you
|
|
ask for it — lists the last 32 newest first (time, duration, signals, rate), each row with
|
|
its own picture beside the numbers.</p>
|
|
|
|
<p>Clicking a row <em>replays</em> it: the stored event is loaded exactly like an exported
|
|
file, <em>without changing the layout</em> — the rows, the colours, the window, the
|
|
cursors and the measurements stay where they are and read the stored data instead. A
|
|
replay leaves trigger mode, because a file has no edge to wait for, and the pane stays
|
|
open. Drag the pane's edge to resize it. <gui>Live</gui> goes back to the stream; the
|
|
status bar names the file until you do.</p>
|
|
|
|
<p>Select two or more events in the list and the two buttons under the header act on them:
|
|
<gui>Compare</gui> puts two events in two plots side by side, keeping the layout you have
|
|
— one plot per event, the axes synchronised, so zooming a row in one zooms the same row in
|
|
the other — and <gui>Accumulate</gui> overlays up to four of them in the same traces,
|
|
translucent, so where they agree the trace is brighter. Your own traces stay where they
|
|
are in both. They need events with the same signals and the same length. A single click
|
|
selects, a <em>double</em> click replays.</p>
|
|
|
|
<p><gui>Record events</gui>, in the trigger panel with the trigger's other options, is
|
|
what decides whether anything is kept. It is <em>off by default</em> — nothing is written
|
|
to disk until you ask — and with it off the history button goes with it.</p>
|
|
</section>
|
|
|
|
<section id="search">
|
|
<title>Search the buffer</title>
|
|
<p><gui>Search the buffer</gui>, at the foot of the trigger panel and collapsed until you open
|
|
it, answers the question the trigger answers — <em>where does this condition hold?</em> — over
|
|
the <em>whole</em> retained buffer rather than at the live edge. It runs the trigger's own
|
|
evaluator over the ring in stream order, so a <gui>hit</gui> is not a level you point at: it is
|
|
an <em>instant</em> the trigger would have fired on, timed the way an acquisition would have
|
|
timed it. A pulse-width finding, for instance, is the closing edge of a qualifying excursion,
|
|
not the excursion itself.</p>
|
|
|
|
<p>The condition is the one the rest of the panel is set to — the same signal, shape, level and
|
|
options — so there is no second condition to keep in step: change the panel and the next search
|
|
asks the new question. Nothing is searched until you ask, and the status line says
|
|
<gui>not searched</gui>.</p>
|
|
|
|
<steps>
|
|
<item>
|
|
<p>Set the condition above, then press <gui>Search</gui>. Covering the whole ring takes a
|
|
moment, and the scan runs in chunks so the stream keeps arriving while it does; the status
|
|
line counts the ground covered — <gui>scanning 1.2 s of 8.0 s, 40 found</gui>.
|
|
<gui>Stop</gui> ends a scan early and keeps the hits found so far.</p>
|
|
</item>
|
|
<item>
|
|
<p>Step through the hits with the arrows either side of the position readout
|
|
(<gui>3 of 40</gui>). The first <gui>next</gui> goes to the first hit, and the ends do not
|
|
wrap — a wrap from the last hit to the first would look exactly like the view not having
|
|
moved. Each step <em>pauses</em> on its hit, centred, exactly as the Pause button does, so
|
|
what you read is the frozen window cut around that instant; press the pause button again to
|
|
go back to the stream.</p>
|
|
</item>
|
|
<item>
|
|
<p>Every plot row marks the hits that fall in the window, up to sixteen of them. When more
|
|
are in view the pane says so and suggests zooming in — <gui>16 of 38 marks shown — zoom in
|
|
to see the rest</gui> — and when the selected hit has scrolled off the window it says that
|
|
instead. A hit the live stream has since overwritten reads <gui>no longer in the buffer</gui>
|
|
beside its position.</p>
|
|
</item>
|
|
</steps>
|
|
|
|
<p>How a scan ended is part of the answer: <gui>N found in 8.0 s</gui> when it covered the whole
|
|
ring; <gui>N found; the stream overtook the oldest samples</gui> when the producer overwrote
|
|
samples before the scan reached them, so the count is of what was left; and
|
|
<gui>N found (the limit) in the newest …</gui> when a condition that holds almost everywhere —
|
|
an edge on a noisy signal — reached the ten-thousand-hit ceiling. The last is a stop, not a
|
|
crash: a hit list nobody could navigate is not worth building.</p>
|
|
|
|
<p>A result describes the ring it was taken from, so it is <em>dropped</em> when that ring is
|
|
replaced: a new <gui>CONFIG</gui> from the source, or a change to the signal set, re-describes
|
|
the stream and clears the hits. The condition above is untouched — only the answer to it
|
|
is.</p>
|
|
</section>
|
|
|
|
<section id="knowing">
|
|
<title>Worth knowing</title>
|
|
<list>
|
|
<item><p>Arming <em>enables</em> the signal if it was off, because a trigger on a signal
|
|
nobody acquires can never fire.</p></item>
|
|
<item><p>The pre-trigger share is a share of the <em>display window</em>, not of the
|
|
ring. A 2 s window at 50% captures 1 s before the edge and 1 s after.</p></item>
|
|
<item><p>There are four display states, and the status bar names each: <gui>armed</gui>
|
|
(watching, nothing drawn yet), <gui>capturing</gui> (the edge was accepted and the post
|
|
window is filling <em>in view</em>, with the marker at x = 0), <gui>event held</gui>
|
|
(the frozen capture) and <gui>disarmed</gui>. A held capture is never quietly replaced
|
|
by live data.</p></item>
|
|
<item><p>The first edge after arming is only accepted once the history reaches back a
|
|
full pre-trigger window, so a capture may legitimately be shorter than you asked for.
|
|
The axis is pinned to what the capture actually got. <gui>Force</gui> is the one
|
|
acquisition that skips that gate — it captures the history that exists, because "now"
|
|
is the whole of what you asked for — so on a ring that has just started filling its
|
|
left side is short even though the axis still shows only what it got.</p></item>
|
|
<item><p>Disarming <em>during</em> a capture publishes what the capture got to, so the
|
|
picture on screen at that moment stays on screen. No event fired, so the event count
|
|
does not move.</p></item>
|
|
<item><p>The trigger reads the <em>stored</em> signal — decimated and averaged — not the
|
|
wire signal. A spike narrower than one decimation group is filtered away rather than
|
|
triggering on data the buffer does not contain.</p></item>
|
|
</list>
|
|
</section>
|
|
|
|
<section id="example">
|
|
<title>Example</title>
|
|
<p>A 1 Hz sine, level 0, rising, 2 s window at 50%, Single. The capture spans
|
|
<code>[-1.000 .. 1.000]</code> with <code>n=20001</code> samples at 10 kS/s — the span
|
|
times the real rate, plus one — and the marker sits at x = 0 throughout.</p>
|
|
</section>
|
|
|
|
</page>
|