Skip to main content

Real-Time Simultaneous Dual-Channel Oscilloscope & Spectrum Analyzer

PyPI Version License: MIT Hardware Overlay Board Support

A high-performance, dark-mode real-time Dual-Channel Oscilloscope and Spectrum Analyzer software stack running natively on PYNQ Linux platforms.

Features simultaneous dual-channel continuous analog acquisition on Arduino header pins A0 (Vaux1) and A1 (Vaux9), selectable hardware edge triggering (CH1 / A0 vs CH2 / A1), FPGA-accelerated 2048-point FFT & CORDIC magnitude extraction in Programmable Logic, dual AXI DMA streaming direct to DDR memory at ~30 FPS, and non-blocking concurrent dual-channel analog waveform generation with the Digilent Analog Discovery 3 (AD3) via pydwf.


🏛 System Architecture

This repository adopts the canonical PYNQ Custom Overlay pattern (OscilloscopeOverlay). It automatically pulls its compiled hardware bitstream and metadata from GitHub Releases (or loads local custom .bit builds) and encapsulates the Dual DMA receivers, AXI-Lite trigger registers, sequencer controls, and dual-wavegen into a unified Python object.

 [ Analog Discovery 3 ] ──(W1: Yellow)──────> [ PYNQ-Z2 Pin A0 (Vaux1) ]
 [      Wavegen       ] ──(W2: Yellow/White)─> [ PYNQ-Z2 Pin A1 (Vaux9) ]
        │                                                     │
  (pydwf SDK)                                     (XADC Dual Continuous Sequencer)
        │                                                     │ (1 MSPS Interleaved Stream)
        ▼                                                     ▼
 [ AD3SignalGenerator ]                              [ axis_trigger_unit IP ]
 (Concurrent W1 & W2)                                (Selectable Trigger Source: A0/A1)
                                                              │
                                                     [ tlast_generator (2048 pts) ]
                                                              │
                                                     [ axis_broadcaster ]
                                               ┌──────────────┴──────────────┐
                                               ▼ (Time Stream)               ▼ (Signed Stream)
                                      [ AXI DMA 0 (Time) ]          [ xfft (2048-pt BFP) ]
                                               │                             │
                                               │                    [ CORDIC (Magnitude) ]
                                               │                             │
                                               │                    [ AXI DMA 1 (FFT) ]
                                               │                             │
                                               └──────────────┬──────────────┘
                                                              ▼
                                                   [ OscilloscopeOverlay ]
                                            ├── .trigger  (HardwareTrigger AXI-Lite)
                                            ├── .xadc     (StreamingXADC DMA Driver)
                                            ├── .fft      (StreamingFFT PL DMA Driver)
                                            ├── .wavegen  (AD3SignalGenerator Dual-DAC)
                                            └── .dashboard() (Interactive 4-Tab Instrument)

🖥 Interactive 4-Tab Dashboard UI Guide

Tab 1 — 📈 Dual Oscilloscope (A0 & A1)

Displays synchronized real-time time-domain traces for Channel 1 (A0, Cyan) and Channel 2 (A1, Magenta). The Trigger Threshold Line (Orange Dashed) automatically relocates to whichever channel is selected as the active trigger source.

Dual Scope Triggered on A0

Trigger source set to CH2 (A1) — the trigger threshold line dynamically moves to the bottom A1 subplot: Dual Scope Triggered on A1


Tab 2 — 📊 Dual Spectrum Analyzer (FFTs of A0 & A1)

Computes and renders high-speed frequency spectra for both channels simultaneously ($0 - 250,\text{kHz}$) with automated fundamental peak frequency ($f_0$) tracking.

Dual FFT Spectrum Analyzer


Tab 3 & 4 — 🔀 Dedicated Channel Views

Stacked multi-domain displays showing Time Domain (top) and Frequency Domain (bottom) for each channel individually:

Channel 1: A0 (Time + Spectrum) Channel 2: A1 (Time + Spectrum)
Channel 1 View Channel 2 View

⚙️ Control Panel Reference

  1. Action Row (Row 1):

    • ▶ Start Live: Launches non-blocking dual DMA stream and AD3 dual wavegen.
    • ■ Stop: Cleanly halts hardware loops, disarms triggers, and releases AD3 handles.
    • ⚡ Force / Arm: Forces capture in Auto/Normal mode or arms single-shot capture.
    • Auto-Range (Toggle): Dynamically scales horizontal timebase (5–10 signal periods) according to the selected trigger channel's frequency.
    • Live Metric Bar: Real-time $V_{pp}$ and peak fundamental frequency ($f_0$) for both A0 and A1.
  2. Trigger Controls (Row 2):

    • Trig Mode: Auto (continuous with 50 ms fallback), Normal (strictly edge-gated), Single (transient capture).
    • Trig Edge: Rising / Falling edge slope detection.
    • Trig Source: Selects active hardware trigger channel: CH1 (A0) or CH2 (A1).
    • Trig Level: Sets the analog threshold register ($0.0,\text{V} - 3.3,\text{V}$).
  3. Dual Wavegen Controls (Rows 3 & 4):

    • CH1 (A0) & CH2 (A1): Independent waveform shapes (Sine, Triangle, Square), amplitudes ($0.1,\text{V} - 1.5,\text{V}$), and frequencies ($50,\text{Hz} - 100,\text{kHz}$).
  4. FFT Controls (Row 5):

    • FFT Unit: Select logarithmic power (dBV, dBFS) or linear amplitude (Linear).
    • Span / Zoom: Zooms frequency axis (Full 250 kHz, 100 kHz, 20 kHz).

🔌 Hardware Setup & Wiring

AD3 Wire Wire Color PYNQ-Z2 Analog Pin Signal Description
Wavegen 1 (W1) Solid Yellow Header J1 Pin A0 (Pin 6 - Bottom) Channel 1 Analog Input (Vaux1)
Wavegen 2 (W2) Yellow / White Stripe Header J1 Pin A1 (Pin 5 - 2nd from Bottom) Channel 2 Analog Input (Vaux9)
GND Solid Black PYNQ-Z2 GND Common Analog Reference

Note: Connect the AD3 USB cable to the large rectangular USB HOST port on the PYNQ-Z2 board. Use an external 5V auxiliary power supply for the AD3 to ensure voltage rail stability under dual-channel generation.


🚀 Quick Start & Installation

1. Install Package from PyPI

pip install --upgrade pynq-oscilloscope

2. Copy Example Notebooks to Jupyter Workspace

pynq-oscilloscope-get-notebooks

3. Install Digilent AD3 Drivers (One-Time Setup)

from pynq_oscilloscope import install_ad3_drivers
install_ad3_drivers()

💻 Python API Usage

Launch Interactive Dual Dashboard

from pynq_oscilloscope import check_usb_permissions, OscilloscopeOverlay

check_usb_permissions()

# Automatically loads v1.3.0-rc1 dual-channel overlay and programs FPGA
ol = OscilloscopeOverlay()

# Launch interactive 4-tab Plotly + IPywidgets dashboard
app = ol.dashboard()

Programmatic Dual-Channel Capture

from pynq_oscilloscope import OscilloscopeOverlay

ol = OscilloscopeOverlay()

# Configure Trigger: Trigger on Channel 2 (A1) Rising Edge @ 1.65V
ol.trigger.configure(mode="Auto", edge="Rising", source="CH2", threshold_volts=1.65)

# Synchronously capture both channels (1024 samples per channel @ 500 kSPS)
v_a0, v_a1 = ol.capture_stereo()
print(f"Captured A0 Vpp: {v_a0.max()-v_a0.min():.2f} V | A1 Vpp: {v_a1.max()-v_a1.min():.2f} V")

ol.close()

📓 Notebook Suite

Notebook Description Key Modules Used
01_ad3_getting_started.ipynb Verifies Digilent drivers and generates analog waveforms in background worker. AD3SignalGenerator, check_usb_permissions
02_xadc_getting_started.ipynb Single-channel hardware triggering and DMA capture on A0. OscilloscopeOverlay, HardwareTrigger
03_oscilloscope_dashboard.ipynb Main Application: Deploys the complete interactive 4-Tab Dual-Channel Dashboard. OscilloscopeOverlay
04_fft_spectrum_analyzer.ipynb Spectrum Analyzer Guide: Captures PL hardware FFT spectra, analyzes harmonics. OscilloscopeOverlay, StreamingFFT

⚠️ Release Notes & Disclaimer

Pre-Release Disclaimer (v1.3.0-rc1):

  • Sampling Rate: The dual-channel continuous sequencer operates at an aggregate sampling rate of $1.0,\text{MSPS}$ ($500,\text{kSPS}$ per channel).
  • Hardware Phase-Lock: The hardware trigger unit guarantees that DMA packets strictly start aligned to Channel 1 (A0) even when triggering off Channel 2 (A1).
  • Known Considerations: While fully validated for standard laboratory wave generation and cross-channel triggering up to $100,\text{kHz}$, fine adjustments for extreme frequency ratios (e.g. $>10:1$ differences between A0 and A1) or high-noise edge environments may be further tuned in future revisions.

📄 License

This project is licensed under the MIT License - see the LICENSE file for details.

Metadata

Release files for pynq-oscilloscope 1.3.0

For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.

Source distribution (sdist)

Source distribution for pynq-oscilloscope 1.3.0
File Size Uploaded
pynq_oscilloscope-1.3.0.tar.gz 29.3 kB Details

Built distribution (wheel)

Table of built distributions (wheels) for pynq-oscilloscope 1.3.0
File Interpreter ABI Platform
pynq_oscilloscope-1.3.0-py3-none-any.whl Python 3 none any Details

Total release size: 61.8 kB

Release files / pynq_oscilloscope-1.3.0.tar.gz

Download URL pynq_oscilloscope-1.3.0.tar.gz
Size 29.3 kB
Tags Source
SHA-256 checksum
How to use checksums
87d286187324ed5189336c0e9a996040b4a0d719638a94c41b7ea28e1cb2b272
BLAKE2b-256 checksum
How to use checksums
81c36bae73a239df61c51602b99cf4e092ee9ca8a2a4e2ccaf22052d7aae2432
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/7.0.0 CPython/3.13.14

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Aug 17, 2026.

Transparency log

Release files / pynq_oscilloscope-1.3.0-py3-none-any.whl

Download URL pynq_oscilloscope-1.3.0-py3-none-any.whl
Size 32.6 kB
Tags Python 3
SHA-256 checksum
How to use checksums
6cbaa1054f53030a7cf1e8ada40ad6ce8502c374c90d467adc453897a8b85523
BLAKE2b-256 checksum
How to use checksums
596bbcb655c3550c05ffe71ef3e61cab0ecdce1fb0eccecac958007f04fdf089
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/7.0.0 CPython/3.13.14

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Aug 17, 2026.

Transparency log

Release history Release notifications | RSS feed

1.6.0

2 release files

1.5.0

2 release files

1.4.5

2 release files

1.4.0

2 release files

This release

1.3.0 This release

2 release files

1.2.0

2 release files

1.1.0

2 release files

1.0.1

2 release files

1.0.0

2 release files

Anthropic, PBC Visionary sponsor Bloomberg Visionary sponsor Hudson River Trading Visionary sponsor Meta Visionary sponsor NVIDIA Visionary sponsor Microsoft Sustainability sponsor Depot Continuous Integration AWS Cloud computing and Security Sponsor Datadog Monitoring Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page