Control SCPI-compatible test equipment from Python β oscilloscopes, function generators (AWGs), power supplies, and data-acquisition units β over Ethernet/LAN, plus USB, GPIB, and serial through the optional VISA backend.
- One API across vendors. Siglent, Tektronix, and LeCroy oscilloscopes, auto-detected from
*IDN?, alongside PSUs and DAQ units. - Develop without hardware. A realistic mock layer synthesizes state-coupled, trigger-aligned waveforms, so the whole stack runs β and CI passes β with nothing on your bench.
- See it live. A high-performance PyQt6 GUI with interactive measurement markers, plus a browser-based lab gateway.
- Keep the evidence. Provenance-stamped waveform files and automated PDF/Markdown test reports with local-LLM analysis.
Formerly
Siglent-Oscilloscope. Upgrading from the old package? See the Migration Guide.
A live screen capture pulled over LAN from a Siglent SDS824XΒ HD (its 1Β kHz calibration square wave), via scope.screen_capture.get_screenshot_pil().
- Programmatic API: Control your oscilloscope from Python scripts
- Multi-Vendor Oscilloscope Support: Siglent (legacy SDS1000X-E/SDS2000X Plus and modern SDS800X HD/SDS5000X dialects), Tektronix, and LeCroy, auto-detected from
*IDN? - Power Supply & DAQ Support: drive Siglent SPD-series power supplies and SCPI data-acquisition/data-logger units alongside the scope
- Automation & Data Collection: High-level API for batch capture, continuous monitoring, and analysis
- GUI Application: Modern PyQt6-based graphical interface
- Waveform Acquisition: Capture and download waveform data in multiple formats (.npz, .csv, .mat, .h5)
- Acquisition Provenance: every saved waveform records the instrument, settings, and timestamp that produced it; extract raw data from any saved file with load_waveform() or the scpi-extract CLI
- Synthetic Signals & Realistic Mock: generate parameterized test waveforms (sine/square/triangle/ramp/DC/noise/chirp/exponential/pulse/multitone) with
SignalSpec/make_waveform, orsynthesize()/stream()for one-shot arrays and phase-continuous, optionally real-time-paced chunks; develop without hardware against a mock scope that synthesizes state-coupled, trigger-aligned waveforms by default - Channel Configuration: Control voltage scale, coupling, offset, bandwidth
- Trigger Settings: Configure trigger modes, levels, edge detection
- Advanced Analysis: Built-in FFT, SNR, THD, and statistical analysis tools
- High-Performance Live View: Real-time waveform display (5-20 fps, configurable) using PyQtGraph
- Interactive Visual Measurements: Click-and-drag measurement markers directly on waveforms
- 15+ measurement types: Frequency, Vpp, Rise Time, Duty Cycle, etc.
- Visual gates and markers with real-time calculation
- Save/load measurement configurations
- Export results to CSV/JSON
- Non-Blocking Updates: Threaded data acquisition keeps GUI responsive
- Reference Waveforms: Save, overlay, and compare waveforms
- Protocol Decoding: I2C, SPI, UART, CAN, LIN support
- Math Functions: Custom math expressions on waveforms
- VNC Display: Embedded oscilloscope screen viewer
Automatically generate comprehensive PDF and Markdown test reports from your waveform captures with detailed analysis, visualizations, and AI-powered insights. Perfect for documentation, test validation, and automated quality control.
# Install report generator dependencies
# pip install "SCPI-Instrument-Control[report-generator]"
from datetime import datetime
from pathlib import Path
from scpi_control.report_generator.generators.markdown_generator import MarkdownReportGenerator
from scpi_control.report_generator.generators.pdf_generator import PDFReportGenerator
from scpi_control.report_generator.models.report_data import ReportMetadata, TestReport, TestSection, WaveformData
# time_data / voltage_data: your captured numpy arrays (e.g. from scope.get_waveform)
waveform = WaveformData(channel="CH1", time=time_data, voltage=voltage_data, sample_rate=1e6, record_length=len(voltage_data))
metadata = ReportMetadata(title="Probe Calibration Test Report", technician="Lab Technician", test_date=datetime.now(), equipment_model="SDS824X HD")
report = TestReport(metadata=metadata)
report.add_section(TestSection(title="Waveform Captures", waveforms=[waveform], order=1))
report.overall_result = report.calculate_overall_result()
MarkdownReportGenerator().generate(report, Path("calibration_report.md"))
PDFReportGenerator().generate(report, Path("calibration_report.pdf"))Key Features:
- β Automatic Signal Detection - FFT-based classification (sine, square, triangle, pulse, etc.)
- β Comprehensive Statistics - 25+ parameters including Vpp, RMS, frequency, SNR, THD, jitter, overshoot
- β
Template Presets - Ready-made report templates such as
ReportTemplate.create_probe_calibration_template(), manageable from the GUI's Template Manager - β Local-LLM Analysis - Optional AI insights and Q&A tool-calling via Ollama running on your own machine (no cloud providers, no API keys)
- β Region Extraction - Zoom into plateaus, edges, and transients with calibration guidance
- β Multiple Formats - Generate PDF and Markdown reports with embedded plots
- β Professional Layout - Publication-ready reports with metadata, statistics tables, and visualizations
- β
Comparison & Batch Reports - Compare before/after captures or aggregate multi-DUT batches with delta/yield tables, a sign-off block, and a SHA-256 raw-data manifest; available via
Report β Comparison / Batch Reportβ¦in the GUI
Report Sections Include:
- Test metadata (title, ID, operator, timestamp, scope model)
- Waveform plots with automatic scaling
- Signal classification and characteristics
- Detailed measurement tables
- Region-of-interest analysis with zoomed views
- AI-generated insights and recommendations (optional)
- Pass/fail criteria and test conclusions
See examples/probe_calibration_analysis.py for complete examples including region extraction and automated probe compensation guidance.
Use your oscilloscope as a vector display by generating waveforms for XY mode:
- Draw Shapes: Circles, rectangles, stars, polygons, Lissajous figures
- Text Rendering: Display text messages on your oscilloscope screen
- Animations: Create rotating and transforming graphics
- Composite Paths: Combine multiple shapes into complex drawings
Requirements: External AWG/DAC or scope's built-in AWG to feed generated waveforms into scope channels.
# Install the fun extras
# pip install "SCPI-Instrument-Control[fun]"
from scpi_control import Oscilloscope
from scpi_control.vector_graphics import Shape
scope = Oscilloscope('192.168.1.100')
scope.connect()
# Enable XY mode (CH1=X, CH2=Y)
scope.vector_display.enable_xy_mode()
# Generate waveforms for a circle
circle = Shape.circle(radius=0.8, points=1000)
x_wave, y_wave = scope.vector_display.draw(circle)
# Save for AWG upload
scope.vector_display.save_waveforms(circle, "my_circle", format='csv')
# Load my_circle_x.csv and my_circle_y.csv into your AWG!See examples/vector_graphics_xy_mode.py for more demos including animations and text!
pip install SCPI-Instrument-ControlTo include optional features, use extras:
# GUI application with PyQt6
pip install "SCPI-Instrument-Control[gui]"
# Automated report generation (PDF/Markdown with AI analysis)
pip install "SCPI-Instrument-Control[report-generator]"
# Vector graphics and XY mode (draw shapes on scope!)
pip install "SCPI-Instrument-Control[fun]"
# Browser-based lab gateway (scpi-web)
pip install "SCPI-Instrument-Control[web]"
# USB/GPIB/serial instruments via PyVISA
pip install "SCPI-Instrument-Control[usb]"
# Everything
pip install "SCPI-Instrument-Control[all]"Note: The siglent-gui command includes automatic dependency checking. If you try to run the GUI without the required packages, you'll receive a clear error message with installation instructions. Missing optional dependencies (like PyQtGraph for high-performance live view) will trigger warnings but allow the GUI to launch.
| Command | Description |
|---|---|
siglent-gui |
Launch the PyQt6 GUI application |
siglent-report-generator |
Launch the standalone report-generator app |
scpi-web |
Serve the browser-based lab gateway (REST + WebSocket API, optional web UI) |
scpi-extract |
Inspect or export a saved waveform file from the command line |
git clone git@github.com:little-did-I-know/SCPI-Instrument-Control.git
cd SCPI-Instrument-Control
pip install -e .Install with GUI support from source:
pip install -e ".[gui]"pip install -e ".[dev]"To create release artifacts that render correctly on PyPI:
python -m build
twine check dist/*The twine check command validates the built distributions, including the long description rendered from README.md, before upload.
v1.0.0 introduces a package rename from Siglent-Oscilloscope to SCPI-Instrument-Control to better reflect the expanded capabilities of this library.
If you're upgrading from the old siglent package:
Uninstall the old package (if installed):
pip uninstall siglentInstall the new package:
pip install SCPI-Instrument-ControlOr with extras:
pip install "SCPI-Instrument-Control[gui]"
pip install "SCPI-Instrument-Control[all]"Old imports (no longer work as of v2.0.0):
from siglent import Oscilloscope, PowerSupply, FunctionGenerator
from siglent.gui.app import main
from siglent.waveform import WaveformNew imports (recommended):
from scpi_control import Oscilloscope, PowerSupply, FunctionGenerator
from scpi_control.gui.app import main
from scpi_control.waveform import WaveformThe siglent compatibility shim was removed in v2.0.0 (it had emitted a
DeprecationWarning since v1.0.0). import siglent now raises
ModuleNotFoundError β update your imports to scpi_control as shown above;
the API is otherwise identical. If you cannot migrate yet, pin
SCPI-Instrument-Control<2.0.
The CLI commands remain unchanged for convenience:
siglent-gui # Still works!
siglent-report-generator # Still works!No changes needed to scripts or automation that invoke these commands.
| Old | New | Status |
|---|---|---|
PyPI package: siglent |
PyPI package: SCPI-Instrument-Control |
Changed |
import siglent |
import scpi_control |
Required since v2.0.0 |
siglent-gui command |
siglent-gui command |
Unchanged |
siglent-report-generator command |
siglent-report-generator command |
Unchanged |
This library has grown significantly beyond its original focus on Siglent oscilloscopes:
- Multi-Instrument Support: Oscilloscopes, power supplies, and function generators
- Multi-Vendor Support: Works with any SCPI-compatible equipment (not just Siglent)
- Universal Protocol: Based on industry-standard SCPI commands
The new name better represents what the library does: control any SCPI-compatible test equipment.
If you encounter any migration issues:
- Check the CHANGELOG.md for detailed v1.0.0 release notes
- Open an issue on GitHub
- Review the updated examples/ directory for new usage patterns
from scpi_control import Oscilloscope
# Connect to oscilloscope
scope = Oscilloscope('192.168.1.100')
scope.connect()
# Get device information
print(scope.identify())
# Configure channel 1
scope.channel1.set_scale(1.0) # 1V/div
scope.channel1.set_coupling('DC')
scope.channel1.enable()
# Capture waveform
waveform = scope.get_waveform(channel=1)
print(f"Captured {len(waveform.time)} samples")
scope.disconnect()siglent-guiOr from Python:
from scpi_control.gui.app import main
main()- Python 3.9+
- NumPy >= 1.24.0
- Matplotlib >= 3.7.0
- SciPy >= 1.10.0
Install with [gui] extra to add:
- PyQt6 >= 6.6.0
- PyQt6-WebEngine >= 6.6.0
- PyQtGraph >= 0.13.0 (high-performance plotting)
- Report Generator: Install with
[report-generator]to add PyQt6, Pillow, requests, ReportLab, Ollama (PDF/Markdown reports with AI) - HDF5 support: Install with
[hdf5]to add h5py >= 3.8.0 - Vector Graphics: Install with
[fun]to add shapely, Pillow, svgpathtools (XY mode drawing) - Web Gateway: Install with
[web]to add FastAPI, Uvicorn, Pillow (browser-based lab gateway,scpi-web) - USB/GPIB/Serial: Install with
[usb]to add PyVISA + pyvisa-py (USB-TMC, GPIB, and serial instrument connections) - All features: Install with
[all]for complete functionality
The oscilloscope must be connected to your network. The default SCPI port is 5025.
To find your oscilloscope's IP address:
- Press Utility on the oscilloscope
- Navigate to I/O settings
- Check the LAN configuration
The SCPI Instrument Control GUI provides a comprehensive interface for controlling your oscilloscope, capturing waveforms, and performing measurements.
The main interface consists of:
- Waveform Display: High-performance real-time plotting area (center)
- Control Panels: Tabbed interface with all oscilloscope controls (right)
- Menu Bar: File operations, acquisition controls, and utilities (top)
- Status Bar: Connection status and system information (bottom)
To connect to your oscilloscope:
- Launch the GUI:
siglent-gui - Enter your oscilloscope's IP address
- Click Connect
The oscilloscope must be connected to your network (default SCPI port: 5025).
Finding your oscilloscope's IP address:
- Press Utility on the oscilloscope
- Navigate to I/O settings
- Check the LAN configuration
The Channels tab provides complete control over all input channels:
- Enable/Disable: Toggle channels on/off with checkboxes
- Voltage Scale: Adjust volts/division (0.001V to 10V)
- Coupling: Set DC, AC, or GND coupling
- Probe Ratio: Configure probe attenuation (1X, 10X, 100X, etc.)
- Bandwidth Limit: Enable 20MHz bandwidth limiting
- Offset: Adjust vertical position
Quick Tip: Enable channels before starting Live View or capturing waveforms.
The GUI features high-performance real-time waveform viewing powered by PyQtGraph:
Acquisition β Live View (Ctrl+R)
Performance:
- Real-time updates at 5-20 fps (configurable)
- 100x faster than traditional matplotlib-based viewers
- Non-blocking: GUI remains responsive during data acquisition
- Supports all 4 channels simultaneously
Controls:
- Enable channels in the "Channels" tab first
- Live view automatically acquires from enabled channels
- Adjust update rate by modifying
update_intervalinlive_view_worker.py
Interactive measurement markers that you can place and adjust directly on waveforms:
How to use:
- Go to the "Visual Measure" tab
- Select measurement type (Frequency, Vpp, Rise Time, etc.)
- Select channel (CH1-CH4)
- Click "Add Marker"
- Marker auto-places on waveform
- Drag marker gates to adjust measurement region
- See real-time measurement updates
Measurement Types:
- Frequency/Period: Auto-detects signal period
- Voltage: Vpp, Amplitude, Max, Min, RMS, Mean
- Timing: Rise Time, Fall Time, Pulse Width, Duty Cycle
Features:
- Save/Load Configs: Save measurement setups for reuse
- Export Results: Export to CSV or JSON
- Auto-Update: Optional 1-second auto-refresh
- Batch Mode: Run multiple measurements simultaneously
Example Workflow:
# In GUI:
# 1. Capture or enable live view
# 2. Visual Measure tab β Add Marker
# 3. Type: "Frequency", Channel: "CH1" β Add
# 4. Marker appears with measurement result
# 5. Save Config β "my_measurements.json"
# 6. Export Results β "results.csv"The Measurements tab provides quick access to standard oscilloscope measurements:
- 15+ measurement types (frequency, Vpp, RMS, rise time, etc.)
- Channel selection
- Results table with units
- Export measurement results
Interactive cursors for precise measurements:
- Vertical cursors for time measurements
- Horizontal cursors for voltage measurements
- Delta calculations (ΞT, ΞV, frequency)
- Draggable cursor lines
- Real-time delta updates
Frequency domain analysis:
- Fast Fourier Transform visualization
- Peak detection and markers
- Window function selection (Hanning, Hamming, Blackman)
- Frequency and amplitude axes
- Export FFT data
Requires:
pip install "SCPI-Instrument-Control[fun]"
Turn your oscilloscope into a vector display by generating waveforms for XY mode!
The Vector Graphics tab provides:
Shape Generator:
- Basic Shapes: Circle, Rectangle, Star, Triangle, Line
- Lissajous Figures: Classic oscilloscope patterns (3:2, 5:4, 7:5, etc.)
- Parameter Controls: Adjust size, points, frequency ratios, phase shifts
- Generate Button: Create vector paths with customizable parameters
Waveform Export:
- Sample Rate Control: 1-1000 MSa/s for AWG compatibility
- Duration: 1ms to 10s per waveform
- Format Options: CSV (universal), NumPy (.npy), Binary (.bin)
- Save for AWG: Exports separate X and Y waveform files
XY Mode Control:
- Enable/Disable: Configure oscilloscope for XY display mode
- Channel Setup: Auto-configures CH1 (X-axis) and CH2 (Y-axis)
- Status Display: Connection and configuration feedback
How to use:
- Go to the "Vector Graphics π¨" tab
- Select a shape (e.g., "Circle" or "Lissajous")
- Adjust parameters (radius, points, frequencies)
- Click "Generate Shape"
- Set sample rate and duration for your AWG
- Click "Save Waveforms..." to export
- Load the X/Y files into your AWG (Channel 1 = X, Channel 2 = Y)
- Connect AWG outputs to scope inputs
- Click "Enable XY Mode" or manually enable on scope
- Watch your shape appear on the oscilloscope! β¨
Works without scope connection - you can generate and export waveforms offline!
Example Use Cases:
- Draw circles, stars, and geometric shapes
- Create classic Lissajous patterns for calibration
- Generate animations (rotating shapes, morphing patterns)
- Educational demonstrations of XY mode
- Signal generator pattern testing
See examples/vector_graphics_xy_mode.py for programmatic usage and animation examples.
Power Supply:
- Dedicated Power Supply tab (
Connect to Power Supply...menu action) for Siglent SPD-series and generic SCPI-99 power supplies - Per-channel voltage/current setpoints, output enable, and readback
Data Logger:
- Dedicated Data Logger tab (
Connect to Data Logger...menu action) for SCPI DAQ/data-acquisition units - Channel scan configuration and readings display
Terminal:
- Built-in Terminal tab for sending raw SCPI commands directly to the connected instrument
Reference Waveforms:
- Save waveforms as references
- Overlay comparisons
- Difference mode (live - reference)
- Calculate correlation
Math Channels:
- Custom expressions:
C1 + C2,C1 * 2, etc. - Real-time calculation
FFT Analysis:
- Frequency domain visualization
- Window function selection
- Peak detection
Protocol Decode:
- I2C, SPI, UART, CAN, LIN decoding
- Packet analysis and export
Control instruments from any browser on your LAN:
pip install scpi-instrument-control[web] # includes the browser gateway
scpi-web # first run prints a URL with a tokenOn first run the gateway mints an access token and prints a ready-to-open URL
(http://127.0.0.1:8765/?token=β¦). Every request needs a token β mint more
with scpi-web token add <name>. Sessions can target real scopes by IP or a
built-in mock (mock: true) for hardware-free use. The OpenAPI schema is served
at /api/openapi.json (token required); the interactive /docs//redoc UIs are
disabled. Bind to 127.0.0.1 (the default) unless your LAN is trusted, and use
--host 0.0.0.0 to expose it.
Security model: the gateway authenticates every request, gives each instrument session an owner (owner writes, everyone else watches), validates outbound connection targets, and caps concurrent sessions. It does not terminate TLS β put it behind a reverse proxy or keep it on a trusted network. See the Gateway security guide for tokens, ownership, claiming, the SSRF gate, and deployment.
Upgrading from 4.x: the gateway now requires a token, and reference files saved by 4.x must be converted once with
scpi-web references migrate. Both are covered in the security guide.
Full documentation: Web Gateway guide β overview, browser UI tour, and the complete REST & WebSocket API reference.
GET /api/discoverscans the gateway's subnet (or?cidr=β¦) for SCPI instruments on port 5025 and lists them with model and dialect β handy when DHCP moves your instruments around.GET .../scope/screenshot.pngβ the instrument's display as a PNGGET .../scope/waveform?channels=1,2&max_points=Nβ waveform data as JSONGET/PATCH .../scope/math/{1,2}β software math channels (streamed as M1/M2 traces)GET .../scope/measurementsβ the current measurement selectionGET/PATCH .../scope/spectrumβ server-computed FFT spectrum (streamed asspectrumframes)GET .../scope/filters+PATCH .../scope/filters/{1,2}β software Butterworth filters (streamed as F1/F2 traces)GET/POST/DELETE .../scope/references+GET/PUT .../scope/referenceβ saved reference waveforms and the live overlayPOST .../scope/log/start/POST .../scope/log/stopβ record the selected measurements (~1 Hz) server-sideGET .../scope/log,GET .../scope/log/data?since=,GET .../scope/log.csvβ recording status, rows, and CSV export
make webapp-install # once
make webapp-build # build the UI into the server
scpi-web --host 0.0.0.0 # serve API + UI on one portOpen the tokened URL the gateway prints on startup. For UI development, run
scpi-web in one terminal and cd webapp/app && npm run dev in another β Vite
proxies /api (HTTP and WebSocket) to the gateway with hot reload; open the dev
server with the ?token=β¦ from the gateway's startup URL so the UI picks it up.
The home screen scans your LAN and lists instruments to connect to, resume, or open a shared session on β plus manual IP and a hardware-free mock.
from scpi_control import Oscilloscope
# Connect
scope = Oscilloscope('192.168.1.100', port=5025, timeout=5.0)
scope.connect()
# Device information
print(scope.identify()) # Get *IDN? string
print(scope.device_info) # Parsed device info dict
# Basic controls
scope.run() # Start acquisition (AUTO mode)
scope.stop() # Stop acquisition
scope.auto_setup() # Auto setup
scope.reset() # Reset to defaults# Channel configuration (channels 1-4)
scope.channel1.enable()
scope.channel1.coupling = "DC" # DC, AC, or GND
scope.channel1.voltage_scale = 1.0 # Volts/division
scope.channel1.voltage_offset = 0.0 # Volts
scope.channel1.probe_ratio = 10.0 # 10X probe
scope.channel1.bandwidth_limit = "OFF" # ON or OFF
# Get configuration
config = scope.channel1.get_configuration()# Trigger configuration
scope.trigger.mode = "NORMAL" # AUTO, NORM, SINGLE, STOP
scope.trigger.source = "C1" # C1, C2, C3, C4, EX, LINE
scope.trigger.level = 0.0 # Trigger level in volts
scope.trigger.slope = "POS" # POS (rising) or NEG (falling)
# Edge trigger setup
scope.trigger.set_edge_trigger(source="C1", slope="POS")
# Trigger actions
scope.trigger.single() # Single trigger
scope.trigger.force() # Force trigger# Acquire waveform
waveform = scope.get_waveform(channel=1)
# Access data
print(waveform.time) # Time array (numpy)
print(waveform.voltage) # Voltage array (numpy)
print(waveform.sample_rate)
print(waveform.record_length)
# Save waveform
scope.waveform.save_waveform(waveform, "data.csv", format="CSV")# Individual measurements
freq = scope.measurement.measure_frequency(1)
vpp = scope.measurement.measure_vpp(1)
vrms = scope.measurement.measure_rms(1)
period = scope.measurement.measure_period(1)
# All measurements at once
measurements = scope.measurement.measure_all(1)For advanced data collection workflows, use the high-level automation API:
from scpi_control.automation import DataCollector
# Simple capture with automatic analysis
with DataCollector('192.168.1.100') as collector:
# Capture waveforms
data = collector.capture_single([1, 2])
# Analyze waveform
stats = collector.analyze_waveform(data[1])
print(f"Vpp: {stats['vpp']:.3f}V, Freq: {stats['frequency']/1e3:.2f}kHz")
# Save to file - format is auto-detected from the extension (.npz/.csv/.mat/.h5)
collector.save_data(data, 'measurement.npz')Batch capture with configuration sweeps:
# Capture with different timebase and voltage settings
results = collector.batch_capture(
channels=[1],
timebase_scales=['1us', '10us', '100us'],
voltage_scales={1: ['500mV', '1V', '2V']},
triggers_per_config=5
)
collector.save_batch(results, 'batch_output')Continuous time-series collection:
# Collect data over time with automated file saving
collector.start_continuous_capture(
channels=[1, 2],
duration=300, # 5 minutes
interval=1.0, # 1 capture per second
output_dir='time_series_data',
file_format='npz'
)Event-based trigger capture:
from scpi_control.automation import TriggerWaitCollector
with TriggerWaitCollector('192.168.1.100') as tc:
# Configure trigger
tc.collector.scope.trigger.set_source(1)
tc.collector.scope.trigger.set_slope('POS')
tc.collector.scope.trigger.set_level(1, 1.0)
# Wait for trigger event
data = tc.wait_for_trigger(channels=[1, 2], max_wait=30.0)Advanced analysis:
# Built-in analysis includes: Vpp, RMS, frequency, SNR, THD, etc.
analysis = collector.analyze_waveform(waveform)
print(f"SNR: {analysis['snr_db']:.2f} dB")
print(f"THD: {analysis['thd_percent']:.2f}%")See examples/ directory for complete automation examples including:
- Simple capture (
simple_capture.py) - Batch processing (
batch_capture.py) - Continuous monitoring (
continuous_capture.py) - Trigger-based capture (
trigger_based_capture.py) - Advanced analysis with visualization (
advanced_analysis.py)
Any file saved by the library (.npz/.csv/.mat/.h5) can be read back with
load_waveform(), which normalizes format differences and reattaches
acquisition provenance when present:
from scpi_control.waveform_io import load_waveform
loaded = load_waveform("measurement.npz")
print(loaded.time, loaded.voltage) # numpy arrays
print(loaded.provenance) # instrument/settings snapshot, or None
df = loaded.to_dataframe() # pandas DataFrame, provenance in df.attrsThe same data is available from the command line via scpi-extract:
scpi-extract measurement.npz --info # provenance + metadata summary
scpi-extract measurement.npz --csv out.csv # dump raw time,voltage rows
scpi-extract measurement.npz --json # machine-readable metadataThis project ships 27 runnable example scripts, each documented with its
requirements in examples/README.md β see it for the
full list. A few highlights:
- basic_usage.py - Connection and basic operations
- waveform_capture.py - Capture and save waveforms
- measurements.py - Automated measurements
- live_plot.py - Real-time plotting
- probe_calibration_analysis.py - Automated report generation with region extraction and AI analysis
- synthetic_signals.py - Generating parameterized test waveforms and streaming state-coupled mock captures (no hardware)
- waveform_provenance_and_extract.py - Capturing with provenance, saving, and reading back with
load_waveform()(no hardware)
- SDS800X HD Series: SDS804X HD, SDS824X HD
- SDS1000X-E Series: SDS1102X-E, SDS1104X-E, SDS1202X-E, SDS1204X-E
- SDS2000X Plus Series: SDS2104X+, SDS2204X+, SDS2354X+
- SDS5000X Series: SDS5034X, SDS5054X, SDS5104X
- Tektronix TBS1000C Series: TBS1102C
- Tektronix 2 Series MSO: MSO24
- Tektronix 4 Series MSO: MSO44, MSO46
- Tektronix 5 Series MSO: MSO54, MSO56, MSO58, MSO58LP
- Tektronix 6 Series MSO: MSO64
- LeCroy WaveSurfer 3000z Series: WaveSurfer 3024z
- LeCroy WaveRunner 8000 Series: WaveRunner 8104
All Tektronix MSO models (2/4/5/6 Series) share one command variant and support automated measurements β see the SCPI Dialects guide for the full per-vendor gap list.
Command tables were verified command-by-command against the vendor programmer manuals (Tektronix TBS1000C, 2 Series MSO, and 4/5/6 Series MSO/6 Series LPD manuals; the Teledyne LeCroy MAUI Remote Control and Automation Manual) and exercised against a dialect-aware mock; not yet run against real Tektronix or LeCroy hardware.
- Siglent SDG1000X Series: SDG1032X, SDG1025, SDG1020
- Siglent SDG2000X Series: SDG2122X, SDG2082X, SDG2042X
- Siglent SPD3303X Series: SPD3303X, SPD3303X-E (triple output)
- Siglent SPD1000X Series: SPD1305X, SPD1168X (single output)
- Keysight/Agilent 34970A Series: 34970A, 34972A
- Keysight DAQ970A Series: DAQ970A, DAQ973A
- Generic SCPI-99 data loggers via the DAQ capability registry
Should work with other Siglent oscilloscopes that support SCPI commands over Ethernet. Model-specific features are auto-detected via the ModelCapability registry. Unrecognized Tektronix or LeCroy models fall back to a conservative generic profile for that vendor (with a logged warning) rather than being rejected outright.
Note: Some SCPI commands vary between models. The library includes model-specific command variants for HD, X, and Plus series (Siglent) and for TBS vs. MSO (2/4/5/6 Series share one variant) (Tektronix).
Contributions are welcome! Please read our Contributing Guide for details on:
- Development setup and workflow
- Code style and testing requirements
- Pull request process
- How to report bugs and request features
# Clone and setup
git clone https://github.com/little-did-I-know/SCPI-Instrument-Control.git
cd SCPI-Instrument-Control
# Install development environment
make dev-setup
# Run tests
make test
# Format code
make format
# Run all checks
make checkDuring development, python -m pytest --testmon runs only the tests affected by your changes for fast feedback; the full suite is still required before opening a PR.
See our Code of Conduct and Security Policy for more information.
- Issues: Report bugs or request features
- Discussions: Ask questions and share ideas
- Security: See our Security Policy for reporting vulnerabilities
- π Interactive Tutorial - Jupyter notebook with step-by-step examples
- π Examples Directory - Ready-to-run example scripts
- π API Documentation - Complete API reference in this README
- π§ Contributing Guide - How to contribute to the project
- π§ͺ Experimental Features Guide - Beta releases and experimental features
- π Security Policy - Security best practices and reporting
MIT License - see LICENSE file for details





