Skip to content

Scope (Oscilloscope)¤

Errors raised by these methods are documented in Exceptions.

Interface¤

Bases: Instrument

Oscilloscope instrument. Tracks scope state locally; call sync_configuration() after open() to refresh.

Provide either config or driver/num_channels together, not both.

Parameters:

  • name ¤

    (str | None, default: None ) –

    Channel-name prefix for published data. Falls back to config.device.name when config is given.

  • driver ¤

    (ScopeDriverBase | None, default: None ) –

    Concrete scope driver; owns its own transport::

    scope = InstroScope( "scope", driver=Keysight1200X(""), num_channels=4, )

  • num_channels ¤

    (int | None, default: None ) –

    Analog-input channel count.

  • publishers ¤

    (list[Publisher] | None, default: None ) –

    Publishers that receive emitted Measurement/Command data. Combined with any publishers declared in config.

  • config ¤

    (ScopeConfig | dict | Path | str | None, default: None ) –

    A ScopeConfig, a dict, or a path to a JSON config file. Its channels, acquisition, and trigger blocks are applied through the public setters on open(); each channel's measurements are registered as background daemon functions.

  • autostart ¤

    (bool, default: False ) –

    When True, open the connection and start background polling. Requires config with at least one measurements entry, since the daemon has nothing to poll otherwise.

  • **kwargs ¤

    –

    Default tags applied to every emitted Measurement/Command. Pass dataset_rid="<rid>" to auto-create a NominalCorePublisher (uses the on-disk 'default' Nominal credential).

name instance-attribute ¤

name = name

legacy_naming instance-attribute ¤

legacy_naming = legacy_naming

publishers instance-attribute ¤

publishers = publishers or []

default_tags instance-attribute ¤

default_tags: dict[str, str] = {}

channel_names property ¤

channel_names: tuple[str, ...]

Return an insertion-ordered snapshot of all published channel names.

Names are complete after one full daemon iteration: {name}.loop_time publishes every iteration, so call get_channel("loop_time", wait_for_new_samples=True) then read channel_names to ensure the complete set has arrived.

Raises:

  • RuntimeError –

    No background buffer; start() was not called.

background_interval instance-attribute ¤

background_interval = poll_interval

add_publisher ¤

add_publisher(publisher: Publisher)

Register a publisher to receive this instrument's Measurement/Command data.

publish ¤

publish(data: Measurement | Command, **kwargs)

Fan data out to every configured publisher; kwargs pass through.

add_background_daemon_function ¤

add_background_daemon_function(method: Callable, *args, **kwargs)

Append method to the daemon's call list. Use define_background_daemon to replace instead.

stop ¤

stop()

Signal the background daemon to stop and join it. No-op if not running.

get_channel ¤

get_channel(
    channel_name: str,
    length: int = 1,
    wait_for_new_samples: bool = False,
    timeout: float = 10.0,
) -> Measurement

Return the most recent length samples for channel_name from the in-memory buffer.

If the channel does not exist yet, or no sample is available, the code will always block until timeout expires.

Parameters:

  • channel_name ¤

    (str) –

    Name of the channel to retrieve.

  • length ¤

    (int, default: 1 ) –

    Number of trailing samples to return.

  • wait_for_new_samples ¤

    (bool, default: False ) –

    Block until at least length new values arrive.

  • timeout ¤

    (float, default: 10.0 ) –

    Seconds to wait when insufficient data exists or wait_for_new_samples=True.

Raises:

  • RuntimeError –

    No background buffer; start() was not called.

  • ChannelNotFoundError –

    channel had no values and no data appeared before timeout. wait_for_new_samples=True and channel did not appear within timeout.

  • ChannelValueTimeoutError –

    wait_for_new_samples=True and values did not arrive within timeout.

get_single_channel_value ¤

get_single_channel_value(channel_name: str) -> float | str | None

Return the most recent sample for channel_name from the in-memory buffer.

This will not wait, if data is not available then None is returned.

Parameters:

  • channel_name ¤

    (str) –

    Name of the channel to retrieve.

Raises:

  • RuntimeError –

    No background buffer; start() was not called.

define_background_daemon ¤

define_background_daemon(method: Callable, *args, **kwargs)

Replace all daemon functions with a single method (called with the given args).

open ¤

open() -> None

Open the underlying driver and apply any configured initial state.

start ¤

start() -> None

Start the background daemon; warns when nothing is registered to poll.

close ¤

close() -> None

Stop the daemon and publishers, then close the underlying driver.

sync_configuration ¤

sync_configuration() -> ScopeState

Bulk-query the instrument and overwrite the tracked ScopeState with live state.

Note that trigger source/type/level/slope/mode aren't bulk-queried — not all scopes expose every trigger field, so call the per-field getters where supported.

set_vertical_scale ¤

set_vertical_scale(
    volts_per_div: float, channel: int, **kwargs
) -> Command

Set the vertical scale (V/div) on channel.

get_vertical_scale ¤

get_vertical_scale(channel: int, **kwargs) -> Measurement | None

Query the vertical scale (V/div) on channel.

set_vertical_offset ¤

set_vertical_offset(offset: float, channel: int, **kwargs) -> Command

Set the vertical offset (volts) on channel.

get_vertical_offset ¤

get_vertical_offset(channel: int, **kwargs) -> Measurement | None

Query the vertical offset (volts) on channel.

set_coupling ¤

set_coupling(coupling: Coupling, channel: int, **kwargs) -> Command

Set AC/DC input coupling on channel.

get_coupling ¤

get_coupling(channel: int, **kwargs) -> Measurement

Query the input coupling mode on channel (published as a string).

set_probe_attenuation ¤

set_probe_attenuation(factor: float, channel: int, **kwargs) -> Command

Set the probe attenuation ratio (e.g. 1, 10, 100) on channel.

get_probe_attenuation ¤

get_probe_attenuation(channel: int, **kwargs) -> Measurement | None

Query the probe attenuation ratio on channel.

set_horizontal_scale ¤

set_horizontal_scale(seconds_per_div: float, **kwargs) -> Command

Set the timebase (seconds/div).

get_horizontal_scale ¤

get_horizontal_scale(**kwargs) -> Measurement | None

Query the timebase (seconds/div).

get_sample_rate ¤

get_sample_rate(**kwargs) -> Measurement | None

Query the current sample rate (Sa/s).

set_acquisition_mode ¤

set_acquisition_mode(mode: AcquisitionMode, **kwargs) -> Command

Set the acquisition mode (NORMAL/AVERAGE/HIRES/PEAK_DETECT/ENVELOPE).

get_acquisition_mode ¤

get_acquisition_mode(**kwargs) -> Measurement

Query the current acquisition mode (published as a string).

set_average_count ¤

set_average_count(count: int, **kwargs) -> Command

Set the average count (waveforms averaged) used in AVERAGE acquisition mode.

get_average_count ¤

get_average_count(**kwargs) -> Measurement | None

Query the average count.

run ¤

run(**kwargs) -> Command

Start continuous acquisition.

stop_acquisition ¤

stop_acquisition(**kwargs) -> Command

Stop acquisition; records the acquisition timestamp if one was armed.

single ¤

single(**kwargs) -> Command

Arm a single-shot acquisition.

get_acquisition_state ¤

get_acquisition_state(**kwargs) -> Measurement

Query RUNNING/STOPPED. If STOPPED while armed, records the acquisition timestamp.

fetch_waveform ¤

fetch_waveform(
    channel: int, timeout: float = 5.0, **kwargs
) -> Measurement

Fetch the acquired waveform from channel.

Timestamps are ns relative to the trigger point (negative = pre-trigger). If an acquisition is armed, blocks up to timeout seconds for it to complete; raises TimeoutError if it doesn't.

measure ¤

measure(
    measurement_type: ScopeMeasurementType,
    channel: int = 1,
    timeout: float = 5.0,
    **kwargs,
) -> Measurement | None

Take a built-in measurement on channel.

Timestamps default to the last recorded acquisition time (falls back to time.time_ns() if none). If an acquisition is armed, blocks up to timeout seconds for it to complete; raises TimeoutError if it doesn't.

set_trigger_source ¤

set_trigger_source(channel: int, **kwargs) -> Command

Set the trigger source to channel.

set_trigger_type ¤

set_trigger_type(trigger_type: TriggerType, **kwargs) -> Command

Set the trigger type (EDGE, PULSE, …).

set_trigger_level ¤

set_trigger_level(level: float, **kwargs) -> Command

Set the trigger level (volts).

set_trigger_slope ¤

set_trigger_slope(slope: TriggerSlope, **kwargs) -> Command

Set the trigger edge slope (RISING/FALLING/EITHER).

set_trigger_mode ¤

set_trigger_mode(mode: TriggerMode, **kwargs) -> Command

Set the trigger mode (AUTO/NORMAL).

force_trigger ¤

force_trigger(**kwargs) -> Command

Force a trigger event immediately.

get_trigger_status ¤

get_trigger_status(**kwargs) -> Measurement

Query the trigger status (published as a string).

save_screenshot ¤

save_screenshot(
    filepath: str, to_instrument: bool = False, **kwargs
) -> Command

Capture a screenshot and save it. to_instrument=True writes to the scope's filesystem; otherwise to the host.

save_settings ¤

save_settings(
    name: str, to_instrument: bool = False, **kwargs
) -> Command

Save scope setup. to_instrument=True writes to the scope's filesystem; otherwise to the host.

load_settings ¤

load_settings(
    name: str, from_instrument: bool = False, **kwargs
) -> Command

Recall a scope setup. from_instrument=True reads from the scope's filesystem; otherwise from the host.

Invalidates the tracked ScopeState since instrument state changed externally; call sync_configuration() to refresh.

Types & Configuration¤

Oscilloscope shared types: coupling, acquisition/trigger modes, waveform data, tracked state.

Coupling ¤

Bases: Enum

Input coupling mode for an oscilloscope channel.

AC class-attribute instance-attribute ¤

AC = 'AC'

DC class-attribute instance-attribute ¤

DC = 'DC'

AcquisitionMode ¤

Bases: Enum

Oscilloscope acquisition mode.

NORMAL class-attribute instance-attribute ¤

NORMAL = 'NORMAL'

AVERAGE class-attribute instance-attribute ¤

AVERAGE = 'AVERAGE'

HIGH_RESOLUTION class-attribute instance-attribute ¤

HIGH_RESOLUTION = 'HIGH_RESOLUTION'

PEAK_DETECT class-attribute instance-attribute ¤

PEAK_DETECT = 'PEAK_DETECT'

ENVELOPE class-attribute instance-attribute ¤

ENVELOPE = 'ENVELOPE'

TriggerType ¤

Bases: Enum

Oscilloscope trigger type.

EDGE class-attribute instance-attribute ¤

EDGE = 'EDGE'

PULSE class-attribute instance-attribute ¤

PULSE = 'PULSE'

TriggerSlope ¤

Bases: Enum

Trigger edge slope.

RISING class-attribute instance-attribute ¤

RISING = 'RISING'

FALLING class-attribute instance-attribute ¤

FALLING = 'FALLING'

EITHER class-attribute instance-attribute ¤

EITHER = 'EITHER'

TriggerMode ¤

Bases: Enum

Trigger mode controlling how the oscilloscope waits for a trigger.

AUTO class-attribute instance-attribute ¤

AUTO = 'AUTO'

NORMAL class-attribute instance-attribute ¤

NORMAL = 'NORMAL'

TriggerStatus ¤

Bases: Enum

Read-back trigger status.

ARMED class-attribute instance-attribute ¤

ARMED = 'ARMED'

READY class-attribute instance-attribute ¤

READY = 'READY'

TRIGGERED class-attribute instance-attribute ¤

TRIGGERED = 'TRIGGERED'

AUTO class-attribute instance-attribute ¤

AUTO = 'AUTO'

SAVE class-attribute instance-attribute ¤

SAVE = 'SAVE'

SCAN class-attribute instance-attribute ¤

SCAN = 'SCAN'

AcquisitionState ¤

Bases: Enum

Oscilloscope acquisition run state.

RUNNING class-attribute instance-attribute ¤

RUNNING = 'RUNNING'

STOPPED class-attribute instance-attribute ¤

STOPPED = 'STOPPED'

ScopeMeasurementType ¤

Bases: Enum

Built-in oscilloscope measurement types.

VPP class-attribute instance-attribute ¤

VPP = 'VPP'

VMAX class-attribute instance-attribute ¤

VMAX = 'VMAX'

VMIN class-attribute instance-attribute ¤

VMIN = 'VMIN'

VAVG class-attribute instance-attribute ¤

VAVG = 'VAVG'

VRMS class-attribute instance-attribute ¤

VRMS = 'VRMS'

FREQUENCY class-attribute instance-attribute ¤

FREQUENCY = 'FREQUENCY'

PERIOD class-attribute instance-attribute ¤

PERIOD = 'PERIOD'

DUTY_CYCLE class-attribute instance-attribute ¤

DUTY_CYCLE = 'DUTY_CYCLE'

WaveformData dataclass ¤

WaveformData(times: list[int], voltages: list[float])

Raw waveform from a fetch: times in ns relative to the trigger; voltages after probe attenuation.

times instance-attribute ¤

times: list[int]

voltages instance-attribute ¤

voltages: list[float]

ChannelState dataclass ¤

ChannelState(
    vertical_scale: float | None = None,
    vertical_offset: float | None = None,
    coupling: Coupling | None = None,
    probe_attenuation: float | None = None,
)

Tracked per-channel state. Fields start as None and populate on set/query.

vertical_scale class-attribute instance-attribute ¤

vertical_scale: float | None = None

vertical_offset class-attribute instance-attribute ¤

vertical_offset: float | None = None

coupling class-attribute instance-attribute ¤

coupling: Coupling | None = None

probe_attenuation class-attribute instance-attribute ¤

probe_attenuation: float | None = None

TriggerState dataclass ¤

TriggerState(
    source: int | None = None,
    type: TriggerType | None = None,
    level: float | None = None,
    slope: TriggerSlope | None = None,
    mode: TriggerMode | None = None,
)

Tracked trigger state (source channel, type, level (V), slope, mode). Fields start as None.

source class-attribute instance-attribute ¤

source: int | None = None

type class-attribute instance-attribute ¤

type: TriggerType | None = None

level class-attribute instance-attribute ¤

level: float | None = None

slope class-attribute instance-attribute ¤

slope: TriggerSlope | None = None

mode class-attribute instance-attribute ¤

mode: TriggerMode | None = None

ScopeState dataclass ¤

ScopeState(
    channels: dict[int, ChannelState] = dict(),
    trigger: TriggerState = TriggerState(),
    acquisition_mode: AcquisitionMode | None = None,
    average_count: int | None = None,
    horizontal_scale: float | None = None,
)

Tracked scope state: per-channel (1-based), trigger, acquisition mode, average count, timebase.

channels class-attribute instance-attribute ¤

channels: dict[int, ChannelState] = field(default_factory=dict)

trigger class-attribute instance-attribute ¤

trigger: TriggerState = field(default_factory=TriggerState)

acquisition_mode class-attribute instance-attribute ¤

acquisition_mode: AcquisitionMode | None = None

average_count class-attribute instance-attribute ¤

average_count: int | None = None

horizontal_scale class-attribute instance-attribute ¤

horizontal_scale: float | None = None

Pydantic config models for JSON config-driven InstroScope construction.

SCOPE_VENDOR_REGISTRY module-attribute ¤

SCOPE_VENDOR_REGISTRY: dict[str, str] = {
    "Keysight1200X": "instro.scope.drivers.keysight_1200x.Keysight1200X",
    "SiglentSDS1000XE": "instro.scope.drivers.siglent_sds1000x_e.SiglentSDS1000XE",
    "Tektronix2SeriesMSO": "instro.scope.drivers.tektronix_2series.Tektronix2SeriesMSO",
}

FilePublisherConfig ¤

Bases: BaseModel

Publisher config for writing measurements to a local file.

model_config class-attribute instance-attribute ¤

model_config = ConfigDict(extra='forbid')

type class-attribute instance-attribute ¤

type: Literal['FilePublisher'] = 'FilePublisher'

directory class-attribute instance-attribute ¤

directory: str = Field(
    description="Output directory for the written file."
)

format class-attribute instance-attribute ¤

format: Literal['json', 'jsonl', 'csv', 'avro'] = 'avro'

custom_file_name class-attribute instance-attribute ¤

custom_file_name: str | None = Field(
    default=None, description="Filename without extension."
)

NominalCorePublisherConfig ¤

Bases: BaseModel

Publisher config for streaming to a Nominal Core dataset.

model_config class-attribute instance-attribute ¤

model_config = ConfigDict(extra='forbid')

type class-attribute instance-attribute ¤

type: Literal['NominalCorePublisher'] = 'NominalCorePublisher'

dataset_rid class-attribute instance-attribute ¤

dataset_rid: str = Field(description="Target Nominal Core dataset RID.")

batch_size class-attribute instance-attribute ¤

batch_size: int | None = Field(
    default=None, description="Publish batch size override."
)

profile class-attribute instance-attribute ¤

profile: str | None = Field(
    default=None,
    description="On-disk Nominal credential profile name; defaults to 'default'.",
)

TimingConfig ¤

Bases: BaseModel

Timing configuration for instrument background polling.

model_config class-attribute instance-attribute ¤

model_config = ConfigDict(extra='forbid')

poll_interval class-attribute instance-attribute ¤

poll_interval: float = Field(
    ge=0.01, description="Polling interval in seconds"
)

DeviceInfo ¤

Bases: BaseModel

Device metadata. name is the channel-name prefix on publish (e.g. my_device.temperature).

model_config class-attribute instance-attribute ¤

model_config = ConfigDict(extra='forbid')

name instance-attribute ¤

name: str

description class-attribute instance-attribute ¤

description: str = ''

manufacturer class-attribute instance-attribute ¤

manufacturer: str = ''

model class-attribute instance-attribute ¤

model: str = ''

ChannelConfig ¤

Bases: BaseModel

Initial per-channel state and polled measurements, applied through the InstroScope setters on open().

model_config class-attribute instance-attribute ¤

model_config = ConfigDict(extra='forbid')

vertical_scale class-attribute instance-attribute ¤

vertical_scale: float | None = Field(
    default=None, gt=0, description="Vertical scale in V/div."
)

vertical_offset class-attribute instance-attribute ¤

vertical_offset: float | None = Field(
    default=None, description="Vertical offset in volts."
)

coupling class-attribute instance-attribute ¤

coupling: Coupling | None = Field(
    default=None, description="Input coupling, 'AC' or 'DC'."
)

probe_attenuation class-attribute instance-attribute ¤

probe_attenuation: float | None = Field(
    default=None,
    gt=0,
    description="Probe attenuation ratio, e.g. 1, 10, 100.",
)

measurements class-attribute instance-attribute ¤

measurements: list[ScopeMeasurementType] = Field(
    default_factory=list,
    description="Built-in measurements to background-poll on this channel.",
)

AcquisitionConfig ¤

Bases: BaseModel

Initial acquisition state, applied through the InstroScope setters on open().

model_config class-attribute instance-attribute ¤

model_config = ConfigDict(extra='forbid')

mode class-attribute instance-attribute ¤

mode: AcquisitionMode | None = Field(
    default=None,
    description="Acquisition mode, e.g. 'NORMAL' or 'AVERAGE'.",
)

average_count class-attribute instance-attribute ¤

average_count: int | None = Field(
    default=None,
    ge=2,
    description="Waveforms to average; requires mode 'AVERAGE'.",
)

horizontal_scale class-attribute instance-attribute ¤

horizontal_scale: float | None = Field(
    default=None, gt=0, description="Timebase in s/div."
)

start_acquisition_on_open class-attribute instance-attribute ¤

start_acquisition_on_open: bool = Field(
    default=False,
    description="Start continuous acquisition (``run()``) as the last step of ``open()``.",
)

TriggerConfig ¤

Bases: BaseModel

Initial trigger state, applied through the InstroScope setters on open().

model_config class-attribute instance-attribute ¤

model_config = ConfigDict(extra='forbid')

source class-attribute instance-attribute ¤

source: int = Field(
    ge=1,
    description="1-based analog channel used as the trigger source.",
)

type class-attribute instance-attribute ¤

type: TriggerType | None = Field(
    default=None, description="Trigger type, 'EDGE' or 'PULSE'."
)

level class-attribute instance-attribute ¤

level: float | None = Field(
    default=None, description="Trigger level in volts."
)

slope class-attribute instance-attribute ¤

slope: TriggerSlope | None = Field(
    default=None,
    description="Trigger slope, 'RISING', 'FALLING', or 'EITHER'.",
)

mode class-attribute instance-attribute ¤

mode: TriggerMode | None = Field(
    default=None, description="Trigger sweep mode, 'AUTO' or 'NORMAL'."
)

VisaDriverConfig ¤

Bases: BaseModel

Driver config for a VISA-connected scope.

model_config class-attribute instance-attribute ¤

model_config = ConfigDict(extra='forbid')

connection_type class-attribute instance-attribute ¤

connection_type: Literal['visa'] = 'visa'

name class-attribute instance-attribute ¤

name: str = Field(description='Scope vendor/model key.')

num_channels class-attribute instance-attribute ¤

num_channels: int = Field(
    ge=1, description="Number of analog-input channels."
)

visa instance-attribute ¤

visa: VisaConfig

name_must_be_registered classmethod ¤

name_must_be_registered(v: str) -> str

ScopeConfig ¤

Bases: BaseModel

Validated config for constructing an InstroScope from JSON.

model_config class-attribute instance-attribute ¤

model_config = ConfigDict(extra='forbid')

version class-attribute instance-attribute ¤

version: Literal[1] = 1

instrument class-attribute instance-attribute ¤

instrument: Literal['InstroScope'] = 'InstroScope'

device instance-attribute ¤

device: DeviceInfo

driver instance-attribute ¤

channels class-attribute instance-attribute ¤

channels: dict[int, ChannelConfig] = Field(
    default_factory=dict,
    description="Per-channel initial state keyed by 1-based channel number.",
)

acquisition class-attribute instance-attribute ¤

acquisition: AcquisitionConfig | None = None

trigger class-attribute instance-attribute ¤

trigger: TriggerConfig | None = None

timing class-attribute instance-attribute ¤

timing: TimingConfig | None = None

publishers class-attribute instance-attribute ¤

publishers: list[PublisherConfigType] = Field(default_factory=list)

resolve_scope_from_config ¤

resolve_scope_from_config(
    config: ScopeConfig,
) -> tuple[str, ScopeDriverBase, int, list[Publisher], float | None]

Resolve a validated ScopeConfig into the (name, driver, num_channels, config_publishers, poll_interval) InstroScope needs.

Driver Interface¤

Bases: ABC

Vendor scope driver contract. Concrete drivers compose a transport (typically VisaDriver).

Channels are 1-indexed analog input numbers throughout — the wrapper instrument (InstroScope) is responsible for range-checking against the declared num_channels.

open abstractmethod ¤

open() -> None

Open the underlying transport. Idempotent.

Concrete drivers also perform any one-shot instrument setup here (e.g. *CLS, remote-mode handshake).

close abstractmethod ¤

close() -> None

Close the underlying transport. Idempotent.

check_errors abstractmethod ¤

check_errors() -> None

Drain the vendor's error queue; raise RuntimeError if any error is pending.

Used between setup commands and any blocking query — calling a data query while the scope's error queue holds a syntax error would hang.

set_vertical_scale abstractmethod ¤

set_vertical_scale(volts_per_div: float, channel: int) -> None

Set channel's vertical scale to volts_per_div (V/div).

Drivers may snap to the nearest hardware-supported step. Callers that need the actual applied value should get_vertical_scale() afterward.

get_vertical_scale abstractmethod ¤

get_vertical_scale(channel: int) -> float

Read back channel's vertical scale (V/div).

set_vertical_offset abstractmethod ¤

set_vertical_offset(offset: float, channel: int) -> None

Set channel's vertical offset to offset (volts).

get_vertical_offset abstractmethod ¤

get_vertical_offset(channel: int) -> float

Read back channel's vertical offset (volts).

set_coupling abstractmethod ¤

set_coupling(coupling: Coupling, channel: int) -> None

Set AC/DC input coupling on channel.

get_coupling abstractmethod ¤

get_coupling(channel: int) -> Coupling

Read back input coupling on channel.

set_probe_attenuation abstractmethod ¤

set_probe_attenuation(factor: float, channel: int) -> None

Set channel's probe attenuation ratio (e.g. 1, 10, 100, 1000).

get_probe_attenuation abstractmethod ¤

get_probe_attenuation(channel: int) -> float

Read back channel's probe attenuation ratio.

set_horizontal_scale abstractmethod ¤

set_horizontal_scale(seconds_per_div: float) -> None

Set the timebase to seconds_per_div. Applies globally to all channels.

get_horizontal_scale abstractmethod ¤

get_horizontal_scale() -> float

Read back the timebase (seconds/div).

get_sample_rate abstractmethod ¤

get_sample_rate() -> float

Read back the current sample rate (samples per second).

This is the effective hardware rate the scope is acquiring at; it depends on the timebase, memory depth, and interpolation settings.

set_acquisition_mode abstractmethod ¤

set_acquisition_mode(mode: AcquisitionMode) -> None

Set the acquisition mode.

Drivers should raise NotImplementedError for AcquisitionMode values their scope doesn't support (e.g. Keysight 1200X has no ENVELOPE mode).

get_acquisition_mode abstractmethod ¤

get_acquisition_mode() -> AcquisitionMode

Read back the current acquisition mode.

set_average_count abstractmethod ¤

set_average_count(count: int) -> None

Set the number of waveforms to average. Only takes effect in AcquisitionMode.AVERAGE.

get_average_count abstractmethod ¤

get_average_count() -> int

Read back the waveforms-to-average count.

run abstractmethod ¤

run() -> None

Start continuous (free-running) acquisition.

stop abstractmethod ¤

stop() -> None

Stop acquisition. Leaves the captured data intact for fetch_waveform / measure.

single abstractmethod ¤

single() -> None

Arm a single-shot acquisition.

Non-blocking — use get_acquisition_state to poll for STOPPED, or prefer digitize() which combines arming and waiting.

digitize abstractmethod ¤

digitize(timeout: float) -> None

Arm a single acquisition and block until the trigger fires and the capture completes.

Acquisition is global — all enabled channels capture simultaneously. On success the scope is left stopped with valid data ready for readout.

Parameters:

  • timeout ¤

    (float) –

    Maximum seconds to wait for the trigger to fire.

Raises:

  • TimeoutError –

    Trigger did not fire within timeout. The driver clears any pending operation so the session stays usable.

get_acquisition_state abstractmethod ¤

get_acquisition_state() -> AcquisitionState

Read back the acquisition run state (RUNNING / STOPPED).

fetch_waveform abstractmethod ¤

fetch_waveform(channel: int) -> WaveformData

Fetch the most recently acquired waveform from channel.

Returns:

  • WaveformData –

    WaveformData with times in nanoseconds relative to the

  • WaveformData –

    trigger point (negative = pre-trigger) and voltages already

  • WaveformData –

    scaled through the configured probe attenuation.

setup_measurement ¤

setup_measurement(
    measurement_type: ScopeMeasurementType, channel: int
) -> None

Ensure a measurement slot exists for measurement_type/channel before the scope triggers.

Required for instruments (e.g. Tektronix) that compute measurements during acquisition — the slot must be present at trigger time or the first measure() returns stale/invalid data. Default is a no-op for instruments (e.g. Keysight 1200X) that compute on demand.

measure abstractmethod ¤

measure(measurement_type: ScopeMeasurementType, channel: int) -> float

Read a built-in measurement (VPP, VMAX, VMIN, VAVG, VRMS, …) on channel.

Returns math.nan when the scope reports its invalid-measurement sentinel (no valid acquisition yet, channel off, etc.).

set_trigger_source abstractmethod ¤

set_trigger_source(channel: int) -> None

Set the trigger source to analog channel.

Drivers typically cache this value because the trigger-level SCPI on some scopes requires the source channel in the same command.

set_trigger_type abstractmethod ¤

set_trigger_type(trigger_type: TriggerType) -> None

Set the trigger type (EDGE, PULSE, …).

set_trigger_level abstractmethod ¤

set_trigger_level(level: float) -> None

Set the trigger threshold to level (volts). Applies to the configured trigger source.

set_trigger_slope abstractmethod ¤

set_trigger_slope(slope: TriggerSlope) -> None

Set the trigger edge slope (RISING / FALLING / EITHER).

set_trigger_mode abstractmethod ¤

set_trigger_mode(mode: TriggerMode) -> None

Set the trigger sweep mode (AUTO / NORMAL).

AUTO forces an acquisition if no trigger fires within the timeout; NORMAL waits indefinitely for a real trigger.

force_trigger abstractmethod ¤

force_trigger() -> None

Force a trigger event immediately, regardless of the configured conditions.

get_trigger_status abstractmethod ¤

get_trigger_status() -> TriggerStatus

Read back the trigger status (ARMED / READY / TRIGGERED / …).

save_screenshot abstractmethod ¤

save_screenshot(filepath: str, to_instrument: bool = False) -> bytes

Capture a screenshot.

Parameters:

  • filepath ¤

    (str) –

    Output path. When to_instrument=False this is a host path; when True it is a path on the scope's filesystem (USB stick, internal storage).

  • to_instrument ¤

    (bool, default: False ) –

    When True, the scope writes the file itself and this returns b"". When False, the image is transferred to the host, written to filepath, and the raw bytes are returned for in-memory use.

save_settings abstractmethod ¤

save_settings(name: str, to_instrument: bool = False) -> bytes

Save the current scope setup. Path semantics mirror :meth:save_screenshot.

load_settings abstractmethod ¤

load_settings(name: str, from_instrument: bool = False) -> None

Recall a scope setup from name.

With from_instrument=True the scope reads from its own filesystem; otherwise the host reads name and pushes the bytes to the scope. After loading, the calling InstroScope should invalidate its tracked ScopeState and resync if a fresh view is needed.

Vendor Drivers¤

Keysight 1200X¤

Keysight InfiniiVision 1200 X-Series oscilloscope driver (EDUX1052G and family).

Keysight1200X ¤

Keysight1200X(visa_resource: str | VisaConfig)

Bases: ScopeDriverBase

SCPI driver for Keysight InfiniiVision 1200 X-Series oscilloscopes.

open ¤
open() -> None
close ¤
close() -> None
check_errors ¤
check_errors() -> None

Query :SYSTem:ERRor? once and raise on a non-zero code. Does not drain the queue.

set_vertical_scale ¤
set_vertical_scale(volts_per_div: float, channel: int) -> None
get_vertical_scale ¤
get_vertical_scale(channel: int) -> float
set_vertical_offset ¤
set_vertical_offset(offset: float, channel: int) -> None
get_vertical_offset ¤
get_vertical_offset(channel: int) -> float
set_coupling ¤
set_coupling(coupling: Coupling, channel: int) -> None
get_coupling ¤
get_coupling(channel: int) -> Coupling
set_probe_attenuation ¤
set_probe_attenuation(factor: float, channel: int) -> None
get_probe_attenuation ¤
get_probe_attenuation(channel: int) -> float
set_horizontal_scale ¤
set_horizontal_scale(seconds_per_div: float) -> None
get_horizontal_scale ¤
get_horizontal_scale() -> float
get_sample_rate ¤
get_sample_rate() -> float
set_acquisition_mode ¤
set_acquisition_mode(mode: AcquisitionMode) -> None
get_acquisition_mode ¤
get_acquisition_mode() -> AcquisitionMode
set_average_count ¤
set_average_count(count: int) -> None
get_average_count ¤
get_average_count() -> int
run ¤
run() -> None
stop ¤
stop() -> None
single ¤
single() -> None
digitize ¤
digitize(timeout: float) -> None

:DIGitize the cached trigger source, then *OPC? under a scoped VISA timeout.

On timeout, clear() aborts the pending op and restores the session.

get_acquisition_state ¤
get_acquisition_state() -> AcquisitionState

:OPERegister:CONDition? bit 3 (0x08) — set = RUNNING, clear = STOPPED.

fetch_waveform ¤
fetch_waveform(channel: int) -> WaveformData

Fetch the waveform from channel over WORD (unsigned 16-bit, LSB-first), 1000 points.

measure ¤
measure(measurement_type: ScopeMeasurementType, channel: int) -> float

Install then query a built-in measurement on channel.

The install form runs first as a guard — bad command syntax surfaces via check_errors() before we'd block on the query. The vendor's invalid-measurement sentinel maps to NaN.

set_trigger_source ¤
set_trigger_source(channel: int) -> None
set_trigger_type ¤
set_trigger_type(trigger_type: TriggerType) -> None
set_trigger_level ¤
set_trigger_level(level: float) -> None
set_trigger_slope ¤
set_trigger_slope(slope: TriggerSlope) -> None
set_trigger_mode ¤
set_trigger_mode(mode: TriggerMode) -> None
force_trigger ¤
force_trigger() -> None
get_trigger_status ¤
get_trigger_status() -> TriggerStatus

:OPERegister:CONDition? bits: 0x20 = ARMED, 0x08 = AUTO (running), else TRIGGERED.

save_screenshot ¤
save_screenshot(filepath: str, to_instrument: bool = False) -> bytes

:SAVE:IMAGe to the scope, or :DISPlay:DATA? PNG,COLor and write locally.

save_settings ¤
save_settings(name: str, to_instrument: bool = False) -> bytes

:SAVE:SETup to scope memory or to the host (:SYSTem:SETup?).

load_settings ¤
load_settings(name: str, from_instrument: bool = False) -> None

:RECall:SETup from scope memory, or send local bytes via :SYSTem:SETup.

setup_measurement ¤
setup_measurement(
    measurement_type: ScopeMeasurementType, channel: int
) -> None

Ensure a measurement slot exists for measurement_type/channel before the scope triggers.

Required for instruments (e.g. Tektronix) that compute measurements during acquisition — the slot must be present at trigger time or the first measure() returns stale/invalid data. Default is a no-op for instruments (e.g. Keysight 1200X) that compute on demand.

Siglent SDS1000X-E¤

Siglent SDS1000X-E series oscilloscope driver (SDS1104X-E and family).

SiglentSDS1000XE ¤

SiglentSDS1000XE(visa_resource: str | VisaConfig)

Bases: ScopeDriverBase

SCPI driver for Siglent SDS1000X-E series oscilloscopes (SDS1104X-E and family).

open ¤
open() -> None

Open the transport and disable comm headers so query replies are bare values.

close ¤
close() -> None
check_errors ¤
check_errors() -> None

Poll CMR? then EXR? and raise on the first non-zero code (no error queue on Siglent).

set_vertical_scale ¤
set_vertical_scale(volts_per_div: float, channel: int) -> None
get_vertical_scale ¤
get_vertical_scale(channel: int) -> float
set_vertical_offset ¤
set_vertical_offset(offset: float, channel: int) -> None
get_vertical_offset ¤
get_vertical_offset(channel: int) -> float
set_coupling ¤
set_coupling(coupling: Coupling, channel: int) -> None
get_coupling ¤
get_coupling(channel: int) -> Coupling
set_probe_attenuation ¤
set_probe_attenuation(factor: float, channel: int) -> None
get_probe_attenuation ¤
get_probe_attenuation(channel: int) -> float
set_horizontal_scale ¤
set_horizontal_scale(seconds_per_div: float) -> None
get_horizontal_scale ¤
get_horizontal_scale() -> float
get_sample_rate ¤
get_sample_rate() -> float
set_acquisition_mode ¤
set_acquisition_mode(mode: AcquisitionMode) -> None
get_acquisition_mode ¤
get_acquisition_mode() -> AcquisitionMode
set_average_count ¤
set_average_count(count: int) -> None
get_average_count ¤
get_average_count() -> int
run ¤
run() -> None
stop ¤
stop() -> None
single ¤
single() -> None
digitize ¤
digitize(timeout: float) -> None

Arm a single acquisition then poll INR? bit 0 (new signal acquired) until set or timeout.

get_acquisition_state ¤
get_acquisition_state() -> AcquisitionState
fetch_waveform ¤
fetch_waveform(channel: int) -> WaveformData

Fetch the full waveform from channel over C{n}:WF? DAT2 (signed 8-bit codes).

measure ¤
measure(measurement_type: ScopeMeasurementType, channel: int) -> float

Query a built-in parameter via C{n}:PAVA?; unavailable/sentinel results map to NaN.

set_trigger_source ¤
set_trigger_source(channel: int) -> None
set_trigger_type ¤
set_trigger_type(trigger_type: TriggerType) -> None
set_trigger_level ¤
set_trigger_level(level: float) -> None
set_trigger_slope ¤
set_trigger_slope(slope: TriggerSlope) -> None
set_trigger_mode ¤
set_trigger_mode(mode: TriggerMode) -> None
force_trigger ¤
force_trigger() -> None
get_trigger_status ¤
get_trigger_status() -> TriggerStatus
save_screenshot ¤
save_screenshot(filepath: str, to_instrument: bool = False) -> bytes

Transfer a screen dump (SCDP, a raw BMP) to the host and write it to filepath.

save_settings ¤
save_settings(name: str, to_instrument: bool = False) -> bytes

Save the panel setup to a USB file (STPN) or transfer it to the host (PNSU?).

load_settings ¤
load_settings(name: str, from_instrument: bool = False) -> None

Recall a panel setup from a USB file (RCPN) or push host bytes back (PNSU).

The host-side PNSU write-back is known to wedge the USBTMC interface on some SDS1000X-E firmware; prefer from_instrument=True (USB stick) over USB connections.

setup_measurement ¤
setup_measurement(
    measurement_type: ScopeMeasurementType, channel: int
) -> None

Ensure a measurement slot exists for measurement_type/channel before the scope triggers.

Required for instruments (e.g. Tektronix) that compute measurements during acquisition — the slot must be present at trigger time or the first measure() returns stale/invalid data. Default is a no-op for instruments (e.g. Keysight 1200X) that compute on demand.

Tektronix 2 Series MSO¤

Tektronix 2 Series MSO oscilloscope driver (MSO22, MSO24).

Tektronix2SeriesMSO ¤

Tektronix2SeriesMSO(visa_resource: str | VisaConfig)

Bases: ScopeDriverBase

SCPI driver for Tektronix 2 Series MSO oscilloscopes (MSO22, MSO24).

open ¤
open() -> None
close ¤
close() -> None
check_errors ¤
check_errors() -> None

Drain ALLEv? and raise on any event with code > 1.

set_vertical_scale ¤
set_vertical_scale(volts_per_div: float, channel: int) -> None
get_vertical_scale ¤
get_vertical_scale(channel: int) -> float
set_vertical_offset ¤
set_vertical_offset(offset: float, channel: int) -> None
get_vertical_offset ¤
get_vertical_offset(channel: int) -> float
set_coupling ¤
set_coupling(coupling: Coupling, channel: int) -> None
get_coupling ¤
get_coupling(channel: int) -> Coupling
set_probe_attenuation ¤
set_probe_attenuation(factor: float, channel: int) -> None
get_probe_attenuation ¤
get_probe_attenuation(channel: int) -> float
set_horizontal_scale ¤
set_horizontal_scale(seconds_per_div: float) -> None
get_horizontal_scale ¤
get_horizontal_scale() -> float
get_sample_rate ¤
get_sample_rate() -> float
set_acquisition_mode ¤
set_acquisition_mode(mode: AcquisitionMode) -> None
get_acquisition_mode ¤
get_acquisition_mode() -> AcquisitionMode
set_average_count ¤
set_average_count(count: int) -> None
get_average_count ¤
get_average_count() -> int
run ¤
run() -> None
stop ¤
stop() -> None
single ¤
single() -> None
digitize ¤
digitize(timeout: float) -> None

SEQuence+RUN, then *OPC? under a scoped VISA timeout. clear() on timeout to restore the session.

get_acquisition_state ¤
get_acquisition_state() -> AcquisitionState
fetch_waveform ¤
fetch_waveform(channel: int) -> WaveformData

Fetch the waveform from channel over RIBinary (signed 16-bit).

setup_measurement ¤
setup_measurement(
    measurement_type: ScopeMeasurementType, channel: int
) -> None

Ensure a persistent measurement slot exists for this type and channel.

Uses MEASUrement:ADDMEAS <type> to create the slot atomically with the target type — this avoids the race where ADDNew "MEAS<n>" + MEAS<n>:TYPe creates a slot that briefly computes under the scope's default type (typically Period) before the type change takes effect, causing the first measure() call to return a stale, wrong-type value. ADDMEAS doesn't take a name; the new slot's name (the scope auto-assigns the next MEAS<n>) is recovered by diffing MEASUrement:LIST? before and after the add.

Tektronix computes measurements during acquisition, so the slot must exist before the scope triggers for results to be valid.

clear_measurements ¤
clear_measurements() -> None

Delete every measurement slot on the scope and reset the local cache.

measure ¤
measure(measurement_type: ScopeMeasurementType, channel: int) -> float

Read a built-in measurement from a persistent slot; the vendor's invalid sentinel maps to NaN.

set_trigger_source ¤
set_trigger_source(channel: int) -> None
set_trigger_type ¤
set_trigger_type(trigger_type: TriggerType) -> None
set_trigger_level ¤
set_trigger_level(level: float) -> None
set_trigger_slope ¤
set_trigger_slope(slope: TriggerSlope) -> None
set_trigger_mode ¤
set_trigger_mode(mode: TriggerMode) -> None
force_trigger ¤
force_trigger() -> None
get_trigger_status ¤
get_trigger_status() -> TriggerStatus
save_screenshot ¤
save_screenshot(filepath: str, to_instrument: bool = False) -> bytes
save_settings ¤
save_settings(name: str, to_instrument: bool = False) -> bytes
load_settings ¤
load_settings(name: str, from_instrument: bool = False) -> None