Repository navigation
Peak Fitting and Background Models
The peak fitting algorithms, baseline estimation engines, and background decomposition methodologies implemented in python-cmat adhere to established analytical practices in high-resolution semiconductor
While ideal charge generation and preamplifier electronics produce symmetric Gaussian photopeaks, real High-Purity Germanium (HPGe) and Ge(Li) detectors exhibit low-energy tailing caused by:
- Incomplete Charge Collection & Hole Trapping: Lower drift mobility and radiation damage defect centers trap charge carriers before collection, attenuating pulse height.
- Ballistic Deficit: Charge collection rise times varying with interaction location, occasionally exceeding amplifier shaping times.
- Small-Angle Compton Scattering: Photons scattering in cryostat windows, dead layers, or target holders prior to full absorption.
python-cmat provides three analytical models for 1D projections and 2D coincidence peak fitting:
A pure Gaussian photopeak sitting on a linear baseline:
-
Net Peak Area:
$$A_{\text{net}} = \sqrt{2\pi} H \sigma \approx 2.5066 \cdot H \cdot \sigma$$ -
Full Width at Half Maximum (FWHM):
$$\text{FWHM} = 2\sqrt{2\ln 2} \sigma \approx 2.35482 \cdot \sigma$$ - Best For: Fast preliminary fits, well-shaped scintillation detector peaks (LaBr$_3$, NaI), or HPGe peaks with negligible trapping.
The classic formulation established in RadWare (gf3), SAMPO, and xtrackn (Helmer & Lee, 1980; Radford, 1995; Routti & Prussin, 1969). The exponential tail joins the Gaussian at
-
Net Peak Area:
$$A_{\text{net}} = H \sigma \left[ \sqrt{\frac{\pi}{2}}\left(1 + \text{erf}\left(\frac{\alpha}{\sqrt{2}}\right)\right) + \frac{1}{\alpha}\exp\left(-\frac{1}{2}\alpha^2\right) \right]$$ -
Parameters:
$\alpha > 0$ defines the tail join distance in units of$\sigma$ below centroid$\mu$ . - Best For: Standard HPGe spectroscopy with mild low-energy tailing.
The rigorous analytical formulation combining a symmetric Gaussian
where:
-
Parameters:
-
$H$ : Gaussian peak amplitude. -
$\mu, \sigma$ : Centroid and Gaussian dispersion width. -
$f_T$ : Integrated area of the convolved exponential tail. -
$\beta$ : Exponential decay slope length (channels). -
$A_S$ : Amplitude of the Compton step function.
-
-
Total Net Peak Area:
$$A_{\text{net}} = \sqrt{2\pi} H \sigma + f_T$$ - In 2D coincidence matrices, the true coincidence peak is evaluated as the 2D tensor product
$H \cdot P_X(x) \cdot P_Y(y)$ with total net volume:$$V_{\text{fit}} = H (\sqrt{2\pi}\sigma_x + \eta_{Tx})(\sqrt{2\pi}\sigma_y + \eta_{Ty})$$
In multichannel analyzer (MCA/ADC) spectroscopy and the standard GASPware / xtrackn suite, an integer histogram bin
python-cmat strictly adheres to this Fortran xtrackn convention ("al centro del canale", src/xtrack/trackn.F):
- All 1D and 2D continuous peak fitting routines evaluate analytical models on bin centers (
$x_i = k + 0.5, y_j = l + 0.5$ ). - Calibrated peak energies
$E(\mu) = a_0 + a_1 \mu + a_2 \mu^2$ are evaluated directly at the continuous centroid$\mu$ , guaranteeing exact 1:1 energy calibration agreement withxtrackn. - Peak curves and centroid marker stems naturally align with the exact center of histogram bins on both browser canvases and vector PDF exports.
In 2D
-
$p|p^t$ (True Net Coincidence Peak): Genuine correlated full-energy cascade events ($E_d \otimes E_f$ ), modeled as a 2D peak profile$H \cdot P_X(x) \cdot P_Y(y)$ . -
$p|bg$ (Det 1 Peak with Det 2 Continuum / Random Ridge): Full energy in Det 1 ($E_d$ ) and Compton continuum (or randoms) in Det 2$\rightarrow$ forms a vertical cross-ridge$R_x \cdot P_X(x)$ . -
$bg|p$ (Det 2 Peak with Det 1 Continuum / Random Ridge): Full energy in Det 2 ($E_f$ ) and Compton continuum (or randoms) in Det 1$\rightarrow$ forms a horizontal cross-ridge$R_y \cdot P_Y(y)$ . -
$bg|bg$ (2D Compton Continuum & Accidental Coincidences): Compton continuum and time-uncorrelated random coincidences in both detectors$\rightarrow$ modeled as a 2D planar baseline$b_0 + b_x(x - x_c) + b_y(y - y_c)$ .
Because accidental (time-uncorrelated) coincidences naturally distribute into the exact same topological structures (FEP–Random into ridges, Compton–Random into continuum, Random–Random into the local plane), no arbitrary user-tuned random fraction is required.
The 2D fitting engine extracts all parameters simultaneously via Levenberg-Marquardt optimization with Poisson statistical weights (
and the Peak-to-Total-Background ratio:
When analyzing 3D matrix volumes (e.g. cmat3d_webviewer.py, fitting a 2D coincidence peak on any orthogonal plane automatically performs discrete Gamba background decomposition on the 3rd axis (
The 3D volume is sliced over the 2D Peak (
- $\text{Spec}{P|P}(z) = \sum{(x,y) \in \text{ROI}_{P|P}} V(x, y, z)$
- $\text{Spec}{P|BG}(z) = \sum{(x,y) \in \text{ROI}_{P|BG}} V(x, y, z)$
- $\text{Spec}{BG|P}(z) = \sum{(x,y) \in \text{ROI}_{BG|P}} V(x, y, z)$
- $\text{Spec}{BG|BG}(z) = \sum{(x,y) \in \text{ROI}_{BG|BG}} V(x, y, z)$
The net coincidence spectrum on the 3rd axis is constructed using the discrete Gamba formula:
This cleanly eliminates both Compton ridges and time-uncorrelated random events from the 3rd-axis projection, providing pure net lifetime curves or detector ring distributions.
Following the classic GASPware xtrackn gate methodology:
-
Peak Gate Windows (
$W$ ): Arbitrary consecutive peak windows ${ [W_{k,\min}, W_{k,\max}] }{k=1}^K$ defined usingW. Total peak width: $$\Delta W{\text{tot}} = \sum_{k=1}^K (W_{k,\max} - W_{k,\min} + 1)$$ -
Background Gate Windows (
$X$ ): Arbitrary consecutive background windows ${ [X_{m,\min}, X_{m,\max}] }{m=1}^M$ defined usingX. Total background width: $$\Delta X{\text{tot}} = \sum_{m=1}^M (X_{m,\max} - X_{m,\min} + 1)$$ -
Coincidence Slicing: Slicing matrix
$M$ along the gated axis produces 1D projection vectors:$$S_{W_k}(i) = \sum_{j = W_{k,\min}}^{W_{k,\max}} M_{i, j}, \quad S_{X_m}(i) = \sum_{j = X_{m,\min}}^{X_{m,\max}} M_{i, j}$$ -
Normalized Background Subtraction: When background regions are present (
$\Delta X_{\text{tot}} > 0$ ), the net coincidence spectrum$S_{\text{net}}$ is:$$\text{Scale} = \frac{\Delta W_{\text{tot}}}{\Delta X_{\text{tot}}}$$ $$S_{\text{net}}(i) = \sum_{k=1}^K S_{W_k}(i) - \text{Scale} \cdot \sum_{m=1}^M S_{X_m}(i)$$ -
Visual Overlays & Negative Baseline:
- Gated peak windows render in translucent green (
#22c55e30), background in amber (#f59e0b30). - The 2D matrix renders matching vertical/horizontal band overlays across gated channels.
- A dashed zero-baseline is drawn on the gated 1D projection when over-subtracted continuum channels fluctuate below zero counts.
- Gated peak windows render in translucent green (
Automated peak finding in python-cmat implements Continuous Wavelet Transform (CWT) multi-scale peak detection (Du et al., 2006):
Because
Wavelet coefficients
Pressing H (or clicking Fit All [H]) executes automated multi-peak fitting across all visible candidate photopeaks on display. The continuum baseline is estimated using a Peak-Aware Continuum Average engine designed specifically to handle both high-statistics projections and low-statistics / coincidence-gated spectra without noise-clipping bias:
Standard morphological baseline filters like plain SNIP rely on concave lower-envelope clipping ($v_i = \min(v_i, \frac{v_{i-p} + v_{i+p}}{2})$). In low-statistics spectra or background-subtracted coincidence cuts (
Because the peak search routine (P) has already identified candidate photopeaks, channels outside the candidate peak clusters are known a priori to be pure continuum:
-
Peak Exclusion Masking:
$$\text{ROI}_{\text{cl}} = \left[ \min(\text{cluster}) - 2.0 \times \text{FWHM}, \ \max(\text{cluster}) + 2.0 \times \text{FWHM} \right]$$ -
Continuum Rolling Average: Across pure background channels (
$\mathbb{E}[\epsilon_i] = 0$ ), the continuum is smoothed using a rolling Bartlett filter with window$W \approx 5.0 \times \text{FWHM}$ . This estimates the central expectation value ($\bar{y}$ ) directly through the center of the noise grass ($< 0.1$ count bias), with full tolerance for negative count bins. - Cluster Baseline Bridging: Across each peak cluster, the baseline connects the smoothed left continuum to the smoothed right continuum linearly without clipping or artificial bowing.
- Dense Forest Fallback: If peak coverage exceeds 92% of the display window, the engine automatically falls back to SNIP.
Adjacent peaks separated by
-
G: Snaps to the local peak summit within$\pm 2$ channels and computes parabolic sub-channel centroid refinement ($\delta = \frac{1}{2} \frac{y_0 - y_2}{y_0 - 2y_1 + y_2}$ ). Hovering an existing marker within 1.2 channels deletes it. -
V: PressingVanywhere within a multiplet cluster automatically fits all components simultaneously with full parameter covariance error propagation.
Pressing R twice sets left and right region limits V inside the region fits all peaks within the boundary on top of this straight-line background.
To streamline spectroscopic reporting and automate data export for external calibration programs, python-cmat supports real-time appending of all 1D and 2D peak fit results to a clean, fixed-width text log.
To ensure clean vertical alignment across text editors and avoid tab misalignment for large peak counts (10+ digits with uncertainties), columns are right-aligned with fixed character widths:
-
1D Fits:
# 1D Fits: Energy(err) Net_Area(err) FWHM(err) Chi2 Peak_to_BG 1164.257(0.003) 339769.5(735.4) 3.060(0.006) 144.37 5.84 1164.76(0.00) 339769.5(735.4) 3.06(0.01) 144.37 5.84(Energy and FWHM display in keV when calibrated or channels when uncalibrated).
-
2D Coincidence Fits (Gamba Decomposition):
# 2D Fits: Energy1(err) Energy2(err) Net_Area(err) Gamba_Area(err) FWHM1(err) FWHM2(err) Chi2 Peak_to_BG 1164.215(0.052) 1345.264(99.304) 32.8(9123.4) 25.6(16.1) 3.002(0.110) 0.636(119.698) 1.23 0.01 1164.71(0.05) 1345.76(99.30) 32.8(9123.4) 25.6(16.1) 3.00(0.11) 0.64(119.70) 1.23 0.01
-
Web Viewer GUI: Click
ON / OFFtoggle in the sidebar Peak Fitting control group or set a custom filename. -
CLI Startup Flag:
python3 cmat_webviewer.py --fit-log [filename] matrix.cmat -
Headless Shell / Macro:
fit_log on [filename],fit_log off,fit_log status -
Default Filename: If no filename is specified, an automatic timestamped file (
fit_results_YYYYMMDD_HHMMSS.txt) is generated to prevent overwriting previous analyses.
Fit results logs can be automatically analyzed and matched against evaluated nuclear structure data to identify parent isotopes and 2D cascades using the ENSDF Isotope Identification tool.
Detecting true physical
-
Compton Scattering Cross-Ridges (
$p|bg$ and$bg|p$ ): A high-intensity photopeak in Det 1 coincident with a continuous Compton scattering event in Det 2 creates a continuous vertical line across the entire matrix. Any noise fluctuation along this ridge resembles a 2D peak. -
Detector Cross-Talk & Scattering Artifacts: Single gamma rays scattering from one detector into another produce diagonal ridges (
$\rho_{xy} \approx -1, x + y = \text{const}$ ).
python-cmat implements a dedicated 4-stage hybrid 2D search engine to discriminate genuine coincidences:
Continuous Wavelet Transform (CWT) peak searches are executed across both 1D total projections (Det 1 and Det 2) down to a user-selectable signal-to-noise ratio threshold (
For each candidate pair
Candidate peaks are subjected to physical validation filters:
-
Gamba Ratio Filter: The peak-to-total-background ratio
$\Pi = n_{p|p}^t / n_{p|p}^m$ must exceed the user-defined threshold ($\Pi_{\text{min}}$ , default$0.05$ ). Pure Compton ridges have$n_{p|p}^t \approx 0 \implies \Pi \approx 0$ and are cleanly rejected. -
Statistical Significance: The net peak height
$H$ must exceed $\text{SNR}{\text{threshold}} \cdot \sqrt{\max(1, B{\text{local}}})$. -
Covariance Ellipse Filter: The 2D cross-correlation coefficient
$|\rho_{xy}| < 0.85$ rejects diagonal scattering cross-talk. -
Width Bounding: Fitted dispersions must satisfy physical detector bounds (
$0.4 \times \text{FWHM}_0 \le \text{FWHM} \le 3.5 \times \text{FWHM}_0$ ).
Surviving candidates are clustered within
In fast-timing nuclear spectroscopy (e.g. LaBr$_3$(Ce) scintillators, BaF$2$, TAC, TDC, or digital CFD timestamp time-difference $\Delta T$ matrices), nuclear level half-lives ($T{1/2}$) are extracted by convolving the instrumental prompt response function (IRF) with the physical exponential decay.
The combined model convolves a Gaussian prompt response (representing the instrument time resolution with dispersion
Where:
-
$\lambda = \frac{\ln 2}{T_{1/2}}$ is the decay constant ($\text{ch}^{-1}$ ). - For positive half-lives (
$T_{1/2} > 0$ , right-sided decay tail$x > x_0$ ):$$F(x) = \text{BG} + \frac{A}{2} \exp\left( \frac{\sigma_g^2 \lambda^2}{2} - \lambda(x - x_0) \right) \text{erfc}\left( \frac{\sigma_g \lambda - (x - x_0)/\sigma_g}{\sqrt{2}} \right)$$ - For negative half-lives (
$T_{1/2} < 0$ , inverted / left-sided decay tail$x < x_0$ ):$$F(x) = \text{BG} + \frac{A}{2} \exp\left( \frac{\sigma_g^2 \lambda^2}{2} + \lambda(x - x_0) \right) \text{erfc}\left( \frac{\sigma_g \lambda + (x - x_0)/\sigma_g}{\sqrt{2}} \right)$$ - For prompt-only resolution calibration (
$T_{1/2} = 0$ ):$$F(x) = \text{BG} + A \exp\left(-\frac{(x - x_0)^2}{2\sigma_g^2}\right)$$ - For pure exponential decay without prompt broadening (
$\text{FWHM} = 0$ ):$$F(x) = \text{BG} + A \exp(-\lambda |x - x_0|) \cdot \Theta(\pm(x - x_0))$$
Direct evaluation of python-cmat implements numerically stable evaluation using scipy.special.erfcx:
For deep tail regions (
Because the background offset and exponential decay slope can exhibit strong mathematical covariance in truncated fit ranges, halflife.py provides automated
- Fix background to a sequence of values
$B_k \in [B_{\text{min}}, B_{\text{max}}]$ . - Perform bounded Levenberg-Marquardt / Trust Region Reflective optimization over free parameters
$(T_{1/2}, \text{FWHM}, x_0, A)$ . - Record
$\chi^2(B_k)$ and locate the global parabolic minimum$\chi^2_{\text{min}}$ . - Calculate
$1\sigma$ confidence limits from the profile crossing points$\chi^2(B) = \chi^2_{\text{min}} + 1.0$ .
For coincidence-gated time spectra
python-cmat © 2026. Released under the MIT License. Return to GitHub Repository
Interactive 2D & 3D Matrix Analysis & Spectroscopy
- Home
- Interactive Web Viewer
- 3D Matrix Analysis & Web Viewer
- Keyboard Shortcuts & Controls
- ROOT Files & Live Histograms
- ENSDF Isotope Identification
- Spectroscopy Commands & Macros
- Configuration Guide
- Python API & CLI Tools