Sample & Hold / Buffer / Decimate
Shippingstatefulsample_holdStateful: classic S&H latch, ring-buffer capture, or decimation
Signature
Inputs
signalSignalrequiredtriggerSignal
Outputs
outputSignalfullSignal
Parameters
| Key | Type | Default | Notes |
|---|---|---|---|
mode | enum | sample_hold | one of: sample_hold, buffer, decimate |
hold_every | int | 1 | |
trigger_edge | enum | rising | one of: rising, falling, any |
buffer_size | int | 1024 | |
decimate_n | int | 4 | |
initial_value | float | 0.0 |
Description
Sample & Hold / Buffer / Decimate is a single stateful node that captures samples from its signal input and re-emits them under one of three mode policies. In `sample_hold` mode it acts as a classic latch: on each qualifying edge of the optional trigger input it captures the current signal value and holds it constant on output until the next trigger; between triggers the output is frozen. In `buffer` mode it writes incoming samples into a ring buffer of length buffer_size, asserting the full output when the buffer wraps. In `decimate` mode it passes every decimate_n-th sample and discards the rest, reducing the effective sample rate.
The node is stateful (SHState): it retains the held value, the ring-buffer contents and write index, and the previous trigger level needed for edge detection across evaluation ticks. The trigger_edge parameter selects rising, falling, or any transitions; if no trigger is wired in sample_hold mode, the hold_every parameter provides an internal sample cadence (capture every -th sample). Before the first capture the output takes initial_value.
Sample & Hold is a value-domain operation: it never interpolates or synthesizes new numbers, so the physical unit of signal passes through unchanged and each held or forwarded sample carries its original uncertainty verbatim. Holding a value does not shrink its variance, and decimation does not average — the surviving samples keep their exact . Unlike a filter, no error is combined across samples.
Mathematics
Examples
Latch on a rising trigger edge
With mode = sample_hold and trigger_edge = rising, wire a strobe into trigger. Each low-to-high transition captures the instantaneous signal value and holds it. Between edges the output is a flat staircase:
signal: 1.2 1.7 2.3 2.9 3.1
trigger: 0 1 0 1 0 (rising at samples 1 and 3)
output: 0.0 1.7 1.7 2.9 2.9The pre-trigger samples emit initial_value (here 0.0).
Decimate a 48 kHz stream to 12 kHz
Set mode = decimate and decimate_n = 4. The node forwards every 4th sample, dropping the intermediate three, yielding a effective rate. Because no averaging occurs, any signal energy above will alias — precede with iir_filter or smoothing as an anti-alias stage if the band is not already limited.
Applications
- ADC front-end modeling: freezing an analog signal on a convert-start strobe so downstream logic sees a stable value during conversion.
- Multi-rate DSP: down-sampling a fast sensor or audio stream to a slower processing rate via `decimate` after band-limiting.
- Block/frame acquisition: filling a fixed-length `buffer` and using the `full` flag to trigger FFT, statistics, or windowed analysis on complete frames.
- Event-driven measurement: latching a meter reading at the moment an external event (trigger edge) occurs, e.g. peak-time capture in a physics experiment.
Neat
The same node covers three textbook operations — zero-order hold, framing/ring-buffering, and integer decimation — because all three are pure sample-selection policies over shared latch state; only the emit rule differs.
In `buffer` mode the `full` output is an edge flag that fires exactly when the write index wraps past `buffer_size`, letting you drive frame-synchronous processing without an external counter.
Known issues
`decimate` performs no anti-alias filtering: spectral content above half the decimated rate folds back into band. Band-limit upstream when this matters.
In `sample_hold` mode with no `trigger` wired, capture falls back to the `hold_every` cadence; if you expected edge behavior but left `trigger` unconnected, the output will instead update every $n$-th sample rather than holding indefinitely.