This is a Docker environment that seamlessly integrates GNU Radio with JupyterLab, by dealing with the complex compatibility challenges through virtual environment isolation and providing an automatic notebook template system for rapid SDR development.
GNU Radio (from Ubuntu packages) and Jupyter (from pip) have fundamentally incompatible dependencies:
- pyzmq conflict: System GNU Radio requires one version, Jupyter requires another
- NumPy version lock: GNU Radio is compiled against NumPy 1.x, incompatible with NumPy 2.x
- Python path isolation: System packages vs. virtual environment packages need careful bridging
System Python (/usr/bin/python3)
βββ GNU Radio 3.10.9.2 (apt packages)
βββ System pyzmq (required by GNU Radio)
βββ NumPy 1.x (system version)
Virtual Environment (/opt/venv) - ISOLATED
βββ JupyterLab (latest)
βββ Different pyzmq (Jupyter's version)
βββ NumPy 1.x (pinned for compatibility)
βββ All user packages
Bridge: IPython startup script adds system packages to path
Result: Both GNU Radio and Jupyter work perfectly together
# Build the Docker image
./gnuradio_jupyter_docker_manager.sh build
# Start the container (auto-finds available port if 8888 is taken)
./gnuradio_jupyter_docker_manager.sh start
# Access JupyterLab
http://localhost:8888/lab?token=dockerEvery new notebook automatically includes GNU Radio setup! No manual configuration needed.
Coming Soon:
- Hardware Support: RTL-SDR, HackRF, USRP device passthrough
- GNU Radio from Source: Rebuild to remove NumPy 1.x restrictions
- OOT Modules: gr-satellites, gr-inspector, and more
- Educational Platform:
- Interactive API documentation as notebooks
- Coherent systems examples from textbooks
- Specialized constellation/communications plotting tools
- Extended Libraries: CommPy, scikit-rf, pyadi-iio for complete SDR toolkit
- Linux host (tested on Ubuntu)
- ~4GB disk space for Docker image
- Port 8888 available (or script will find another)
Before building the Docker image, install the following:
sudo apt update
sudo apt install python3-setuptoolsInstall Docker from Ubuntu repos (simpler for offline/local use):
sudo apt update
sudo apt install docker.io docker-composeAdd yourself to docker group:
sudo usermod -aG docker $USER
newgrp dockerStart Docker:
sudo systemctl start docker
sudo systemctl enable docker| Solution | Has Jupyter? | GNU Radio Works? | Conflict Resolution | Auto Templates | Container-ized | Size |
|---|---|---|---|---|---|---|
| This Project | β Full JupyterLab | β Via bridge | β Elegant venv isolation | β Yes! | β Docker | ~3.5GB |
| GNU Radio Docker | β No | β Yes | N/A | β No | β Docker | ~2GB |
| Radioconda | β Yes | β Yes | β No | β Conda env | ~6GB+ | |
| Arch AUR | β User problem | β Yes | β System conflicts | β No | β System pkg | Varies |
Unique Features of This Solution:
- solution that properly integrates Jupyter + GNU Radio without Conda
- Automatic notebook templates with GNU Radio setup (unique feature)
- Build verification ensures working images
- Multiple variants support (dev/test/prod)
- Optimized layer caching for fast rebuilds (~2 min for dependency changes)
-
Virtual Environment Isolation
/opt/venvcompletely isolated from system Python- NO
--system-site-packagesflag (would break pyzmq isolation) - GNU Radio accessed via explicit sys.path manipulation
-
NumPy 1.x Constraint
"numpy>=1.24,<2.0" # NEVER upgrade to 2.x - will break GNU Radio
- This cascades to constrain scipy, pandas, matplotlib versions
- Build verification ensures NumPy 1.x is maintained
-
Docker Layer Optimization
# Layers 1-5: Rarely change (cached) # Layer 6: Dependencies from pyproject.toml (rebuilds on change) # Layers 7-9: Always rebuild (fast)
Result: Dependency changes = ~2 minute rebuild, not 10+
-
User Permission Handling
- Container user (jovyan) maps to host UID/GID
- Build args passed:
USER_IDandGROUP_ID - All mounted volumes maintain correct permissions
/
βββ gnuradio_jupyter_docker_manager.sh # Main management script
βββ docker/
β βββ Dockerfile # Multi-stage optimized build
β βββ docker-compose.yml # Container orchestration
β βββ jupyter_template_system_config.py
β βββ docker_build_verification_tests.py
β βββ templates/
β βββ gnuradio_notebook_starter_template.json
βββ config/
β βββ pyproject.toml # Dependencies & notebook config
βββ notebooks/ # Your notebooks (persistent)
βββ flowgraphs/ # GNU Radio flowgraphs
βββ scripts/ # Python scripts
βββ data/ # Data files
# Standard build
./gnuradio_jupyter_docker_manager.sh build
# Clean rebuild (no cache)
./gnuradio_jupyter_docker_manager.sh rebuild
# Build specific variant
./gnuradio_jupyter_docker_manager.sh build dev# Start (finds available port automatically)
./gnuradio_jupyter_docker_manager.sh start
# Start specific variant on different port
./gnuradio_jupyter_docker_manager.sh start dev # Uses port 8889
# Stop container
./gnuradio_jupyter_docker_manager.sh stop
# View logs
./gnuradio_jupyter_docker_manager.sh logs -f
# Open shell in container
./gnuradio_jupyter_docker_manager.sh shell
# Check status
./gnuradio_jupyter_docker_manager.sh status# Quick GNU Radio test
./gnuradio_jupyter_docker_manager.sh test
# Comprehensive verification suite
./gnuradio_jupyter_docker_manager.sh verifyThe build includes automatic verification that tests:
- Python version compatibility
- NumPy 1.x enforcement
- GNU Radio functionality
- Jupyter installation
- Template system
- File permissions
Build fails if any test fails - ensuring only working images.
Every new notebook automatically includes:
- GNU Radio bridge configuration
- Essential imports (numpy, matplotlib, scipy)
- Helper functions for DSP
- Project configuration
- Example GNU Radio code
[tool.jupyter]
# Add custom imports
[tool.jupyter.imports]
signal_processing = [
"from scipy import signal",
"from scipy.fft import fft, fftfreq",
]
# Add configuration code
[tool.jupyter.code_cells]
code_cells = [
"""SAMPLE_RATE = 2.4e6 # Your project config"""
]No rebuild needed for template changes! Just edit and create new notebook.
-
NumPy Version Lock
# In config/pyproject.toml "numpy>=1.24,<2.0" # NEVER change to 2.x
GNU Radio is compiled against NumPy 1.x ABI. Using 2.x = immediate crashes.
-
Virtual Environment Isolation
# NEVER add --system-site-packages to venv creation RUN python3 -m venv /opt/venv # Keep it isolated
-
Dependency Version Constraints Due to NumPy 1.x requirement:
scipy>=1.10,<1.14pandas>=2.0,<2.2matplotlib>=3.5,<3.9ruff<0.5.0
-
SSHFS Mounts Don't Work
- Docker Compose fails with SSHFS-mounted directories
- Solution: Always run from local filesystem
- Error:
mkdir /path: file exists
-
Port Conflicts with Running Services
- Issue: Cannot start if VM or other Jupyter instance is using ports
- Behavior: Script automatically finds next available port, but may still conflict
- Solution: Stop conflicting services or manually specify different port
- Default ports: default=8888, dev=8889, test=8890
- Manual port override:
./gnuradio_jupyter_docker_manager.sh start default 9000
-
Limited Testing Environment
- Tested only on: Kubuntu 24.04 LTS
- Not tested on: Other Linux distributions, macOS, Windows (WSL)
- VM conflicts: Issues reported when running alongside VirtualBox VMs using same ports
-
Management Script Has Duplicate Functions
- The bash script has some duplicate function definitions
- Doesn't affect functionality but should be cleaned up
# Development environment (port 8889)
./gnuradio_jupyter_docker_manager.sh build dev
./gnuradio_jupyter_docker_manager.sh start dev
# Test environment (port 8890)
./gnuradio_jupyter_docker_manager.sh build test
./gnuradio_jupyter_docker_manager.sh start test
# Custom port
./gnuradio_jupyter_docker_manager.sh start default 9000Edit config/pyproject.toml:
dependencies = [
"numpy>=1.24,<2.0", # Keep this constraint!
"your-package>=1.0", # Add new packages here
]Then rebuild:
./gnuradio_jupyter_docker_manager.sh rebuild# GNU Radio is automatically available
from gnuradio import gr, blocks, analog
# Install additional packages at runtime
!pip install some-package
# Or use uv (faster)
!uv pip install some-packageCheck which test failed:
β NumPy version (2.0.1)
β GNU Radio requires NumPy 1.x, not 2.x
Verify the bridge is active:
docker exec gnuradio-notebook /opt/venv/bin/python -c \
"import sys; print('/usr/lib/python3/dist-packages' in sys.path)"# Check template system
./gnuradio_jupyter_docker_manager.sh template-info
# View logs
./gnuradio_jupyter_docker_manager.sh logs | grep -i templateThe container automatically maps to your user ID:
# This is handled automatically
docker-compose build --build-arg USER_ID=$(id -u) --build-arg GROUP_ID=$(id -g)- Image Size: ~3.5GB (includes GNU Radio, Jupyter, scientific stack)
- Build Time:
- First build: ~10 minutes
- Dependency change: ~2 minutes (cached layers)
- Template change: No rebuild needed
- Runtime Memory: ~1GB minimum, 4GB recommended
- CPU: Benefits from multiple cores for signal processing
# Backup all user data
./gnuradio_jupyter_docker_manager.sh backup
# Creates timestamped archive of:
# - notebooks/
# - flowgraphs/
# - scripts/
# - data/
# - config/gnuradio_jupyter_docker_manager.sh provides:
- Intelligent port management (auto-finds available ports)
- Variant support (dev, test, production)
- Build verification
- Backup/restore functionality
- Template system management
- System packages: GNU Radio from Ubuntu 24.04
- Virtual environment: Isolated Python environment
- Bridge setup: IPython startup script for GNU Radio access
- Template system: Automatic notebook initialization
- Verification: Comprehensive test suite
- Base template: GNU Radio setup, imports, helpers
- Project layer: Custom configuration from pyproject.toml
- Applied automatically to all new notebooks
- No rebuild needed for template changes
- Ubuntu: 24.04 LTS
- GNU Radio: 3.10.9.2
- Python: 3.12
- NumPy: 1.26.x (1.x required!)
- JupyterLab: 4.x
- Docker Compose: 3.8
Verified Environment:
- Host OS: Kubuntu 24.04 LTS
- Docker: 20.10+
- Architecture: x86_64
Known Limitations:
- Only tested on Kubuntu 24.04 - compatibility with other distributions not verified
- Port conflicts with VMs and existing Jupyter instances require manual resolution
- SSHFS mount directories are not supported
MIT License (or your chosen license)
This project was developed with significant technical assistance from Claude 4.1 Opus, which helped architect the virtual environment isolation strategy, resolve complex dependency conflicts, and implement the automatic notebook template system.