Skip to content

Add common_mode_correction and subtract_polynomial_background steps#103

Merged
lg345 merged 1 commit into
masterfrom
feature/detector-common-mode-and-bkgsub
Jul 17, 2026
Merged

Add common_mode_correction and subtract_polynomial_background steps#103
lg345 merged 1 commit into
masterfrom
feature/detector-common-mode-and-bkgsub

Conversation

@lg345

@lg345 lg345 commented Jul 17, 2026

Copy link
Copy Markdown
Owner

Implements the two steps from #102.

What changed

  • common_mode_correction (XSpect/analysis/spectroscopy.py): subtracts a per-row, per-column, or per-bank electronic baseline estimated from a signal-free reference band. Runs on 3D detector data (shots x rows x cols) before shot reduction; also handles 2D. Preserves input shape. method is median (default) or mean; axis is row/column/bank; bank_size defaults to 128 (ePix100).
  • subtract_polynomial_background (same file): fits a low-order polynomial to signal-free regions along the spatial axis and subtracts it. Non-destructive, writes <key>_bkgsub. Fit regions named either by background ranges or by excluding peak_mask. peak_mask takes a single range or a list of ranges, so multiple emission lines on one detector can be masked at once. Per-row weighting drops NaNs from each row's fit and leaves them NaN in the output. Reuses the vectorized weighted-polyfit (Vandermonde + batched normal-equation solve) from patch_pixels.

Reviewer notes

  • The polynomial fit is a batched weighted least squares (einsum to build per-row normal equations, np.linalg.solve over the batch). The batch dimension is small (order+1 = 2-3), so cost is dominated by the data-sized einsum, same order as the single-solve version.
  • common_mode_correction was placed in the Shot Filtering table; subtract_polynomial_background in the XES-Specific table.

How to test

pytest tests/test_spectroscopy_steps.py -q

31 passing (7 common-mode, 8 background-subtraction, rest pre-existing). The 11 failures in the full suite (batch_manager, xas, regression) are pre-existing on master and unrelated to this change.

Closes #102

common_mode_correction subtracts per-row, per-column, or per-bank
electronic baseline estimated from a signal-free reference band, on 3D
detector data before shot reduction, preserving shape.

subtract_polynomial_background fits a low-order polynomial to signal-free
regions along the spatial axis and subtracts it, writing a non-destructive
<key>_bkgsub. peak_mask accepts multiple ranges so several emission lines
dispersed on one detector can be masked at once. Per-row weighting excludes
NaNs from the fit. Reuses the vectorized weighted-polyfit approach from
patch_pixels.

Adds unit tests for both steps and documents them in the YAML guide and
README step lists.

Closes #102
Copilot AI review requested due to automatic review settings July 17, 2026 06:42
@lg345
lg345 merged commit 3bdc04a into master Jul 17, 2026
1 check passed
@lg345
lg345 deleted the feature/detector-common-mode-and-bkgsub branch July 17, 2026 06:42

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Adds two new, registered spectroscopy pipeline steps to support detector baseline correction and spatial polynomial background subtraction (Issue #102), along with documentation and unit tests so they can be configured via YAML and verified in isolation.

Changes:

  • Added common_mode_correction step to subtract per-row/column/bank common-mode offsets using a signal-free reference band.
  • Added subtract_polynomial_background step to fit/subtract a low-order polynomial baseline along a spatial axis, writing <on>_bkgsub and supporting multi-range peak masking.
  • Extended docs/README step listings and added unit tests covering key behaviors and edge cases.

Reviewed changes

Copilot reviewed 4 out of 4 changed files in this pull request and generated 5 comments.

File Description
XSpect/analysis/spectroscopy.py Implements the two new registered steps (common_mode_correction, subtract_polynomial_background).
tests/test_spectroscopy_steps.py Adds unit tests validating correctness, shape preservation, NaN handling, and non-destructive output behavior.
README.md Updates the “Registered steps” list to include the two new steps.
docs/YAML_PIPELINE_GUIDE.md Documents the new steps, their parameters, and YAML configuration examples.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

)
return

reducer = np.nanmedian if method == "median" else np.nanmean
band = working
n_cols = working.shape[2]
corrected = working.copy()
for start in range(0, n_cols, bank_size):
Comment on lines +280 to +283
Works on a 1D spectrum or a 2D array (bins x pixels). The fit reuses the
vectorized weighted-polynomial projection from patch_pixels: the offset
vector depends only on the sample positions and weights, so it is built
once and applied to every row with a single matrix multiply.
Comment on lines +319 to +323
if background is not None:
weights[:] = 0.0
for rng in background:
weights[rng[0] : rng[1]] = 1.0
elif peak_mask is not None:
Comment on lines +352 to +356
# A[r] = V^T diag(w_r) V ; b[r] = V^T diag(w_r) flat_r, batched over rows r.
A = np.einsum("pk,pr,pl->rkl", V, w_full, V) # (N_rows, order+1, order+1)
b = np.einsum("pk,pr->rk", V, w_full * flat) # (N_rows, order+1)
coeffs = np.linalg.solve(A, b) # (N_rows, order+1)
baseline = (V @ coeffs.T) # (n_pixels, N_rows)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Add detector common-mode correction and polynomial spatial background subtraction steps

3 participants