Skip to main content

InstroScope

InstroScope is a hardware abstraction layer (HAL) that provides a unified interface for SCPI-based oscilloscopes. The category class defines the vendor-independent API (set_vertical_scale, fetch_waveform, measure, set_trigger_level, …). A vendor-specific driver translates those calls into vendor commands.

Supported Vendors

  • Keysight: InfiniiVision 1200 X-Series via SCPI/VISA (Keysight1200X)
  • Siglent: SDS1000X-E series via SCPI/VISA (SiglentSDS1000XE)
  • Tektronix: 2 Series MSO via SCPI/VISA (Tektronix2SeriesMSO)
If your vendor or model is not listed, see Custom Driver Development below.

Key Concepts

Driver Composition

An InstroScope is built from a concrete driver:
  • Keysight1200X owns the connection setup and vendor-specific command mapping.
  • InstroScope owns the category-level workflow: configuration tracking, acquisition control, measurements, waveform fetches, publishers, the background daemon.

Lifecycle

  1. Construct: instantiate the vendor driver and pass it to InstroScope.
  2. open(): establish the VISA connection.
  3. Configure: set vertical (per channel), horizontal, acquisition, and trigger settings.
  4. Acquire: arm a single-shot with single(), or free-run with run().
  5. Read: fetch a waveform with fetch_waveform() or take a built-in measurement with measure().
  6. close(): disconnect from hardware.

Acquisition Control vs. the Background Daemon

InstroScope has two independent start/stop concepts:
  • Acquisition control drives the instrument: run(), single(), and stop_acquisition(). These map to the front-panel Run, Single, and Stop keys. After single(), both fetch_waveform() and measure() block up to their timeout for the trigger to fire, then read. They raise TimeoutError if it does not.
  • The background daemon drives polling on the host: start() and stop() (inherited from Instrument) periodically call the methods you register and stream their results to publishers.

Configuration Tracking

InstroScope tracks vertical, horizontal, acquisition, and trigger state locally as you issue commands. Call sync_configuration() after open() (or after load_settings()) to bulk-query the instrument and overwrite the tracked state.
sync_configuration() does not bulk-query trigger source, type, level, slope, or mode. Not all scopes expose those through a simple query, so set them explicitly to populate the tracked state.

Measurements

measure(measurement_type, channel) reads a built-in measurement: VPP, VMAX, VMIN, VAVG, VRMS, FREQUENCY, PERIOD, or DUTY_CYCLE. It returns NaN when the scope has no valid result (no acquisition yet, channel off). fetch_waveform(channel) returns a Measurement whose timestamps are relative to the trigger point (negative values are pre-trigger), with voltages already scaled through the configured probe attenuation.

Creating an InstroScope Instance

Parameters

  • name: A name for this scope instance. Used as a prefix for channel names when publishing.
  • driver: A concrete ScopeDriverBase instance configured with the connection details for that model.
  • num_channels: Number of analog-input channels on the oscilloscope.
  • publishers: Optional list of publishers to attach.
  • **kwargs: Additional keyword arguments become default tags when using a publisher that supports tags (like NominalCorePublisher). Pass legacy_naming=True here to publish pre-v1.0 channel names.

Choosing a Driver

Choose the driver that matches the model, then pass it the connection settings. Use Keysight1200X, SiglentSDS1000XE, or Tektronix2SeriesMSO. Each accepts a VISA resource string or a VisaConfig. To inspect a VISA instrument’s identity before choosing a driver:

Examples

All measurement methods return Measurement objects. This is common amongst all Instrument objects.

Basic Usage

Important Note about PublishersData is published as a direct result of an instrument method being called. Calling measure() reads the value from the instrument and causes all attached publishers to publish it automatically.

Background Daemon for Continuous Monitoring

Register the measurements to poll, free-run the instrument with run(), then start() the daemon.
Scope Background DaemonInstroScope registers no default daemon functions. Register the measurements with add_background_daemon_function() before start(), or use define_background_daemon() to replace the registered set. The default polling interval is 1 second, configurable via background_interval.
See Two ways to get data for more on background fetching.

Published channels

Every call produces a channel keyed under {name}.{descriptor}, where {name} is the constructor argument and {descriptor} is the row below. Substitute {N} with the channel number and {type} with the lowercased measurement type (e.g. vpp). Pass legacy_naming=True to the constructor for the pre-v1.0 names.

Method Reference


Custom Driver Development

This section is for developers implementing InstroScope support for oscilloscopes that aren’t supported out of the box. A scope driver subclasses ScopeDriverBase and owns its transport. Its responsibilities:
  1. Expose a protocol-native constructor: accept a visa_resource string or VisaConfig.
  2. Own transport setup: create and store the transport internally. Do not require callers to pass a VisaDriver.
  3. Own lifecycle: implement open() and close().
  4. Map commands: translate each abstract method into vendor commands.
  5. Parse responses: convert responses to the expected types (float, enums, WaveformData).
  6. Drain the error queue: implement check_errors(). InstroScope calls it between setup commands and blocking queries, so a pending syntax error raises instead of hanging a data query.
Channels are 1-indexed analog input numbers throughout.

ScopeDriverBase Interface

All scope drivers subclass ScopeDriverBase and implement these abstract methods:
setup_measurement(measurement_type, channel) is an optional override (default no-op). Implement it for instruments that compute measurements during acquisition (e.g. Tektronix), where the measurement slot must exist at trigger time. Raise NotImplementedError for AcquisitionMode values the scope does not support (e.g. the Keysight 1200X has no ENVELOPE mode). See Exceptions for unsupported-feature handling. For VISA-backed drivers, create a VisaDriver internally and use self._visa.write(command) and self._visa.query(command) for all I/O. VisaDriver owns the resource lock and serializes concurrent calls. See the VisaDriver guide for the full transport reference.

Implementation Example: Keysight 1200 X-Series Driver

Vendor SCPI VariationsScope vendors differ in SCPI command sets, error-query forms, and waveform-preamble formats. The Keysight 1200X computes measurements on demand, while the Tektronix 2 Series requires measurement slots installed before the trigger fires (setup_measurement). Always consult your oscilloscope’s programming manual.

Using a Custom Driver

Construct InstroScope with your own driver instance: