Metadata-Version: 2.4
Name: ae-picker
Version: 0.2.1
Summary: First-arrival time picking for acoustic emission and microseismic waveforms
Author-email: Daniel Wamriew <wamriewdan@gmail.com>
License: MIT License
        
        Copyright (c) 2026 Daniel Wamriew
        
        Permission is hereby granted, free of charge, to any person obtaining a copy
        of this software and associated documentation files (the "Software"), to deal
        in the Software without restriction, including without limitation the rights
        to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
        copies of the Software, and to permit persons to whom the Software is
        furnished to do so, subject to the following conditions:
        
        The above copyright notice and this permission notice shall be included in all
        copies or substantial portions of the Software.
        
        THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
        IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
        FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
        AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
        LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
        OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
        SOFTWARE.
        
Project-URL: Homepage, https://github.com/wamriewdan/ae_arrival_picker
Project-URL: Repository, https://github.com/wamriewdan/ae_arrival_picker
Project-URL: Issues, https://github.com/wamriewdan/ae_arrival_picker/issues
Keywords: acoustic emission,microseismic,signal processing,arrival picking,seismology
Classifier: Development Status :: 3 - Alpha
Classifier: Intended Audience :: Science/Research
Classifier: License :: OSI Approved :: MIT License
Classifier: Operating System :: OS Independent
Classifier: Programming Language :: Python :: 3
Classifier: Programming Language :: Python :: 3.9
Classifier: Programming Language :: Python :: 3.10
Classifier: Programming Language :: Python :: 3.11
Classifier: Programming Language :: Python :: 3.12
Classifier: Topic :: Scientific/Engineering
Classifier: Topic :: Scientific/Engineering :: Information Analysis
Requires-Python: >=3.9
Description-Content-Type: text/markdown
License-File: LICENSE
Requires-Dist: matplotlib>=3.7
Requires-Dist: numpy>=1.24
Requires-Dist: pandas>=1.5
Requires-Dist: scipy>=1.10
Provides-Extra: dev
Requires-Dist: build; extra == "dev"
Requires-Dist: jupyter; extra == "dev"
Requires-Dist: nbconvert; extra == "dev"
Requires-Dist: twine; extra == "dev"
Provides-Extra: obspy
Requires-Dist: obspy; extra == "obspy"
Dynamic: license-file

# ae-picker

`ae-picker` is a Python package for automatic first-arrival time picking in
acoustic emission (AE) and microseismic waveform data.

It includes waveform readers, multiple picking algorithms, batch processing,
and plotting helpers for review and comparison.

## Algorithm notes

### AIC picker

The AIC picker treats the waveform as two segments split at sample `k` and
selects the split that minimizes the Akaike Information Criterion:

```text
AIC(k) = k * log(var(x[0:k])) + (N - k - 1) * log(var(x[k+1:N]))
```

Short explanation:

- Before the arrival, the signal is assumed to behave like background noise.
- After the arrival, the variance changes because the waveform contains the
  first motion and subsequent energy.
- The best onset is the sample where this two-segment model fits best.

### Refined STA/LTA picker

The refined STA/LTA picker in this package is a two-stage method:

1. A recursive STA/LTA trigger finds a coarse onset window.
2. A Hilbert-envelope refinement step walks back to the earliest persistent
   onset inside that window.

The STA/LTA trigger is based on the ratio

```text
CFT(i) = STA(i) / LTA(i)
```

where the fallback implementation in this package uses

```text
STA(i) = mean(|x[i-nsta:i]|)
LTA(i) = mean(|x[i-nlta:i]|)
```

and triggers when `CFT(i)` rises above the on-threshold and ends when it falls
below the off-threshold.

The envelope-refinement stage uses the analytic-signal envelope

```text
e(i) = |H{x}(i)|
```

and robust noise statistics

```text
sigma ~= 1.4826 * MAD(e_noise)
thr_high = median(e_noise) + k_high * sigma
thr_low  = median(e_noise) + k_low  * sigma
```

Short explanation:

- STA/LTA provides a stable first trigger for emergent arrivals.
- The envelope stage then refines that trigger by requiring a persistent rise
  above a lower threshold, which improves onset timing.
- In this repository, the "refined STA/LTA" picker is this package-specific
  combination of recursive STA/LTA and envelope-based onset refinement.


## Plotting

### `plot_sta_lta_overlay` — STA/LTA diagnostic plot

Produces a three-panel figure for diagnosing the STA/LTA picker on a single
channel:

1. **Waveform** — raw amplitude time series.
2. **STA & LTA envelopes** — centered moving averages of `|amp|` showing how
   the short- and long-term averages evolve around the arrival.
3. **STA/LTA characteristic function** — the recursive ratio with trigger-on
   and trigger-off threshold lines, and optional onset marker lines.

```python
from ae_picker import refined_stalta_picker, plot_sta_lta_overlay

amp, time = channels[0]["amp"], channels[0]["time"]
N = len(time)

pick_idx, cft, triggers = refined_stalta_picker(
    amp, time,
    sta_s=2e-6, lta_s=100e-6,
    sta_thresh=2.5, lta_thresh=1.5,
    search_start=int(0.5 * N),   # filtered records: no triggers before t=0
)

fig, axes = plot_sta_lta_overlay(
    amp, time,
    sta_s=2e-6, lta_s=100e-6,
    sta_thresh=2.5, lta_thresh=1.5,
    triggers=triggers,            # draws onset vline on all panels
    tlim_us=(-100, 200),          # zoom to ±µs around arrival (relative to time[0])
)
```

Key parameters:

| Parameter | Description | Default |
|---|---|---|
| `sta_s`, `lta_s` | STA and LTA window lengths (seconds) | `5e-6`, `50e-6` |
| `sta_thresh`, `lta_thresh` | Trigger on/off threshold lines | `2.5`, `1.5` |
| `triggers` | `[[onset, offset], ...]` sample pairs from `refined_stalta_picker` | `None` |
| `manual_picks_s` | Additional pick times (seconds) to overlay | `None` |
| `tlim_us` | X-axis limits in microseconds relative to `time[0]` | `None` (full record) |
| `savepath` | File path to save the figure | `None` |

---

### `plot_wave_and_spectrogram` — waveform + PSD spectrogram

Produces a two-panel figure with the normalised waveform above and the
Power Spectral Density spectrogram (Hann window, Welch method) below, sharing
the same time axis.  Suitable for journal figures.

```python
from ae_picker import plot_wave_and_spectrogram

fig, (ax_wave, ax_spec) = plot_wave_and_spectrogram(
    amp, time,
    fmax=500e3,              # Hz — clip frequency axis at 500 kHz
    tmin=time[0],            # display window start (seconds)
    tmax=time[-1],           # display window end   (seconds)
    dyn_range_db=80,         # colour dynamic range
    title="Channel 1",
    savepath="ch1_spec.png",
)
```

Key parameters:

| Parameter | Description | Default |
|---|---|---|
| `fmax` | Upper frequency limit for the spectrogram (Hz) | `None` (Nyquist) |
| `nperseg` | STFT window length (samples); `None` → auto (~2 ms) | `None` |
| `overlap` | Fractional window overlap `[0, 1)` | `0.90` |
| `dyn_range_db` | Colour dynamic range in dB | `80` |
| `norm_percentile` | Percentile used to normalise the waveform | `99.9` |
| `tmin`, `tmax` | Display window start/end (seconds) | `None` (full record) |
| `savepath` | File path to save the figure | `None` |

## Features

- AIC, envelope-based, and STA/LTA picking workflows
- Readers for the repository's filtered and unfiltered waveform formats
- Batch processing that writes a single `picks_summary.csv`
- Plot helpers for waveform review and picker comparison
- A command-line interface exposed as `ae-picker`

## Installation

Install from PyPI after the package is published:

```bash
pip install ae-picker
```

Install from a local checkout:

```bash
git clone https://github.com/wamriewdan/ae_arrival_picker
cd ae_arrival_picker
pip install .
```

Optional extras:

```bash
pip install -e ".[dev]"
pip install ".[obspy]"
```

The package is installed as `ae-picker` but imported as `ae_picker`.

## Quick start

Batch process a dataset with the Python API:

```python
from ae_picker import run

df = run("path/to/your/data_dir", plot=False, save_plots=False)
print(df.head())
```

Run the CLI:

```bash
ae-picker path/to/your/data_dir --save-plots
```

Pick a single file:

```python
from ae_picker import aic_picker, plot_channels, read_unfiltered

meta, channels = read_unfiltered("my_ae_file.txt")

aic_picks = []
for ch in channels:
    idx, _ = aic_picker(ch["amp"], search_start=1, search_end=10)
    aic_picks.append(idx)
    print(f"P arrival at {ch['time'][idx] * 1e6:.1f} us")

fig = plot_channels(meta, channels, picks={"AIC": aic_picks})
fig.savefig("picks.png", dpi=150)
```


## Batch input layout

The batch runner expects a root directory containing one or both of these
subdirectories:

```text
your_data_dir/
|-- unfiltered_signals/
`-- filtered_signals/
```

`run()` and `ae-picker` scan those folders, infer the signal type from the
folder name, and write results to `picks_output/picks_summary.csv` by default.

## References

1. Maeda, N. (1985). *A Method for Reading and Checking Phase Time in
   Auto-Processing System of Seismic Wave Data*. Zisin, 38(3), 365-379.
   https://doi.org/10.4294/zisin1948.38.3_365
2. Allen, R. V. (1978). *Automatic Earthquake Recognition and Timing from
   Single Traces*. Bulletin of the Seismological Society of America, 68(5),
   1521-1532. https://doi.org/10.1785/BSSA0680051521
3. Beyreuther, M., Barsch, R., Krischer, L., Megies, T., Behr, Y., and
   Wassermann, J. (2010). *ObsPy: A Python Toolbox for Seismology*.
   Seismological Research Letters, 81(3), 530-533.
   https://doi.org/10.1785/gssrl.81.3.530

## License

MIT
