Acquisition Module¶
Data acquisition functions for logging data from soundcards and National Instruments DAQ devices.
Acquisition Settings¶
MySettings is the object you pass to every acquisition call — it holds
the device, channel, sampling, trigger, voltage-range, IEPE excitation
and per-channel calibration configuration. Every constructor argument is
keyword-only with a default, and the attributes are plain and mutable.
The full per-attribute reference is below; for worked end-to-end recipes
(IEPE on a cDAQ, calibration at logging time) see the
Data Acquisition user guide.
MySettings ¶
Bases: object
A container for every acquisition setting used by a recording.
A single MySettings instance configures all acquisition entry
points — acquisition.log_data, acquisition.signal_generator,
the streams recorders and the Logger GUI. All constructor
arguments are keyword-only and have defaults, so override only the
few you need; attributes are plain and may also be set after
construction (settings.fs = 12800). See the Data Acquisition
user guide for worked end-to-end examples.
Conventions used throughout:
- Everything is in volts. Acquired data and generated output are
in volts; engineering-unit scaling is applied at display/fit time
from
channel_sensitivities, never by rescaling the stored data. - Per-channel fields take a scalar or a sequence.
iepe_excit_current_Aandchannel_sensitivitiesaccept one value (broadcast to allchannels) or a list of lengthchannels, indexed in captured-column order — on a cDAQ chassis that is slot order (seeinput_channels_spec). - The
output_*fields configure the generation/AO path and default to their input counterparts when left unset.
Attributes:
-
channels(int) –Number of input channels (default
2). On the soundcard backend this is clamped to the device'smax_input_channelsatstart_streamtime (with a printed warning) — so the default of 2 becomes 1 on a mono mic rather than failing with PortAudio-9998. The NI backend instead raisesValueErrorif the count exceeds the device's available AI channels. -
fs(int) –Input sampling frequency in Hz (default
44100). On a DSA module (NI 9234) the driver coerces this to the nearest rate on its discrete divider ladder. -
nbits(int) –Sample bit depth — 8, 16, 24 or 32 (default
16). -
chunk_size(int) –Samples acquired per channel per callback (default
100; values below 10 are raised to 10). Also the upper bound onpretrig_samples. -
num_chunks(int) –Chunks held in the oscilloscope circular buffer (default
6); recomputed fromviewed_timewhen set. -
viewed_time(float or None) –Oscilloscope display window in seconds (default
0.3). When set, overridesnum_chunksasceil(viewed_time * fs / chunk_size). Set to None to size the oscilloscope buffer directly fromnum_chunksinstead. -
stored_time(float) –Duration of the recorded capture in seconds (default
2). -
pretrig_samples(int or None) –Samples retained before the trigger, or
None(default) for untriggered recording. Must not exceedchunk_size(the pretrigger buffer holds only one chunk of pre-trigger context), and must be less thanstored_time * fs— otherwise there would be no post-trigger data left to record. -
pretrig_threshold(float) –Trigger level, as a magnitude, in the units the recorder stores (default
0.05). On NI that is volts. On a soundcard it is volts onceVmaxSCis set and full-scale units while it is left at 1.0 (uncalibrated) — the samples are scaled byVmaxSCon the way in, and the threshold is compared after that scaling. The 0.05 default was chosen as "5% of full scale" for an uncalibrated device; on a characterised interface it means 50 mV, which can sit close to the noise floor, so raise it to a sensible fraction of the expected signal. -
pretrig_channel(int) –Channel index monitored for the trigger (default
0). -
pretrig_timeout(float) –Seconds to wait for the trigger event before recording anyway (default
20). It bounds only the wait for the threshold crossing: once the crossing happens, the post-trigger data is givenstored_time + 5seconds of its own to arrive, so a capture longer than the timeout is not cut short. -
lpf_on(bool) –Digital low-pass toggle (default
False). When on,log_datacaptures ABOVEfsand resamples down behind a linear-phase anti-alias FIR (analysis.resample_to_fs— passband tofs/2.56, 96 dB stopband atfs/2).fskeeps its normal meaning (the rate you log at); the toggle changes only HOW that rate is achieved — oversample + noise-reducing decimation instead of sampling atfsdirectly. How far abovefsthe capture runs is set byoversample; on a device with a published rate ladder it is one of that device's real rates, otherwise an integer multiple offsunder the device maximum. The logged settings record the capture rate aslpf_capture_fs. NOTE the capture rate can differ fromfswith this toggle OFF too: a device that cannot run atfsat all (any sound card asked for 3 kHz) is captured at a rate it can run and resampled down regardless, because the alternative is letting the OS resample silently. -
oversample(str) –How far above
fsto capture when oversampling —'auto'(default),'lowest'or'highest'.'auto'is device-specific: a sound card (delta-sigma, already anti-aliased at its own rate) takes the lowest rate with headroom, while NI takes the highest, which is mandatory on the filterless multiplexed USB-6003/6212 and buys noise process gain on DSA modules. Override when you know better than the default — seestreams.oversample_strategy. -
capture_fs(float) –Force the rate the hardware runs at, in Hz, overriding the automatic choice (default
None= auto).fsis what you want delivered; this is what the converter actually samples at before pydvma decimates down tofs. Auto picks the lowest rate the device can genuinely run that coversfs, which is right for a sound card (delta-sigma, already anti-aliased at its own rate). Set it explicitly to capture faster — worth doing on hardware with no anti-alias filter, where a high capture rate is the only protection. Must be at leastfs. -
device_driver(str) –Input backend —
'soundcard'(default),'nidaq'or'mock'(the hardware-free test backend). -
device_index(int or None) –Index into the enumerated device list for the chosen driver;
Nonepicks a default (the system default input soundcard, or NI device 0). For a cDAQ chassis this indexes the chassis as a whole, not a module — list candidates withdvma.list_available_devices()(its nidaq section is indexed the same waydevice_indexis). -
device(str or int or None) –Name the hardware instead of numbering it (default
None). A case-insensitive substring of the device name —device='U24XL'— is resolved to whichever index that interface currently occupies, choosing the best backend available for it and filling indevice_index,device_nameanddevice_hostapitogether. On Windows that choice is material: one interface is listed once per host API and they differ in word length and in whether they will silently resample, so the resolved backend also depends onfs. The choice and its reason are printed. RaisesValueErrorlisting the candidates if the name matches no device, or more than one. An int is taken as an index. Runstreams.list_available_devicesto see what is present and what pydvma knows about each device's voltage scale. -
device_name(str or None) –Exact enumerated name that
device_indexis expected to refer to (defaultNone). Device indices are positions in an enumeration, not identities, and the enumeration reorders — so when this is set,streams.start_streamverifies the two still agree before opening, follows the name to its new index if it moved, and refuses rather than record the wrong instrument if it has gone. Left unset,streams.Recorder.init_streamrecords the resolved name after the first capture, which arms the same check for every capture after that. -
device_hostapi(str or None) –Host-API name that
device_indexwas chosen on, e.g.'Windows WDM-KS'(defaultNone, also filled in after the first capture). The other half of the identity, and the half that matters on Windows: PortAudio lists one interface once per host API with the SAME name each time, sodevice_namealone cannot tell four candidates apart and the check would give up. Ignored on platforms that list each device once. -
input_channels_spec(str or None) –Optional raw DAQmx physical-channel string for the AI task, e.g.
'cDAQ1Mod1/ai0:3,cDAQ1Mod3/ai0'. Overrides the auto-built'<dev>/ai0:N-1'string when set — use it for gappy or mixed-module layouts the count-based builder cannot express. nidaqmx backend only. -
VmaxNI(float) –Full-scale input voltage for the NI AI task (default
5); ±VmaxNI is passed as min/max toadd_ai_voltage_chan. Pick the smallest range covering the signal for best resolution. Fixed at ±5 V on the 9234 (other values are accepted but ignored by the hardware). -
input_gain_db(float) –Preamp gain currently set on the audio interface, in dB (default
None). pydvma cannot read this — it is a front-panel control no audio API exposes — so stating it here letsVmaxSCbe derived from the device's published maximum input level, and records in the saved dataset what the front panel was set to. Takes precedence over an explicitVmaxSC. Only applies to interfaces characterised inpydvma._soundcard_specs; ignored otherwise. Changing the gain on the hardware invalidates the calibration, so re-state it. A characterised FIXED-GAIN interface (e.g. the ESI U24 XL) needs no stated gain:VmaxSCis derived automatically when this isNoneandVmaxSCis left at its default. -
input_mode(str) –Which input the signal is on —
'line'(default),'inst'or'mic'. Sets the maximum input level used withinput_gain_db; on a Scarlett 2i2 these are 22, 12 and 16 dBu at minimum gain respectively. -
VmaxSC(float) –Soundcard input calibration (default
1.0) — the jack voltage corresponding to a normalised reading of 1.0. Default1.0treats normalised samples as volts at unit scale (no calibration); set it to your measured input sensitivity to calibrate captures in volts. -
NI_mode(str) –NI terminal configuration —
'DAQmx_Val_RSE'(default),'DAQmx_Val_NRSE','DAQmx_Val_Diff'or'DAQmx_Val_PseudoDiff'. DSA modules (9234) are pseudo-differential only. -
iepe_excit_current_A(float or sequence of float) –Per-channel IEPE / ICP excitation current in amps (default
0.0= off on every channel). Scalar broadcasts; a sequence must be lengthchannels. Only NI 9234-class DSA modules support it; the legal discrete values on the 9234 are0.0and0.002(2 mA), validated against the module that actually owns each channel. A channel with current> 0is switched to AC coupling and the recorder blocks ~2 s after start for the sensor bias to settle through the AC-coupling HPF. Requiresdevice_driver='nidaq'(raisesValueErrorotherwise). Never enable it on a channel wired to an AO output (e.g. a loopback) — the current drives back into the AO terminal. -
channel_sensitivities(float or sequence of float) –Per-channel sensitivity in volts per engineering unit — V/g for an accelerometer, V/N for a force transducer, V/Pa for a microphone, etc. (default
1.0= no calibration applied). Scalar broadcasts; a sequence must be lengthchannelsand every value must be non-zero.log_datastores the reciprocal asTimeData.channel_cal_factors, which plotting and modal fitting apply automatically, so a100 mV/gaccelerometer (0.1here) gives a cal factor of10and plots read ing. The storedtime_dataarray itself stays in volts. -
output_device_driver(str) –Backend for the output/AO path; defaults to
device_driver(same device as the input). -
output_device_index(int or None) –Device index for the output path.
Nonefollows the resolveddevice_indexwhen the output driver matches the input driver and the input device can play (forsoundcard, when it reports output channels — a USB audio interface drives its own outputs; a capture on it then runs as ONE full-duplex stream, seepydvma.streams.Recorder.init_stream). Otherwise:soundcardfalls back to the default output device (a microphone-only input cannot play the stimulus), andnidaq/mockto device 0 for cross-driver output. -
output_channels(int) –Number of output (AO) channels (default
1). -
output_channels_spec(str or None) –Raw DAQmx physical-channel string for the AO task, e.g.
'cDAQ1Mod2/ao0'; the output analogue ofinput_channels_spec. nidaqmx backend only. -
output_fs(int) –Output sample rate in Hz; defaults to
fs. -
output_VmaxNI(float or None) –Full-scale output voltage for the NI AO task; defaults to
VmaxNI. (The NI 9260 is limited to ±4.24 V.) -
output_VmaxSC(float or None) –Full-scale output voltage for the soundcard AO path — the jack voltage corresponding to a ±1 sounddevice sample; defaults to
VmaxSC. -
use_output_as_ch0(bool) –When
Trueand anoutputarray is passed tolog_data, the generated drive signal is prepended as channel 0 of the recorded data (defaultFalse). Useful for transfer-function tests where the excitation should be the reference channel; the prepended column passes through with a cal factor of 1. -
init_view_time(bool) –Show the time-domain oscilloscope view on launch (default
True). -
init_view_freq(bool) –Show the frequency-domain oscilloscope view on launch (default
True). -
init_view_levels(bool) –Show the channel-levels oscilloscope view on launch (default
True).
Examples:
IEPE accelerometers on a cDAQ with per-channel calibration —
100 mV/g ICP accelerometers on the 9234's ai0/ai1 and a
2.3 mV/N force probe on ai2 (channel index 3 unused):
>>> settings = dvma.MySettings(
... device_driver='nidaq',
... device_index=0, # the cDAQ chassis
... channels=3,
... NI_mode='DAQmx_Val_PseudoDiff', # required by the 9234
... VmaxNI=5, # 9234 fixed at ±5 V
... fs=12800,
... iepe_excit_current_A=[0.002, 0.002, 0.0], # 2 mA accels only
... channel_sensitivities=[0.1, 0.1, 0.0023], # V/g, V/g, V/N
... )
>>> dataset = dvma.log_data(settings)
Scalars broadcast to every channel — four identical IEPE-powered 100 mV/g accelerometers:
>>> settings = dvma.MySettings(
... device_driver='nidaq', channels=4,
... iepe_excit_current_A=0.002, channel_sensitivities=0.1,
... )
See Also
acquisition.log_data: Run a capture using these settings. list_available_devices: Print soundcard + nidaq devices by index. suggest_ni_settings: Safe NI ranges/rate/mode for a device.
Output_Signal_Settings ¶
Bases: object
Pre-set values for the Logger GUI's "Generate output" panel.
A lightweight holder for the four output-generation fields the
Logger GUI exposes. Pass an instance to
gui.Logger(..., output_signal_settings=...) to pre-fill that
panel; the GUI then feeds the chosen values to
acquisition.signal_generator when you preview or play the output.
It is only consumed by the GUI — for scripted output, call
acquisition.signal_generator / log_data(output=...) directly
(see the Data Acquisition user guide).
The signal duration is not stored here — it is a separate field
in the GUI panel (and the T= argument of signal_generator
when scripting).
Attributes:
-
type(str) –Output waveform, matching the panel's drop-down — one of
'None'(output off; the default),'sweep'(a linear chirp fromf1tof2),'gaussian'(band-limited Gaussian noise) or'uniform'(band-limited uniform noise). Maps tosignal_generator'ssig. -
amp(float) –Peak amplitude in volts (default
0). Clamped to ±settings.output_vmax()at generation time. -
f1(float) –Lower frequency in Hz (default
0). For'sweep'the start frequency; for the noise types the lower band-pass corner. Passed through asf=[f1, f2]. -
f2(float) –Upper frequency in Hz (default
0). For'sweep'the end frequency; for noise the upper band-pass corner. The GUI rejectsmax(f1, f2) > fs/2(Nyquist).
Examples:
>>> # band-limited noise, 0.1 V, 100-300 Hz, pre-loaded in the GUI
>>> oss = dvma.Output_Signal_Settings(type='gaussian',
... amp=0.1, f1=100, f2=300)
>>> logger = dvma.Logger(settings, output_signal_settings=oss)
Main Acquisition Function¶
log_data ¶
Acquire one block of time-domain data and return it as a DataSet.
Two call modes depending on settings.pretrig_samples:
- No pretrigger (
pretrig_samples is None): starts / reuses a stream, waits forsettings.stored_timeseconds, and returns the most recentstored_time * fssamples from the circular buffer. Ifoutputis supplied it is played in parallel (soundcard play is blocking; NI play is non-blocking and synchronized againststored_timevia WaitUntilTaskDone). - Pretrigger armed (
pretrig_samplesset): waits up tosettings.pretrig_timeoutseconds for the monitored channel to crosssettings.pretrig_threshold, then a furtherstored_time + 5seconds for the post-trigger half of the window to fill. The timeout therefore bounds the WAIT FOR THE EVENT only — a long capture cannot expire it. When anoutputstimulus is supplied the timeout clock starts once the stimulus is actually playing (the ~1 s settle sleep and AO task setup are not counted against it). On trigger, returns a window ofstored_time * fssamples straddling the trigger sample so thatpretrig_samplesof pre-trigger data appears at the start of the returned buffer. On timeout with no trigger the function does not raise — it falls back to returning the tail of the buffer (same as the no-pretrigger path) withtrigger_detected = False.
Parameters¶
settings : MySettings
Acquisition configuration. See pydvma.options.MySettings.
test_name : str or None
Stored on the returned TimeData for labelling.
rec : Recorder-like or None
Ignored. Retained for backward compatibility with callers (the
GUI's LogDataThread) that still pass a cached recorder.
log_data always calls streams.start_stream(settings)
itself so that switching device or backend between calls
doesn't leave a stale recorder; a running stream whose
signature matches is REUSED (soundcard and NI both), so the
call is cheap for back-to-back captures and the buffer already
holds real history — a capture never starts with the startup-
latency zeros a freshly opened stream begins with. On top of
that, the free-run dwell is topped up until the buffer really
holds stored_time * fs delivered samples
(_wait_for_buffer_fill), covering the fresh-stream case.
A capture during which the acquisition host reported dropped input
prints a loud warning and sets
:data:LAST_CAPTURE_OVERFLOWS — gaps in the data are
unrecoverable and quietly destroy TF coherence, so they must
never pass silently.
output : ndarray (N_samples, output_channels) or None
Optional playback signal in volts. For NI it's passed
through as-is (must stay within ±output_VmaxNI). For
soundcard it's divided by output_VmaxSC to recover the ±1
normalised units sounddevice expects.
cancel_event : threading.Event or None
Optional cooperative stop. When supplied, every wait in the
capture (the free-run dwell, and both phases of the armed wait)
polls it every :data:CANCEL_POLL_INTERVAL seconds; if it is
set, any playing stimulus is stopped and
:class:CaptureCancelled is raised instead of returning data.
None (the default) is the plain blocking behaviour — the
Python API is unchanged. Used by the pydvma serve bridge,
which runs this in a worker thread that cannot be killed from
outside. Same-device soundcard playback (through the capture
stream's duplex output) polls the event too and stops the
stimulus mid-play. The one wait that cannot be interrupted is
playback on a SEPARATE output device, which blocks inside
sd.OutputStream.write.
Returns¶
DataSet
A DataSet containing one TimeData in volts. If
settings.use_output_as_ch0 is True and output was
supplied, the output signal is prepended as an extra channel.
Raises¶
CaptureCancelled
If cancel_event is set before the capture finishes.
ValueError
If pretrig_samples exceeds chunk_size, or leaves no
post-trigger data (>= stored_time * fs).
Notes¶
A clipping warning is printed when |data| > 0.95 * Vmax
anywhere in the capture, where Vmax is VmaxNI on the NI
path and VmaxSC on the soundcard path. Both default to
behaviour equivalent to the old ±1-normalised check when the user
hasn't overridden them.
Pretrigger positioning (both backends, identical logic)¶
On a successful trigger, the returned buffer is
stored_time * fs samples long and the first sample exceeding
pretrig_threshold sits at exactly index pretrig_samples —
samples [0, pretrig_samples) are pre-trigger context. See
streams.Recorder for the state machine that gives this
invariant.
pretrig_samples is capped at chunk_size (validated at
call-time with a ValueError); the recorder only retains that
much pre-trigger context. Larger windows require a larger
chunk_size. It must also leave room for post-trigger data —
pretrig_samples >= stored_time * fs is rejected the same way.
The threshold is compared in the units the recorder stores, which
for a soundcard means volts once VmaxSC is set and full-scale
units while it is 1.0 (uncalibrated). Calibrating a device
therefore changes what a given threshold number means.
On a trigger timeout (pretrig_timeout elapses with nothing
above threshold), the function does not raise — it returns the
tail of the buffer (same shape as the no-pretrigger path), leaves
trigger_detected False, and prints a "not detected" message.
Capture rate vs delivered rate¶
fs is the rate the returned TimeData is at. The rate the CONVERTER
runs at can differ, and streams.select_capture_fs decides which:
- The device cannot run at
fs. Any sound card asked for 3 kHz — their ladders start at 44.1 kHz. Captured at the lowest rate it CAN run and resampled down. This happens withlpf_onoff, because the alternative is the OS resampling silently at a quality that depends on whatever rate the device was left at (measured as poor as 12 dB of alias rejection). lpf_on. Captured abovefsdeliberately, for the anti-alias chain and ~10·log10(M) dB of noise process gain. How far above issettings.oversample— seestreams.oversample_strategy.capture_fs. Forces a specific capture rate outright.
In every case the capture — pretrigger window included, whose
sample-exact alignment survives the rate change — is resampled to
fs behind a linear-phase anti-alias FIR
(analysis.resample_to_fs: passband to fs/2.56, 96 dB stopband
at fs/2, zero-phase), chunk_size and pretrig_samples are
scaled to the capture rate internally so their user-facing meaning
(at fs) is unchanged, and the returned settings record the real
capture rate as lpf_capture_fs.
The log proceeds unfiltered (with a printed note) when there is no
headroom to oversample into, or when the device refuses to OPEN a
stream at a rate its capability probe accepted (PortAudio's
check_input_settings can approve rates InputStream then
rejects, e.g. via MME under a remote-desktop session).
On a sound card, playback shares the capture clock, so a stimulus
passed as output is resampled onto the capture rate when input and
output are the same device (streams.output_shares_input_clock).
Signal Generation¶
output_signal ¶
Play output (in volts) on the configured AO device.
For soundcard, divides by output_VmaxSC to recover the ±1
normalised float sounddevice expects, then writes through
streams.setup_output_soundcard — which plays through the live
capture stream itself when input and output are the same device
(one full-duplex stream; a second stream there would silence the
capture on macOS), or a separate sd.OutputStream otherwise.
Either way the write blocks until the stimulus has been handed to
the stream. For NI, the voltage array is passed straight through
to setup_output_NI (the AO task is configured with
±output_VmaxNI rails).
cancel_event (a threading.Event or None) makes the
SAME-DEVICE soundcard wait cancellable: the duplex playback wait
polls it and stops the stimulus as soon as it is set, regardless of
whether the cancel arrives before or during playback. The
separate-device path cannot honour it mid-write (a blocking
sd.OutputStream.write is uninterruptible) and ignores it.
signal_generator ¶
Create an output-ready waveform.
amplitude is in volts — the generated signal is bounded to
±amplitude and, as a safety ceiling, clipped to
±settings.output_vmax() (i.e. output_VmaxNI on the NI path,
output_VmaxSC on the soundcard path). Returns (t, y) where
y is shape (N, output_channels) in volts, ready to hand to
log_data(..., output=y) or output_signal.
multisine_generator ¶
Create a periodic random-phase multisine buffer for a BLA capture.
One period is N = spec['n_samples'] samples exciting integer DFT
bins k1..k2 (inclusive, satisfying 1 <= k1 <= k2 <= (N-1)//2
-- violating this raises ValueError naming k1, k2 and N) with
equal amplitudes and uniform random phases drawn from
numpy.random.default_rng([seed, m]) — so a saved spec
reproduces the waveform exactly. Both the excitation index q
(0..n_exc-1) and the experiment index e (0..n_exc-1) are
zero-based; experiment e applies the orthogonal DFT-matrix
rotation (phase shift -2*pi*q*e/n_exc on excitation q),
which keeps every channel's amplitude spectrum identical across the
n_exc experiments of a realisation.
Unlike signal_generator this applies NO fade window and NO peak
rescale — both would break exact periodicity. amp_rms sets the
per-channel RMS (identical across realisations, keeping the
excitation class constant); if the resulting peak exceeds
settings.output_vmax() a ValueError is raised — lower the
level. A ValueError is also raised for a degenerate n_exc (< 1),
a degenerate period count (t_periods + p_periods < 1), an e
outside [0, n_exc), or n_exc exceeding
settings.output_channels.
Parameters:
-
settings(MySettings) –output_fs(the time axis),output_channels(checked againstn_exc) and the output voltage rail are consulted. -
spec(dict) –MultisineSpec dict with keys n_samples, k1, k2, p_periods, t_periods, seed, m, e, n_exc, amp_rms. See the web logger's Nonlin-stage guide for the design vocabulary (M realisations, P periods, excited bins k1/k2): https://torebutlin.github.io/pydvma/web-logger/nonlin/.
Returns a tuple (t, y) where y is a C-contiguous array with
shape ((t_periods + p_periods) * n_samples, n_exc) in volts,
ready for log_data(..., output=y) — C-contiguity matters because
sounddevice's OutputStream.write raises TypeError on a
Fortran-ordered buffer, which a naive tile-then-transpose produces
whenever n_exc >= 2.
Stream Monitoring¶
stream_snapshot ¶
Capture the live oscilloscope buffer as a TimeData.
Unlike log_data, which blocks for stored_time seconds and
returns a fresh capture, this is a non-blocking snapshot of the
oscilloscope-side circular buffer (osc_time_data) — i.e. the
most recent num_chunks * chunk_size samples already in memory.
Useful for "what is the stream doing right now?" diagnostics from
a notebook while a stream is running.
Parameters¶
rec : Recorder-like
Retained for backward compatibility; the actual snapshot is
always taken from the module-level streams.REC. Callers can
pass any value (typically streams.REC itself).
Returns¶
TimeData
A single TimeData instance with test_name='stream_snapshot',
carrying the oscilloscope axis and the live buffer. No
channel_cal_factors or units are attached (this is meant
as a quick-look tool, not a calibrated capture).
Notes¶
Requires a live stream: call streams.start_stream(settings)
first, or use a function like log_data that does so internally.
On the soundcard path the buffer holds voltages scaled by
settings.VmaxSC; on the NI path it holds raw volts.