Skip to content

Pre-smoothing spectral SNR mask to suppress noise-dominated low-frequency bins#83

Open
Riviss wants to merge 6 commits intoSeismicSource:mainfrom
Riviss:snr-mask-feature
Open

Pre-smoothing spectral SNR mask to suppress noise-dominated low-frequency bins#83
Riviss wants to merge 6 commits intoSeismicSource:mainfrom
Riviss:snr-mask-feature

Conversation

@Riviss
Copy link

@Riviss Riviss commented Feb 10, 2026

Summary

Adds an optional pre-smoothing spectral SNR mask that clamps noise-dominated low-frequency bins before log-frequency smoothing, preventing the smoothing kernel from bleeding high noise amplitudes into the usable frequency band.

Problem

When the spectral smoothing kernel encounters bins where noise exceeds the signal (common at low frequencies), it spreads those high noise values into neighboring bins. This contaminates the frequency band used for spectral fitting and can bias the corner frequency and moment estimates. We encountered this systematically while processing induced seismicity in northeastern British Columbia, where cultural and industrial noise dominates the low-frequency band.

Solution

A configurable SNR mask is applied between spectrum computation and smoothing:

  • RSS-based masking: The mask is determined on the root-sum-of-squares spectrum across components, then propagated to each individual component. This is more robust than per-component masking.
  • Two modes: left_of_first (default) finds the first frequency where SNR >= threshold and clamps all lower bins; binary clamps every sub-threshold bin.
  • Optional cosine ramp to avoid a hard spectral step at the crossover frequency.
  • Configurable frequency range (spectral_snr_mask_freq_range) to constrain the search band.

New configuration parameters

Parameter Type Description
spectral_snr_mask_threshold float SNR threshold; 0 or unset disables the mask
spectral_snr_mask_mode string left_of_first (default) or binary
spectral_snr_mask_ramp_decades float Width of the cosine ramp in decades
spectral_snr_mask_freq_range float list [min_freq, max_freq] in Hz

Visualization

  • Dashed vertical line at the SNR crossover frequency on spectral plots
  • Shaded region showing the ramp band
  • Text annotation with mask parameters and crossover frequency

Files changed

  • sourcespec/ssp_build_spectra.py - core mask logic, RSS application, deferred smoothing
  • sourcespec/ssp_plot_spectra.py - mask indicator visualization
  • sourcespec/config_files/configspec.conf - new config parameters
  • MANIFEST.in - include all Python modules in sdist (minor packaging fix)

Notes

  • The mask is disabled by default (threshold unset); existing behavior is completely unchanged
  • No new dependencies
  • Developed for induced seismicity analysis in northeastern British Columbia (Montney Play) where low-frequency cultural noise is common

@Riviss Riviss changed the title Pre-smoothing spectral SNR mask Pre-smoothing spectral SNR mask to suppress noise-dominated low-frequency bins Feb 10, 2026
@claudiodsf
Copy link
Member

Hi @Riviss, thank you very much for this PR!

It looks very well-structured, and my standard test cases all still work.

I'll make a detailed review in the following days.

In the meanwhile, please add a CHANGELOG entry.
Also, please consider adding your name to CONTRIBUTORS.txt

Thanks!

@claudiodsf
Copy link
Member

Hi again @Riviss,

I would like to push some changes to your branch https://github.com/Riviss/sourcespec/tree/snr-mask-feature, but it looks like your repository is now archived and read-only.

Could you please "unarchive" it? Thanks!

include docs/*
include imgs/*
# Explicitly include all Python modules so new files are picked up
recursive-include sourcespec *.py
Copy link
Member

Choose a reason for hiding this comment

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

Confused on why you need this, since there are already the following lines in pyproject.toml:

[tool.setuptools.packages.find]
include = ["sourcespec", "sourcespec.*"]

Could you tell me more about the problem you encountered?

f_ramp_start, f_cross, color='#CC9933', alpha=0.12, zorder=2)


def _plot_event_moment_line(spec, ax, ax2):
Copy link
Member

Choose a reason for hiding this comment

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

This function is not technically part of this PR, yet it's interesting 😉 .
Maybe we should add a config parameter to enable it?

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.

2 participants