This directory contains comprehensive example scripts demonstrating how to use the pycd48 library for various physics experiments and applications.
Best starting point for new users!
An interactive Jupyter notebook that provides a comprehensive tutorial covering all major features of the pycd48 library.
Usage:
jupyter notebook pycd48_tutorial.ipynb
# or
jupyter lab pycd48_tutorial.ipynbWhat it includes:
- 📖 Introduction to the CD48 and its capabilities
- 🔌 Device connection and configuration
- 📊 Simple and continuous data collection
- 📈 Real-time data visualization with matplotlib
- 🧮 Statistical analysis and accidental coincidence calculations
- 🎛️ Advanced features (DAC control, overflow detection, data logging)
- 💡 Interactive code cells with detailed explanations
- 🎨 Publication-quality plots and visualizations
Perfect for:
- Learning the library interactively
- Experimenting with different configurations
- Teaching and educational demonstrations
- Rapid prototyping of experiments
- Creating custom analysis workflows
Prerequisites: Install Jupyter separately (pip install jupyter or uv pip install jupyter)
If you're new to the CD48, follow this recommended order:
- pycd48_tutorial.ipynb - Interactive tutorial (recommended start!)
- device_info.py - Verify your connection works
- simple_counting.py - Learn basic counting operations
- calibrate_trigger.py - Find optimal trigger levels for your detectors
- continuous_collection.py - Understand time-resolved measurements
- Then explore the advanced examples based on your application
Purpose: Test connection and display device information
Usage:
python device_info.pyWhat it does:
- Auto-detects and connects to the CD48
- Displays firmware version and device info
- Shows current configuration settings
- Lists all available commands
- Tests the LED indicators
Perfect for:
- First-time setup verification
- Troubleshooting connection issues
- Quick device health check
Duration: ~5 seconds
Purpose: Basic counting and coincidence measurement
Usage:
python simple_counting.pyWhat it does:
- Configures all 8 counters for various channel combinations
- Measures for 10 seconds with fixed trigger level
- Displays total counts and count rates for:
- Singles on all 4 input channels
- 2-fold coincidences (A-B, A-C, B-C)
- 3-fold coincidences (A-B-C)
- Shows overflow warnings if counters saturate
Perfect for:
- Learning basic data acquisition
- Verifying detector signals
- Quick signal quality check
Duration: ~10 seconds
Purpose: Time-resolved data collection with visualization
Usage:
python continuous_collection.pyWhat it does:
- Collects data continuously for 60 seconds (1-second intervals)
- Monitors channels A, B, and A-B coincidences
- Calculates comprehensive statistics (mean, std, accidental rate)
- Generates publication-quality plots:
- Time series of count rates
- Distribution histograms
- Estimates true vs accidental coincidences
- Saves results as
cd48_data.png
Perfect for:
- Monitoring detector stability over time
- Statistical analysis of count rates
- Understanding accidental coincidence corrections
- Preparing data for reports
Duration: ~60 seconds
Purpose: Cosmic ray muon detection with multi-detector telescope
Usage:
python cosmic_ray_telescope.pyWhat it does:
- Configures a vertical cosmic ray telescope with multiple detectors
- Measures singles on 4 detectors (top, middle, bottom, background)
- Counts 2-fold and 3-fold coincidences
- Calculates telescope efficiency
- Estimates muon flux (particles/m²·s)
- Performs accidental coincidence corrections
- Generates comprehensive analysis plots:
- Singles rates over time
- Coincidence rates with statistical uncertainty
- Rate distributions
- Correlation analysis
- Saves timestamped results
Perfect for:
- Cosmic ray physics experiments
- Educational muon lifetime measurements
- Multi-detector correlation studies
- Testing detector alignment and efficiency
Typical setup:
Detector A (top)
↓ muon path
Detector C (middle)
↓
Detector B (bottom)
Detector D (background, side)
Duration: ~5 minutes (configurable)
Purpose: Automatic trigger threshold calibration and optimization
Usage:
python calibrate_trigger.pyWhat it does:
- Scans trigger voltage from 0.1V to 2.0V in small steps
- Measures count rate at each threshold level
- Identifies the "knee" in the rate curve (noise threshold)
- Provides recommended trigger levels for each channel
- Generates diagnostic plots:
- Count rate vs trigger voltage (log scale)
- Normalized rates for easy comparison
- Marks optimal threshold points
- Saves results as
trigger_calibration.png
Perfect for:
- Finding optimal trigger levels for new detectors
- Characterizing detector noise levels
- Ensuring consistent thresholds across channels
- Troubleshooting low signal-to-noise ratio
Duration: ~1-2 minutes (depends on voltage range)
Tips:
- Run with detectors connected but no source for noise characterization
- Run with source present to find signal threshold
- Compare results between channels to match detector sensitivities
Purpose: Continuous data logging to CSV for long-term measurements
Usage:
python data_logger.pyWhat it does:
- Creates timestamped CSV files in
data/directory - Logs all 8 channels plus overflow flags continuously
- Supports indefinite runtime (Ctrl+C to stop)
- Provides real-time console display of key channels
- Flushes data to disk periodically (every 10 measurements)
- Handles graceful shutdown to prevent data loss
- Reports total measurements and file size on exit
CSV Format:
Timestamp, Elapsed_Time_s, Ch0_A_singles, Ch1_B_singles, ..., Overflow_Flag
2026-01-15 10:30:00.123, 0.000, 1234, 1189, ...
Perfect for:
- Long-term stability monitoring
- Overnight measurements
- Building large datasets for statistical analysis
- Continuous environmental monitoring
Duration: Continuous (until stopped)
Configurable parameters:
- Measurement interval (default: 1 second)
- Total duration (default: unlimited)
- Display update frequency
Purpose: Detailed analysis of true vs accidental coincidences
Usage:
python accidental_analysis.pyWhat it does:
- Collects 30 samples with 2-second integration each
- Analyzes singles and coincidence rates statistically
- Calculates expected accidental coincidence rates using:
- R_acc = 2 × τ × R_A × R_B (for 2-fold)
- R_acc ≈ 3 × τ × R_A × R_B × R_C (for 3-fold)
- Determines true coincidence rates
- Computes statistical significance (σ)
- Provides interpretation and warnings
- Generates comprehensive analysis plots:
- Time series of all rates
- Coincidence breakdown (measured/accidental/true)
- Distribution analysis
- Correlation plots (singles product vs coincidences)
- Saves results as
accidental_analysis.png
Perfect for:
- Verifying detector correlation
- Understanding systematic errors
- Quantum optics entanglement verification
- Nuclear correlation measurements
- Educational demonstrations
Duration: ~60 seconds (30 × 2s measurements)
Interpretation guide:
- Accidental fraction < 10%: Excellent, true coincidences dominate
- Accidental fraction 10-50%: Moderate, correction is important
- Accidental fraction > 50%: Poor, consider improving setup
- Significance > 5σ: Highly significant correlation
- Significance > 3σ: Significant correlation
- Significance < 3σ: Increase measurement time
Purpose: Real-time monitoring using automatic repeat mode
Usage:
python realtime_monitor.pyWhat it does:
- Enables CD48's automatic repeat mode
- Device sends count data at set intervals (e.g., every 1 second)
- Displays real-time data stream
- Reduces USB communication overhead
- No polling required - data pushed automatically from device
Perfect for:
- Real-time monitoring dashboards
- Continuous data streaming
- Reducing CPU usage during long measurements
- Synchronized data acquisition
Duration: Continuous (until stopped)
Key feature: Uses the r (set interval) and R (toggle) commands for automatic reporting
Purpose: Automated voltage sweep using DAC output
Usage:
python voltage_sweep.pyWhat it does:
- Sweeps DAC output voltage from 0-4V
- Measures count rates at each voltage
- Finds optimal operating voltage
- Calculates signal-to-noise ratio
- Generates comprehensive analysis plots:
- Count rates vs voltage
- Coincidence rate optimization
- S/N ratio analysis
- Total counts comparison
- Saves results as
voltage_sweep.png
Perfect for:
- PMT high voltage optimization
- Detector bias voltage scanning
- Automated equipment control
- Finding optimal operating points
- Experiment automation
Duration: Configurable (default ~1 minute for 20 points)
Key feature: Uses the V command to control external equipment via DAC output (0-4.08V)
Typical use case: Connect DAC output to PMT power supply control input to find optimal voltage for maximum coincidence rate
Purpose: Counter overflow detection and adaptive measurement
Usage:
python overflow_demo.pyWhat it does:
- Demonstrates counter overflow detection
- Decodes which specific counters overflowed
- Shows difference between 24-bit and 16-bit counters
- Implements adaptive interval adjustment
- Automatically reduces interval when approaching overflow
- Calculates safe measurement intervals for various count rates
- Provides best practices and recommendations
Perfect for:
- High count rate measurements
- Learning counter limitations
- Preventing data loss
- Understanding when to use which counter
Duration: ~30 seconds (configurable)
Key feature: Uses the E command to check and clear overflow flags
Important notes:
- Counters 0-6: 24-bit (max 16,777,215)
- Counter 7: 16-bit (max 65,535) - use for rare events only!
- At 1 MHz: Counter 7 overflows in 0.065 seconds!
Purpose: Run reproducible experiments from YAML configuration files
Usage:
uv sync --extra yaml # or: pip install -e ".[yaml]"
python run_yaml_experiment.py configs/simple_coincidence.yamlWhat it does:
- Loads experiment parameters from YAML (channels, trigger levels, measurement duration)
- Runs the experiment using
run_experiment()from the library - Prints structured results (counts, rates, coincidence statistics)
- Supports all configs in
configs/(coincidence, rate measurement, voltage sweep, etc.)
Perfect for:
- Reproducible experiment workflows
- Sharing experiment setups with collaborators
- Batch runs across multiple configurations
Prerequisites: uv sync --extra yaml or pip install -e ".[yaml]" (includes PyYAML and Pydantic)
See configs/README.md for YAML format details.
All examples can be easily modified for your experiment:
duration = 30 # Count for 30 seconds instead of 10interval = 0.5 # Sample every 0.5 secondswith CD48(port='/dev/ttyUSB0') as cd48: # Linux
# or
with CD48(port='COM3') as cd48: # Windowscd48.set_trigger_level(0.3) # Lower threshold for weaker signals
cd48.set_trigger_level(1.0) # Higher threshold to reduce noise# Example: 4-fold coincidence
cd48.set_channel(0, A=1, B=1, C=1, D=1) # Count A AND B AND C AND D- Start with
calibrate_trigger.pyto find optimal thresholds - Use
cosmic_ray_telescope.pyfor data collection - Switch to
data_logger.pyfor overnight runs - Analyze correlation with
accidental_analysis.py
- Verify detector signals with
simple_counting.py - Optimize thresholds with
calibrate_trigger.py - Use
accidental_analysis.pyto verify entanglement - Long measurements with
data_logger.py
- Check detector response with
device_info.py - Calibrate discriminators with
calibrate_trigger.py - Collect correlation data with
continuous_collection.py - Detailed analysis with
accidental_analysis.py
- Start with
device_info.pyfor student familiarization - Learn basics with
simple_counting.py - Demonstrate statistics with
continuous_collection.py - Teach coincidence corrections with
accidental_analysis.py
- Always start with device_info.py to verify the connection
- Use calibrate_trigger.py before any serious measurements
- Test with simple_counting.py before long runs
- Use data_logger.py for production measurements
- Trigger levels: Too low → noise, too high → miss events
- Measurement intervals: Shorter → better time resolution but more overhead
- Integration time: Longer → better statistics but less temporal detail
- Coincidence window: Fixed at ~25 ns for CD48
- Monitor overflow flags - they indicate counter saturation
- Check singles rates are stable before trusting coincidence data
- Use accidental_analysis.py to verify correlation is real
- Save raw data with data_logger.py for post-processing flexibility
Make sure pycd48 is installed:
cd ..
pip install -e .Try specifying the port manually:
# Linux
with CD48(port='/dev/ttyUSB0') as cd48:
...
# Windows
with CD48(port='COM3') as cd48:
...Add your user to the dialout group:
sudo usermod -a -G dialout $USER
# Then log out and log back in- Check trigger level (try calibrate_trigger.py)
- Verify input signals are connected
- Check impedance setting (50Ω for most detectors)
- Ensure detectors are powered
- Test with LED pulse if available
- Reduce measurement interval
- Use faster polling rate
- Check for very high count rates (>100 kHz)
- Increase threshold to reduce noise
- Check detector power supply stability
- Verify detector temperature is stable
- Look for environmental interference (RF, light leaks)
- Use longer integration times for averaging
- Run accidental_analysis.py to check correlation
- Verify detectors are actually seeing correlated events
- Check detector alignment for cosmic rays
- Consider cross-talk between channels
- Cosmic rays (sea level): ~1 muon/cm²/min ≈ 150/min for 10×10 cm detector
- Scintillator noise (typical): 100-1000 Hz (depends on threshold)
- Photomultiplier dark counts: 100-10,000 Hz (depends on PMT type)
- Maximum rate: ~1 MHz per channel (hardware limit)
- Coincidence window: ~25 ns (fixed, hardware)
- USB polling latency: ~1-50 ms (depends on OS)
- Minimum interval: ~100 ms (recommended)
- Maximum counter value: 16,777,215 (24-bit for ch 0-6)
- 1 hour @ 1 Hz: ~500 KB
- 24 hours @ 1 Hz: ~12 MB
- 1 week @ 1 Hz: ~85 MB
- CD48 Product Page - Hardware specifications
- Main README - Complete API documentation
- Red Dog Physics - Manufacturer website
Have an example you'd like to share? Please submit a pull request!
Good examples to add:
- Muon lifetime measurement analysis
- Quantum entanglement verification
- Multi-detector array calibration
- Advanced statistical analysis
- Real-time plotting with animation