Source code for adctoolbox.toolset.generate_dout_dashboard

"""Generate DOUT analysis dashboard with 6 analysis plots in a 2x3 panel."""

import numpy as np
import matplotlib.pyplot as plt
from pathlib import Path

from adctoolbox.spectrum import analyze_spectrum
from adctoolbox.calibration import calibrate_weight_sine
from adctoolbox.dout import analyze_bit_activity
from adctoolbox.dout import analyze_overflow
from adctoolbox.dout import analyze_enob_sweep
from adctoolbox.dout import analyze_weight_radix

[docs] def generate_dout_dashboard(bits, freq=None, weights=None, output_path=None, show=False): """ Generate comprehensive digital analysis dashboard with 6 subplots in a 2x3 panel. Parameters ---------- bits : array_like Digital bits (N samples x B bits, MSB to LSB order) freq : float, optional Normalized frequency (0-0.5). If None, auto-detect from calibration weights : array_like, optional Nominal weights for bits (default: None, uses binary weights) output_path : str or Path, optional Path to save figure (default: None, don't save) show : bool, optional Whether to display figure (default: False) Returns ------- fig : matplotlib.figure.Figure Figure object containing the dashboard axes : ndarray Array of axes objects (2x3 grid, flattened) """ bits = np.asarray(bits) n_samples, n_bits = bits.shape # Use binary weights if not specified if weights is None: weights = 2.0 ** np.arange(n_bits - 1, -1, -1) else: weights = np.asarray(weights) # Create 2x3 panel fig, axes = plt.subplots(2, 3, figsize=(24, 12)) axes = axes.flatten() # Perform calibration once for all tools result = calibrate_weight_sine(bits, freq=freq) weights_calibrated = result['weight'] freq_refined = result['refined_frequency'] # Plot 1: Spectrum with nominal weights plt.sca(axes[0]) signal_nominal = bits @ weights analyze_spectrum(signal_nominal, create_plot=True) axes[0].set_title('(1) Spectrum: Nominal Weights', fontsize=14) # Plot 2: Spectrum after calibration plt.sca(axes[1]) signal_calibrated = result['calibrated_signal'] analyze_spectrum(signal_calibrated, create_plot=True) axes[1].set_title('(2) Spectrum: Calibrated Weights', fontsize=14) # Plot 3: Bit Activity plt.sca(axes[2]) analyze_bit_activity(bits, create_plot=True, ax=axes[2]) axes[2].set_title('(3) Bit Activity', fontsize=14) # Plot 4: Overflow Check plt.sca(axes[3]) analyze_overflow(bits, weights_calibrated, create_plot=True, ax=axes[3]) axes[3].set_title('(4) Overflow Check', fontsize=14) # Plot 5: ENOB Sweep plt.sca(axes[4]) analyze_enob_sweep(bits, freq=freq_refined, create_plot=True, ax=axes[4], verbose=False) axes[4].set_title('(5) ENOB Bit Sweep', fontsize=14) # Plot 6: Weight Radix plt.sca(axes[5]) analyze_weight_radix(weights_calibrated, create_plot=True, ax=axes[5]) axes[5].set_title('(6) Weight Radix', fontsize=14) plt.tight_layout() # Save if requested if output_path is not None: output_path = Path(output_path) output_path.parent.mkdir(parents=True, exist_ok=True) fig.savefig(output_path, dpi=150, bbox_inches='tight') print(f"[Dashboard saved] -> {output_path}") if not show: plt.close(fig) if show: plt.show() return fig, axes