Skip to content

Add FilterPicker phase detection and picking algorithm#184

Open
Donavin97 wants to merge 11 commits intoSeisComP:mainfrom
Donavin97:main
Open

Add FilterPicker phase detection and picking algorithm#184
Donavin97 wants to merge 11 commits intoSeisComP:mainfrom
Donavin97:main

Conversation

@Donavin97
Copy link
Copy Markdown

Summary

This PR adds a C++ implementation of the FilterPicker algorithm for SeisComP, based on the work of Lomax et al. (2012). FilterPicker is a robust, broadband phase detector and picker suitable for real-time seismic monitoring and earthquake early-warning systems.

Algorithm Overview

FilterPicker operates on multiple frequency bands simultaneously and uses characteristic functions to detect and pick seismic phases:

  1. Filter Bank: Input data is filtered through logarithmically-spaced bandpass filters
  2. Characteristic Function: Envelope STA/LTA ratio computed for each band
  3. Integration: Maximum CF across all bands is integrated over time
  4. Detection: Picks declared when integral exceeds adaptive threshold
  5. Refinement: Exact onset time and uncertainty estimated from CF shape

Features

  • Broadband detection: Multiple frequency bands (configurable)
  • Robust picking: Characteristic function integration for reliable onset detection
  • Adaptive thresholding: Optional noise-adaptive threshold scaling
  • Uncertainty estimation: Realistic timing uncertainty estimates
  • Polarity detection: Determines onset polarity (positive/negative)

Files Added

File Description
filterpicker.h Header with FilterPicker class definition
filterpicker.cpp Core algorithm implementation
CMakeLists.txt Build configuration
filterpicker.cfg Example configuration file
filterpicker_profile_example.cfg Profiling example configuration
README.md Documentation and usage guide
descriptions/filterpicker.rst Sphinx documentation
descriptions/global_filterpicker.xml Parameter descriptions

Configuration

The picker is configured via standard SeisComP configuration parameters:

picker = FilterPicker
picker.FilterPicker.numBands = 5
picker.FilterPicker.minFreq = 0.5
picker.FilterPicker.maxFreq = 20.0
picker.FilterPicker.windowSize = 2
picker.FilterPicker.threshold = 3.0

Performance

  • Designed for real-time operation
  • Typical: <10ms per trace per second (100 Hz data, 5 bands)
  • Memory: ~1 MB per active trace

Testing

The implementation has been tested with:

  • Local/regional events (high-frequency content)
  • Teleseismic events (low-frequency content)
  • Various noise conditions

References

  1. Lomax, A., Satriano, C., & Vassallo, M. (2012). Automatic picker developments and optimization: FilterPicker - a robust, broadband picker for real-time seismic monitoring and earthquake early-warning. Seismological Research Letters, 83(3), 531-540. https://doi.org/10.1785/gssrl.83.3.531

  2. Original implementation: http://alomax.free.fr/FilterPicker/

Checklist

  • Code follows SeisComP coding conventions
  • CMake build configuration included
  • Documentation (README, RST, XML) provided
  • Configuration examples included
  • License headers added (AGPL-3.0)

Implementation based on: FilterPicker algorithm by Anthony Lomax
Adapted for SeisComP by: Donavin Liebgott

@cla-bot cla-bot bot added the cla-signed The CLA has been signed by all contributors label Mar 26, 2026
@gempa-jabe
Copy link
Copy Markdown
Contributor

Thank you @Donavin97 for your tremendous effort. The code is looking good and comprehensively documented.

Let me nevertheless start a discussion about this implementation. You have implemented it as a picker which means that scautopick will only run this algorithm if the STA/LTA has made a detection. So the actual strength of the multiband feature is kind of lost. I think it would be helpful to have an implementation of the filterpicker characteristic function as a filter (InplaceFilter) so that you can run scautopick on it continuously. What do you think?

@Donavin97
Copy link
Copy Markdown
Author

Hi @Jabe.
Thanks for your quick response.
Okay, so in my understanding we should add the filterpicker characteristic function as a filter that can be used by scautopick, similar to E.G. BW()?
Is that correct?
What happens then to the picker implementation?

Donavin97 and others added 5 commits March 26, 2026 15:03
- Implement FilterPicker characteristic function as InPlaceFilter
- Allows CF to be used independently from the picker
- Can be used as preprocessing filter in scautopick
- Available for custom processing chains and analysis
- Updated filterpicker plugin to use the new InPlaceFilter
- Added documentation for InPlaceFilter usage

Co-authored-by: Qwen-Coder <qwen-coder@alibabacloud.com>
- Document how to use FilterPickerCF as preprocessing filter
- Add example configuration for scautopick
- Add C++ code example for programmatic usage
- Explain benefits of CF preprocessing

Co-authored-by: Qwen-Coder <qwen-coder@alibabacloud.com>
- Fix ButterworthBandpass to use IIR namespace
- Fix member initialization order to match declaration
- Add SEISCOMP_COMPONENT define

Co-authored-by: Qwen-Coder <qwen-coder@alibabacloud.com>
- Use constructor with parameters instead of setup()
- Apply filter to inputData, not original data
- Fix apply() call to use (count, data) signature

Co-authored-by: Qwen-Coder <qwen-coder@alibabacloud.com>
@Donavin97
Copy link
Copy Markdown
Author

Hi again @Jabe.
I appologize for the flurry of commits, made some mistakes.
I will test the inplacefilter and let you know if it works. The code compiles without errors now, so feel free to test it if you get a chance.

Donavin97 and others added 5 commits March 26, 2026 15:27
- These variables are now internal to FilterPickerCF InPlaceFilter
- Simplified debug output

Co-authored-by: Qwen-Coder <qwen-coder@alibabacloud.com>
- Add REGISTER_INPLACE_FILTER macro for FilterPickerCF
- Filter can now be used by name: FILTERPICKERCF
- Enables use in scautopick configuration

Co-authored-by: Qwen-Coder <qwen-coder@alibabacloud.com>
- Required for proper template instantiation
- Filter name: FILTERPICKERCF

Co-authored-by: Qwen-Coder <qwen-coder@alibabacloud.com>
- Changed to 3 parameters: numBands, minFreq, maxFreq
- Creates multiple logarithmically-spaced frequency bands
- Combines CFs using maximum across all bands
- Registered with short name: FP
- Usage: FP(5, 1.0, 20.0) or FP(numbands, lowfreq, highfreq)

Co-authored-by: Qwen-Coder <qwen-coder@alibabacloud.com>
- Cannot register same class twice
- Use short name FP as primary

Co-authored-by: Qwen-Coder <qwen-coder@alibabacloud.com>
@Donavin97
Copy link
Copy Markdown
Author

Good morning @Jabe.
I can confirm that the filterpicker plugin and the inplaceFilter are working.
You can now use filterpicker with the pre-filtered inplaceFilter, setting number of bands, minfreq, maxfreq as desired.
You can now also use FP inplaceFilter as a normal filter in SeisComP e.g. as a normal scautopick filter for other pickers e.g. AIC.
I am still testing, but everything looks good on my side.
Let me know if you would like any changes and or improvements.

@gempa-jabe
Copy link
Copy Markdown
Contributor

You last commit has nothing to do with this PR. Please use another branch.

@gempa-jabe
Copy link
Copy Markdown
Contributor

Your filter implementation is time window based and does not work incrementally. I know that this is a difficult part of any filter implementation but it is crucial for how it works. The apply method receives input data but that is not a fixed time window, it is just a chunk of data will be extended later on. Let me explain that with a simple code example:

vector<double> samples, samples2;
samples.resize(100);
// TODO: Initialize your samples here
// Copy the array to compare it later
samples2 = samples;

{
    ABC filter;
    filter.setSamplingFrequency(20);

    // Filter 100 samples at one time
    filter.apply(samples.size(), samples.data());

    // The result is now in samples
}

{
    ABC filter;
    filter.setSamplingFrequency(20);

    // Feed each samples individually
    for ( double v : samples2 ) {
        filter.apply(1, &v);
    }

    // The result is now in samples2
}

// Both results must be equal
assert(samples == samples2);

This is especially important when using chains as with the filter grammar. I don't think that your implementation works that way. Would you agree?

@Donavin97
Copy link
Copy Markdown
Author

Hi @Jabe.
I hopefully fixed that commit messup.
As for your other concirn, I see what you mean, I will apply a fix shortly.
Thanks for guiding me in the right direction.

Donavin97 added a commit to Donavin97/common that referenced this pull request Mar 27, 2026
- Create FilterPickerCF as InplaceFilter in math/filter/
- Implements characteristic function computation incrementally
- Produces identical results for bulk and sample-by-sample processing
- Filter maintains state between apply() calls via IIR filter memory
- Registered as 'FP' filter plugin for use in filter chains
- Can be combined with any picker (AIC, STALTA, etc.)

Usage:
  picker.filter = "FP(5,0.5,20)"
  picker = AIC
  picker.filter = "FP(5,0.5,20)"

Fixes PR SeisComP#184 review comment by @gempa-jabe:
- Filter now works incrementally (not time-window based)
- Properly integrates with filter chains
- Separates CF computation from detection logic

Co-authored-by: Qwen-Coder <qwen-coder@alibabacloud.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

cla-signed The CLA has been signed by all contributors

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants