improving doc
This commit is contained in:
1 parent
02c53bb7a0
commit
1fc2a3afe2
11 files changed
+678
-76
No files matched your search
@@ -0,0 +1,201 @@
|
||||
# udpscope — user guide
|
||||
|
||||
A viewer for a UDPStreamer source: it connects, decodes the CONFIG, plots the signals you enable,
|
||||
and lets you freeze, measure and derive from them. This is the *user* guide; `README.md` documents
|
||||
what was built and why, and `SPECS.md` is the requirement document.
|
||||
|
||||

|
||||
|
||||
*The main window with a source streaming: the signal panel on the right, the plot in the middle, the
|
||||
status line directly under it, and the toolbar above. The window control — `2 s` — is the first thing
|
||||
on the left.*
|
||||
|
||||
## 1. Connecting
|
||||
|
||||
```sh
|
||||
udpscope # asks which source to open
|
||||
udpscope --server 10.0.0.5 --port 8000 # connect straight away
|
||||
udpscope --server 239.1.2.3 --port 8000 --multicast 239.1.2.3 --interface 10.0.0.9
|
||||
```
|
||||
|
||||
With no `--server` the app shows a chooser: the sessions it has stored, each naming its source, plus
|
||||
a form for a new host. A source opened from the list reconnects to the multicast group and interface
|
||||
it was stored with.
|
||||
|
||||
**A unicast source serves one client at a time.** A second viewer's `CONNECT` displaces the first, and
|
||||
they take turns — the status line says so when it happens. Watching one source from several instances
|
||||
needs `--multicast <group>` with `--interface <local address>`.
|
||||
|
||||
Every launch is its own process, so running two scopes side by side is fine.
|
||||
|
||||
## 2. The status line
|
||||
|
||||
Directly under the plot, it reads `● <state> · <rate> · <window>`, and the ⓘ beside it opens the
|
||||
detail: packets, frames, gaps, per-channel sample counts, the buffer's span and its decimation.
|
||||
|
||||
- **The state word is one word** from a fixed set: `live`, `paused`, `armed`, `capturing`,
|
||||
`event held`, `disarmed`. `no data` appears in the rate's place when nothing is arriving.
|
||||
- **The rate is the *stored* rate**, which is the wire rate only while the whole requested window
|
||||
fits in the buffer. A window wider than the budget allows is bought by averaging groups of samples,
|
||||
so the rate falls and the status line says so — that is the anti-alias filter doing its job.
|
||||
- **`connected, but no data is arriving`** appears after three seconds in which no frame arrived while
|
||||
connected: the usual cause is the unicast point above. It clears the moment data returns.
|
||||
- **`N reconnects`** is appended when the client has had to re-establish the session.
|
||||
|
||||
## 3. Signals
|
||||
|
||||
The signal panel lists every signal the CONFIG described, with a switch each. **Signals start
|
||||
disabled — enabling one is what starts acquiring it**, and a signal nobody enables costs nothing.
|
||||
Drag a signal from the panel onto a plot row to add a trace; drag it again to another row to plot the
|
||||
same signal twice. The colour is per *signal*, so the same signal is the same colour wherever it
|
||||
appears.
|
||||
|
||||
The panel also holds the per-signal calibration: gain and offset, applied at ingest, so the
|
||||
measurements and the export carry the same numbers the plot shows.
|
||||
|
||||
## 4. The window and navigation
|
||||
|
||||
The header's window control (`2 s`) sets the time span on screen; the popover takes a number and a
|
||||
unit, with a decade stepper either side. The trigger's event window is a share of *this* span, so a
|
||||
window change moves the trigger with it.
|
||||
|
||||
- **Wheel** zooms about the pointer; **Shift+wheel** on x only, **Ctrl+wheel** y only.
|
||||
- **Ctrl `+` / `-`** zooms x, **Alt `+` / `-`** y, about the plot centre.
|
||||
- **Drag** pans, **right-drag** too (the right button also grabs a cursor at the pointer).
|
||||
- **Ctrl+drag** frames x to a box, **Alt+drag** y.
|
||||
- **Fit to data** (menu) auto-scales both axes and frames the whole buffered range.
|
||||
|
||||
The view is bounded by the **time window**, not by the buffer: zooming out stops at the span you set,
|
||||
and panning stops where the data starts. When the buffer holds *less* than the window — right after a
|
||||
signal is enabled — the window is left empty on its left, which is what a scope that has just started
|
||||
should look like.
|
||||
|
||||
## 5. Trigger
|
||||
|
||||

|
||||
|
||||
*Single mode with a capture held: the axis is the event's own `[-pre, +post]`, the trigger marker
|
||||
sits at the edge, and the status line reads `event held`.*
|
||||
|
||||
The trigger panel has the edge, the pre/post split (as a share of the event span), Normal or Single,
|
||||
and Arm/Disarm. Selecting a signal for the trigger enables it.
|
||||
|
||||
- **While a capture fills** the plot keeps drawing live data on the event's clock, so the post side
|
||||
fills in view; the axis does not move.
|
||||
- **A held event is navigable within its own data** — zooming in works, panning stops at the capture's
|
||||
edges — and it is never quietly replaced by live data.
|
||||
- **Disarming mid-capture** publishes what the capture got and holds that, so the picture on screen
|
||||
when you disarm is the picture you keep.
|
||||
- The event window is counted in **stream seconds** end to end, so a source whose clock advances in
|
||||
jumps still gets the window it asked for.
|
||||
|
||||
## 6. Pause
|
||||
|
||||
Pause freezes the *picture*, not the acquisition: the producer keeps filling the buffer behind it, and
|
||||
the frozen view is a snapshot of the window that was on screen. Resuming shows the data that arrived
|
||||
meanwhile — there is no hole. A paused view is held like a held event, so zooming in works and panning
|
||||
does not walk it off its snapshot.
|
||||
|
||||
## 7. Cursors
|
||||
|
||||
The cursors toolbar toggle switches on two instruments per row:
|
||||
|
||||
- **vertical** — two times, shared by every row;
|
||||
- **horizontal** — two rulers per row;
|
||||
- **both** — the two together;
|
||||
- **mix** — the two times, read off each *trace* where they cross it.
|
||||
|
||||
The pane beside it reports each trace's values at the markers, and **Reset** puts them back at the
|
||||
window's edges. Values read `--` when a marker is past the newest sample and `partial` when only one
|
||||
marker is over data.
|
||||
|
||||
## 8. Measurements
|
||||
|
||||
The measurements pane computes statistics of the **visible window** of a signal: average, top,
|
||||
bottom, min, max, peak to peak, amplitude, pulse duration, period and frequency. `+` adds one, the
|
||||
row's pencil edits it, and **show on plot** draws its result as a ruler (levels) or markers (times).
|
||||
|
||||
`top` and `bottom` take a *split* as a share of the window's own range — the percentage travels
|
||||
between signals where a threshold in volts would not. `period` and `frequency` deliberately have no
|
||||
split: they count rising crossings of the mid level, one edge per cycle, and a split there is a
|
||||
setting you can only get wrong.
|
||||
|
||||
The values are refreshed on a cadence — at most every 100 ms while the window is scrolling, once when
|
||||
it stops, and once per mode change — so a live view cannot cost you frames. The pane's cost is
|
||||
reported in the exit dump with the app's self-check.
|
||||
|
||||
## 9. Math channels
|
||||
|
||||

|
||||
|
||||
*The compact node editor: each node is a box, its inputs the squares on the left edge and its output
|
||||
the square on the right. The orange dot marks the node that carries the channel's value.*
|
||||
|
||||
A math channel is derived from the others and is then an ordinary channel: enable it and it is
|
||||
acquired, plotted, measured and exported like a streamed signal, and another math channel can use it
|
||||
as a source.
|
||||
|
||||
Operations: `channel` (a source), `gain + offset`, `abs`, `sqrt`, `clamp`, `low pass`, `high pass`,
|
||||
`band pass` (biquads, corner in Hz against the stored rate), `sum`, `difference`, `product`, `ratio`.
|
||||
|
||||
- **Click** a node to select it; its parameters appear in the form beside the canvas.
|
||||
- **Click an output square, then an input square**, to wire them. An input is only offered the nodes
|
||||
above it — the graph is a list walked in order, so a cycle cannot be drawn.
|
||||
- **Drag** a box to move it. **add node**, **delete node** and **set as output** are below the form.
|
||||
- The **output is the last node** of a graph you build top to bottom, and the orange dot says which;
|
||||
*set as output* changes it. A graph whose output is the source is valid and just passes the input
|
||||
through — that is the usual reason an operation "does nothing".
|
||||
- **Save** refuses an incomplete graph and says why: an unconnected input, no output, or a source that
|
||||
is not a channel the scope is acquiring.
|
||||
|
||||
The samples are produced at ingest, once per stored slot, so the filters carry real history — a low
|
||||
pass is the filter you asked for rather than a window recomputed every frame.
|
||||
|
||||
## 10. Sessions
|
||||
|
||||
Everything above is saved per source in `~/.config/udpscope/<host>_<port>.toml`: the window, the rows
|
||||
and which signal each slot holds, the calibration, **which signals were enabled**, **the math channels
|
||||
with their graphs** and **the measurements**. Reopening the same source brings the scope back as you
|
||||
left it.
|
||||
|
||||
The file is plain TOML and safe to edit — a malformed line is skipped rather than refusing the whole
|
||||
file. Deleting it starts from the defaults.
|
||||
|
||||
## 11. Export
|
||||
|
||||
**Export visible range…** writes the plotted signals over the visible x range at the *stored* rate to
|
||||
`.npy` or `.csv`, picked by the file name's extension. The table is collected when you click, not when
|
||||
the chooser closes, so a live view cannot scroll under the dialog. The `.npy` is a 2-D array: one row
|
||||
per sample, `time`, `stream_time`, then one column per signal.
|
||||
|
||||
## 12. Keyboard
|
||||
|
||||
| key | action |
|
||||
|---|---|
|
||||
| `space` | pause / resume |
|
||||
| `a` | arm / disarm the trigger |
|
||||
| `t` | the trigger panel |
|
||||
| `l` | the layout editor |
|
||||
| `g` | go live |
|
||||
| `f` | fit to data |
|
||||
| `d` | add the first free signal to the focused row |
|
||||
| `c` | cursors on/off |
|
||||
| `m` | measurements pane |
|
||||
| `e` | export |
|
||||
| `?` | shortcuts |
|
||||
|
||||
`Ctrl+E` exports, `Ctrl+Q` quits, `Ctrl+plus`/`Ctrl+minus` zoom x and `Alt+plus`/`Alt+minus` zoom y.
|
||||
A keystroke is ignored while a text field has focus, so typing in the window control never arms the
|
||||
trigger.
|
||||
|
||||
## 13. Troubleshooting
|
||||
|
||||
| symptom | cause |
|
||||
|---|---|
|
||||
| `connected, but no data is arriving` | another client holds a unicast source — use `--multicast` |
|
||||
| the plot is empty, the status reads `no data` | nothing is enabled: enable a signal in the panel |
|
||||
| the trace is blank while the trigger is armed | `Waiting` — armed and nothing latched yet |
|
||||
| the axis has a margin at the right | a capture is filling: the post side arrives as it is acquired |
|
||||
| a math channel equals its input | its output node is the source — see §9 |
|
||||
| a very wide window shows a low rate | the ingest's anti-alias filter, not a fault |
|
||||
| a level reads `--` | the measurement is invalid in this window (e.g. a period with one edge) |
|
||||
Binary file not shown.
|
After Width: | Height: | Size: 168 KiB |
Binary file not shown.
|
After Width: | Height: | Size: 140 KiB |
Binary file not shown.
|
After Width: | Height: | Size: 148 KiB |
Reference in new issue
Block a user