or run

npx @tessl/cli init
Log in

Version

Tile

Overview

Evals

Files

Files

docs

core-data-structures.mddata-center-clients.mdfile-format-io.mdgeodetic-calculations.mdindex.mdsignal-processing.mdtravel-time-calculations.mdvisualization-imaging.md

signal-processing.mddocs/

0

# Signal Processing

1

2

Comprehensive signal processing toolkit including digital filters, triggering algorithms, spectral analysis, array processing, and coordinate transformations specifically designed for seismological data analysis. These functions integrate seamlessly with ObsPy's core data structures and provide the foundation for advanced seismological analysis workflows.

3

4

## Capabilities

5

6

### Digital Filtering

7

8

High-performance digital filters optimized for seismological data including Butterworth, Chebyshev, and FIR implementations with zero-phase options.

9

10

```python { .api }

11

# Import from obspy.signal.filter

12

def bandpass(data, freqmin: float, freqmax: float, df: float, corners: int = 4,

13

zerophase: bool = False, **kwargs):

14

"""

15

Butterworth bandpass filter.

16

17

Args:

18

data: Input data array

19

freqmin: Low frequency corner in Hz

20

freqmax: High frequency corner in Hz

21

df: Sampling frequency in Hz

22

corners: Filter order (number of poles)

23

zerophase: Apply zero-phase filter

24

**kwargs: Additional filter options

25

26

Returns:

27

Filtered data array

28

"""

29

30

def lowpass(data, freq: float, df: float, corners: int = 4,

31

zerophase: bool = False, **kwargs):

32

"""

33

Butterworth lowpass filter.

34

35

Args:

36

data: Input data array

37

freq: Corner frequency in Hz

38

df: Sampling frequency in Hz

39

corners: Filter order

40

zerophase: Apply zero-phase filter

41

**kwargs: Additional options

42

43

Returns:

44

Filtered data array

45

"""

46

47

def highpass(data, freq: float, df: float, corners: int = 4,

48

zerophase: bool = False, **kwargs):

49

"""

50

Butterworth highpass filter.

51

52

Args:

53

data: Input data array

54

freq: Corner frequency in Hz

55

df: Sampling frequency in Hz

56

corners: Filter order

57

zerophase: Apply zero-phase filter

58

**kwargs: Additional options

59

60

Returns:

61

Filtered data array

62

"""

63

64

def bandstop(data, freqmin: float, freqmax: float, df: float, corners: int = 4,

65

zerophase: bool = False, **kwargs):

66

"""

67

Butterworth bandstop (notch) filter.

68

69

Args:

70

data: Input data array

71

freqmin: Low frequency corner in Hz

72

freqmax: High frequency corner in Hz

73

df: Sampling frequency in Hz

74

corners: Filter order

75

zerophase: Apply zero-phase filter

76

**kwargs: Additional options

77

78

Returns:

79

Filtered data array

80

"""

81

82

def lowpass_cheby_2(data, freq: float, df: float, maxorder: int = 12,

83

ba: bool = False, freq_passband: bool = False):

84

"""

85

Chebyshev type 2 lowpass filter.

86

87

Args:

88

data: Input data array

89

freq: Corner frequency in Hz

90

df: Sampling frequency in Hz

91

maxorder: Maximum filter order

92

ba: Return filter coefficients if True

93

freq_passband: Frequency is passband edge if True

94

95

Returns:

96

Filtered data array or filter coefficients

97

"""

98

99

def lowpass_fir(data, freq: float, df: float, ntaps: int = None, **kwargs):

100

"""

101

FIR lowpass filter using Parks-McClellan optimal design.

102

103

Args:

104

data: Input data array

105

freq: Corner frequency in Hz

106

df: Sampling frequency in Hz

107

ntaps: Number of filter taps (auto if None)

108

**kwargs: FIR design options

109

110

Returns:

111

Filtered data array

112

"""

113

114

def remez_fir(data, freqs: list, desired: list, df: float, **kwargs):

115

"""

116

FIR filter using Remez exchange algorithm.

117

118

Args:

119

data: Input data array

120

freqs: List of frequency band edges in Hz

121

desired: List of desired gains for each band

122

df: Sampling frequency in Hz

123

**kwargs: Remez algorithm options

124

125

Returns:

126

Filtered data array

127

"""

128

```

129

130

### Event Detection and Triggering

131

132

Automated event detection algorithms for identifying seismic arrivals and determining onset times with sub-sample precision.

133

134

```python { .api }

135

# Import from obspy.signal.trigger

136

def classic_sta_lta(a, nsta: int, nlta: int):

137

"""

138

Classic STA/LTA trigger algorithm.

139

140

Args:

141

a: Input data array

142

nsta: Short time average window length in samples

143

nlta: Long time average window length in samples

144

145

Returns:

146

STA/LTA characteristic function array

147

"""

148

149

def recursive_sta_lta(a, nsta: int, nlta: int):

150

"""

151

Recursive STA/LTA trigger algorithm (faster implementation).

152

153

Args:

154

a: Input data array

155

nsta: Short time average window length in samples

156

nlta: Long time average window length in samples

157

158

Returns:

159

STA/LTA characteristic function array

160

"""

161

162

def delayed_sta_lta(a, nsta: int, nlta: int):

163

"""

164

Delayed STA/LTA trigger algorithm.

165

166

Args:

167

a: Input data array

168

nsta: Short time average window length in samples

169

nlta: Long time average window length in samples

170

171

Returns:

172

STA/LTA characteristic function array

173

"""

174

175

def carl_sta_trig(a, nsta: int, nlta: int, ratio: float, quiet: float):

176

"""

177

Carl-STA-Trig algorithm for coincidence triggering.

178

179

Args:

180

a: Input data array

181

nsta: Short time average window length in samples

182

nlta: Long time average window length in samples

183

ratio: Trigger ratio threshold

184

quiet: Quiet ratio threshold

185

186

Returns:

187

Trigger times array

188

"""

189

190

def z_detect(a, nsta: int):

191

"""

192

Z-detector algorithm for event detection.

193

194

Args:

195

a: Input data array

196

nsta: Analysis window length in samples

197

198

Returns:

199

Z-detector characteristic function

200

"""

201

202

def trigger_onset(charfct, thres1: float, thres2: float, max_len: int = None,

203

max_len_delete: bool = False):

204

"""

205

Determine trigger on and off times from characteristic function.

206

207

Args:

208

charfct: Characteristic function array

209

thres1: Trigger on threshold

210

thres2: Trigger off threshold

211

max_len: Maximum trigger length in samples

212

max_len_delete: Delete long triggers if True

213

214

Returns:

215

Array of (trigger_on, trigger_off) sample indices

216

"""

217

218

def coincidence_trigger(trigger_type: str, thr_on: float, thr_off: float,

219

stream, thr_coincidence_sum: int, **kwargs):

220

"""

221

Multi-station coincidence triggering.

222

223

Args:

224

trigger_type: Trigger algorithm ('recstalta', 'classicstalta', etc.)

225

thr_on: Trigger on threshold

226

thr_off: Trigger off threshold

227

stream: Stream with multiple traces

228

thr_coincidence_sum: Minimum stations for coincidence

229

**kwargs: Algorithm-specific parameters

230

231

Returns:

232

List of coincident trigger dictionaries

233

"""

234

```

235

236

### Probabilistic Power Spectral Density

237

238

Advanced spectral analysis class for long-term noise analysis and instrument performance monitoring following McNamara and Buland (2004) methodology.

239

240

```python { .api }

241

class PPSD:

242

def __init__(self, stats, paz_or_resp, dtiny: float = 1e-6,

243

dmedian: float = None, period_smoothing_width_octaves: float = 1.0,

244

period_step_octaves: float = 0.125, **kwargs):

245

"""

246

Probabilistic power spectral density analysis.

247

248

Args:

249

stats: Trace.stats object with metadata

250

paz_or_resp: Poles and zeros dict or response object

251

dtiny: Tiny float for numerical stability

252

dmedian: Median smoothing parameter

253

period_smoothing_width_octaves: Smoothing width in octaves

254

period_step_octaves: Period step size in octaves

255

**kwargs: Additional PPSD parameters

256

"""

257

258

def add(self, stream, verbose: bool = False):

259

"""

260

Add stream data to PPSD analysis.

261

262

Args:

263

stream: Stream object with seismic data

264

verbose: Print processing information

265

"""

266

267

def plot(self, filename: str = None, show_coverage: bool = True,

268

show_histogram: bool = True, show_percentiles: bool = False,

269

percentiles: list = [0, 25, 50, 75, 100], **kwargs):

270

"""

271

Plot PPSD results.

272

273

Args:

274

filename: Save plot to file if specified

275

show_coverage: Show data coverage timeline

276

show_histogram: Show probability density histogram

277

show_percentiles: Show percentile lines

278

percentiles: List of percentiles to show

279

**kwargs: Additional plotting options

280

"""

281

282

def plot_temporal(self, starttime=None, endtime=None, **kwargs):

283

"""

284

Plot temporal evolution of PSDs.

285

286

Args:

287

starttime: Start time for plot window

288

endtime: End time for plot window

289

**kwargs: Plotting options

290

"""

291

292

def plot_spectrogram(self, filename: str = None, **kwargs):

293

"""

294

Plot spectrogram representation of PSDs.

295

296

Args:

297

filename: Save plot to file if specified

298

**kwargs: Plotting options

299

"""

300

301

def save_npz(self, filename: str):

302

"""

303

Save PPSD data to NumPy compressed file.

304

305

Args:

306

filename: Output filename (.npz)

307

"""

308

309

def load_npz(self, filename: str):

310

"""

311

Load PPSD data from NumPy compressed file.

312

313

Args:

314

filename: Input filename (.npz)

315

"""

316

317

def get_percentile(self, percentile: float = 50, hist_stack=None):

318

"""

319

Get specified percentile curve from PPSD.

320

321

Args:

322

percentile: Percentile value (0-100)

323

hist_stack: Histogram stack to use

324

325

Returns:

326

Tuple of (periods, power_values)

327

"""

328

329

def calculate_histogram(self, starttime=None, endtime=None):

330

"""

331

Calculate probability density histogram for time window.

332

333

Args:

334

starttime: Window start time

335

endtime: Window end time

336

337

Returns:

338

2D histogram array

339

"""

340

```

341

342

### Instrument Response Simulation

343

344

Instrument response correction and simulation functions for removing instrument effects and simulating different sensor responses.

345

346

```python { .api }

347

# Import from obspy.signal.invsim

348

def simulate_seismometer(data, samp_rate: float, paz_remove=None, paz_simulate=None,

349

taper: bool = True, simulate_sensitivity: bool = True,

350

taper_fraction: float = 0.05, pre_filt=None, zero_mean: bool = True,

351

nfft_pow2: bool = False, **kwargs):

352

"""

353

Simulate seismometer response.

354

355

Args:

356

data: Input data array

357

samp_rate: Sampling rate in Hz

358

paz_remove: Poles and zeros to remove (dict with 'poles', 'zeros', 'gain')

359

paz_simulate: Poles and zeros to simulate

360

taper: Apply taper to data

361

simulate_sensitivity: Include sensitivity simulation

362

taper_fraction: Taper length as fraction of trace

363

pre_filt: Pre-filter frequencies (list of 4 corners)

364

zero_mean: Remove mean before processing

365

nfft_pow2: Use power-of-2 FFT length

366

**kwargs: Additional options

367

368

Returns:

369

Simulated data array

370

"""

371

372

def corn_freq_2_paz(fc: float, damp: float = 0.707):

373

"""

374

Convert corner frequency and damping to poles and zeros.

375

376

Args:

377

fc: Corner frequency in Hz

378

damp: Damping factor (default 0.707 for critical damping)

379

380

Returns:

381

Dictionary with poles, zeros, and gain

382

"""

383

384

def paz_2_amplitude_value_of_freq_resp(paz, freq: float):

385

"""

386

Calculate amplitude response at specific frequency.

387

388

Args:

389

paz: Poles and zeros dictionary

390

freq: Frequency in Hz

391

392

Returns:

393

Amplitude response value

394

"""

395

396

def evalresp(t_samp: float, nfft: int, filename: str, date, units: str = "VEL",

397

freq: bool = False, **kwargs):

398

"""

399

Use evalresp to calculate instrument response.

400

401

Args:

402

t_samp: Sampling period in seconds

403

nfft: Number of FFT points

404

filename: RESP filename or SEED response

405

date: Response date (UTCDateTime)

406

units: Output units ('DIS', 'VEL', 'ACC')

407

freq: Return frequency array if True

408

**kwargs: Additional evalresp options

409

410

Returns:

411

Complex response array (and frequencies if freq=True)

412

"""

413

414

def cosine_taper(npts: int, p: float = 0.1):

415

"""

416

Generate cosine taper window.

417

418

Args:

419

npts: Number of points

420

p: Taper fraction (0.1 = 10% taper on each end)

421

422

Returns:

423

Taper window array

424

"""

425

```

426

427

### Array Processing and Beamforming

428

429

Multi-station array processing techniques for detecting and locating seismic sources using coherent signal processing across seismic arrays.

430

431

```python { .api }

432

# Import from obspy.signal.array_analysis

433

def array_processing(stream, win_len: float, win_frac: float, sll_x: float,

434

slm_x: float, sll_y: float, slm_y: float, sl_s: float,

435

semb_thres: float = -1e9, vel_thres: float = -1e9,

436

frqlow: float = 1.0, frqhigh: float = 8.0, samp_rate: float = 40.0,

437

prewhiten: int = 0, **kwargs):

438

"""

439

Array processing for slowness and back-azimuth estimation.

440

441

Args:

442

stream: Stream with array data (requires coordinates)

443

win_len: Sliding window length in seconds

444

win_frac: Window overlap fraction (0-1)

445

sll_x: Slowness grid minimum X in s/km

446

slm_x: Slowness grid maximum X in s/km

447

sll_y: Slowness grid minimum Y in s/km

448

slm_y: Slowness grid maximum Y in s/km

449

sl_s: Slowness grid spacing in s/km

450

semb_thres: Semblance threshold

451

vel_thres: Velocity threshold in km/s

452

frqlow: Low frequency in Hz

453

frqhigh: High frequency in Hz

454

samp_rate: Sampling rate in Hz

455

prewhiten: Pre-whitening (0=off, 1=on)

456

**kwargs: Additional options

457

458

Returns:

459

Structured array with processing results

460

"""

461

462

def get_geometry(stream, coordsys: str = 'lonlat', return_center: bool = False):

463

"""

464

Get array geometry from stream coordinates.

465

466

Args:

467

stream: Stream with coordinate metadata

468

coordsys: Coordinate system ('lonlat', 'xy')

469

return_center: Return array center coordinates

470

471

Returns:

472

Array geometry matrix (and center if requested)

473

"""

474

475

def get_timeshift(geometry, sll_x: float, slm_x: float, sll_y: float, slm_y: float,

476

sl_s: float, grdpts_x: int, grdpts_y: int):

477

"""

478

Calculate time shifts for slowness grid.

479

480

Args:

481

geometry: Array geometry matrix

482

sll_x: Slowness grid minimum X

483

slm_x: Slowness grid maximum X

484

sll_y: Slowness grid minimum Y

485

slm_y: Slowness grid maximum Y

486

sl_s: Slowness grid spacing

487

grdpts_x: Grid points in X direction

488

grdpts_y: Grid points in Y direction

489

490

Returns:

491

Time shift array for grid points

492

"""

493

```

494

495

### Coordinate Rotation

496

497

Coordinate system transformations for seismological data including horizontal component rotation and three-component rotations to ray-coordinate systems.

498

499

```python { .api }

500

# Import from obspy.signal.rotate

501

def rotate_ne_rt(n, e, ba: float):

502

"""

503

Rotate North-East components to Radial-Transverse.

504

505

Args:

506

n: North component data array

507

e: East component data array

508

ba: Back-azimuth in degrees

509

510

Returns:

511

Tuple of (radial, transverse) component arrays

512

"""

513

514

def rotate_rt_ne(r, t, ba: float):

515

"""

516

Rotate Radial-Transverse components to North-East.

517

518

Args:

519

r: Radial component data array

520

t: Transverse component data array

521

ba: Back-azimuth in degrees

522

523

Returns:

524

Tuple of (north, east) component arrays

525

"""

526

527

def rotate_zne_lqt(z, n, e, ba: float, inc: float):

528

"""

529

Rotate ZNE components to LQT ray coordinate system.

530

531

Args:

532

z: Vertical component data array

533

n: North component data array

534

e: East component data array

535

ba: Back-azimuth in degrees

536

inc: Inclination angle in degrees

537

538

Returns:

539

Tuple of (L, Q, T) component arrays

540

L: P-wave direction, Q: SV-wave direction, T: SH-wave direction

541

"""

542

543

def rotate_lqt_zne(l, q, t, ba: float, inc: float):

544

"""

545

Rotate LQT ray coordinates back to ZNE components.

546

547

Args:

548

l: L component data array (P-wave direction)

549

q: Q component data array (SV-wave direction)

550

t: T component data array (SH-wave direction)

551

ba: Back-azimuth in degrees

552

inc: Inclination angle in degrees

553

554

Returns:

555

Tuple of (Z, N, E) component arrays

556

"""

557

```

558

559

### Cross Correlation

560

561

Cross-correlation analysis for measuring time delays between signals and template matching applications.

562

563

```python { .api }

564

# Import from obspy.signal.cross_correlation

565

def correlate(a, b, shift_len: int, demean: bool = True, normalize: str = 'naive',

566

method: str = 'auto'):

567

"""

568

Cross-correlate two signals.

569

570

Args:

571

a: First signal array

572

b: Second signal array

573

shift_len: Maximum shift length in samples

574

demean: Remove mean before correlation

575

normalize: Normalization method ('naive', 'full')

576

method: Correlation method ('auto', 'fft', 'direct')

577

578

Returns:

579

Cross-correlation array

580

"""

581

582

def xcorr_max(a, b, abs_max: bool = True):

583

"""

584

Find maximum cross-correlation and lag.

585

586

Args:

587

a: First signal array

588

b: Second signal array

589

abs_max: Use absolute maximum if True

590

591

Returns:

592

Tuple of (correlation_coefficient, lag_in_samples)

593

"""

594

595

def correlate_template(data, template, mode: str = 'valid', normalize: str = 'full'):

596

"""

597

Template matching using cross-correlation.

598

599

Args:

600

data: Data array to search

601

template: Template array to match

602

mode: Correlation mode ('valid', 'full', 'same')

603

normalize: Normalization method

604

605

Returns:

606

Cross-correlation array

607

"""

608

```

609

610

### Spectral Analysis

611

612

Frequency domain analysis tools including power spectral density estimation, spectrograms, and multitaper methods.

613

614

```python { .api }

615

# Import from obspy.signal.spectral_estimation

616

def PPSD(stats, paz_or_resp, **kwargs):

617

"""Create PPSD instance (alias for main PPSD class)."""

618

619

def psd(data, NFFT: int = 256, Fs: float = 2, detrend: str = 'linear',

620

window: str = 'hann', noverlap: int = 0):

621

"""

622

Power spectral density using Welch's method.

623

624

Args:

625

data: Input data array

626

NFFT: FFT length

627

Fs: Sampling frequency

628

detrend: Detrend method ('linear', 'constant', 'none')

629

window: Window function

630

noverlap: Overlap between segments

631

632

Returns:

633

Tuple of (frequencies, power_spectral_density)

634

"""

635

636

def spectrogram(data, samp_rate: float, per_lap: float = 0.9, wlen: float = None,

637

log: bool = False, outfile: str = None, fmt: str = None,

638

axes=None, dbscale: bool = False, **kwargs):

639

"""

640

Create spectrogram of time series data.

641

642

Args:

643

data: Input data array

644

samp_rate: Sampling rate in Hz

645

per_lap: Percentage of overlap (0-1)

646

wlen: Window length in seconds

647

log: Use logarithmic frequency scale

648

outfile: Save to file if specified

649

fmt: File format for saving

650

axes: Matplotlib axes object

651

dbscale: Use dB scale for power

652

**kwargs: Additional plotting options

653

654

Returns:

655

Tuple of (time, frequency, spectrogram_array)

656

"""

657

```

658

659

## Usage Examples

660

661

### Basic Filtering Workflow

662

663

```python

664

from obspy import read

665

from obspy.signal.filter import bandpass, lowpass

666

import numpy as np

667

668

# Read seismic data

669

st = read('seismic_data.mseed')

670

trace = st[0]

671

672

# Apply bandpass filter (1-10 Hz)

673

filtered_data = bandpass(trace.data, 1.0, 10.0, trace.stats.sampling_rate,

674

corners=4, zerophase=True)

675

676

# Apply to trace directly using trace method

677

trace.filter('bandpass', freqmin=1.0, freqmax=10.0, corners=4, zerophase=True)

678

679

# Multiple filter stages

680

trace.filter('highpass', freq=0.5) # Remove long periods

681

trace.filter('lowpass', freq=25.0) # Anti-alias before decimation

682

trace.decimate(2) # Reduce sampling rate by factor of 2

683

```

684

685

### Event Detection with STA/LTA

686

687

```python

688

from obspy import read

689

from obspy.signal.trigger import classic_sta_lta, trigger_onset, plot_trigger

690

import matplotlib.pyplot as plt

691

692

# Read data and select trace

693

st = read('continuous_data.mseed')

694

trace = st[0]

695

696

# Calculate STA/LTA characteristic function

697

df = trace.stats.sampling_rate

698

cft = classic_sta_lta(trace.data, int(5 * df), int(10 * df))

699

700

# Determine trigger times

701

thr_on = 1.5

702

thr_off = 0.5

703

on_off = trigger_onset(cft, thr_on, thr_off)

704

705

# Plot results

706

fig, (ax1, ax2) = plt.subplots(2, 1, figsize=(12, 8))

707

708

# Plot original trace

709

times = trace.times()

710

ax1.plot(times, trace.data, 'black')

711

ax1.set_ylabel('Amplitude')

712

ax1.set_title(f'{trace.id} - Raw Data')

713

714

# Plot characteristic function with triggers

715

ax2.plot(times, cft, 'blue')

716

ax2.axhline(thr_on, color='red', linestyle='--', label='Thr On')

717

ax2.axhline(thr_off, color='orange', linestyle='--', label='Thr Off')

718

719

# Mark trigger times

720

for triggers in on_off:

721

on_time = times[triggers[0]]

722

off_time = times[triggers[1]]

723

ax2.axvspan(on_time, off_time, alpha=0.3, color='red')

724

725

ax2.set_ylabel('STA/LTA')

726

ax2.set_xlabel('Time (s)')

727

ax2.legend()

728

plt.tight_layout()

729

plt.show()

730

```

731

732

### PPSD Noise Analysis

733

734

```python

735

from obspy import read

736

from obspy.signal import PPSD

737

from obspy.clients.fdsn import Client

738

739

# Get station response

740

client = Client("IRIS")

741

inventory = client.get_stations(network="IU", station="ANMO", location="00",

742

channel="BHZ", level="response")

743

744

# Read continuous data

745

st = read('continuous_noise.mseed')

746

747

# Create PPSD instance

748

ppsd = PPSD(st[0].stats, metadata=inventory)

749

750

# Add data to analysis (can add multiple days/files)

751

ppsd.add(st)

752

753

# Plot results

754

ppsd.plot(show_coverage=True, show_histogram=True)

755

ppsd.plot_temporal() # Show temporal evolution

756

ppsd.plot_spectrogram() # Show spectrogram view

757

758

# Get percentile curves

759

periods, median_psd = ppsd.get_percentile(percentile=50)

760

periods, low_noise = ppsd.get_percentile(percentile=10)

761

periods, high_noise = ppsd.get_percentile(percentile=90)

762

```

763

764

### Array Beamforming

765

766

```python

767

from obspy import read

768

from obspy.signal.array_analysis import array_processing, get_geometry

769

import numpy as np

770

771

# Read array data (requires coordinate metadata)

772

st = read('array_data.mseed')

773

774

# Get array geometry

775

geometry = get_geometry(st, coordsys='lonlat')

776

777

# Array processing parameters

778

kwargs = dict(

779

# sliding window properties

780

win_len=1.0, # window length in seconds

781

win_frac=0.05, # window overlap fraction

782

# slowness grid

783

sll_x=-3.0, slm_x=3.0, # X slowness limits (s/km)

784

sll_y=-3.0, slm_y=3.0, # Y slowness limits (s/km)

785

sl_s=0.03, # slowness step (s/km)

786

# frequency band

787

frqlow=1.0, frqhigh=8.0, # frequency band (Hz)

788

# processing

789

samp_rate=40.0, # sampling rate

790

prewhiten=0, # pre-whitening off

791

semb_thres=-1e9, # semblance threshold

792

vel_thres=-1e9, # velocity threshold

793

)

794

795

# Perform array processing

796

out = array_processing(st, **kwargs)

797

798

# Extract results

799

times = out[:, 0] # time stamps

800

rel_power = out[:, 1] # relative power

801

abs_power = out[:, 2] # absolute power

802

baz = out[:, 3] # back-azimuth

803

slow = out[:, 4] # slowness magnitude

804

805

# Convert slowness to apparent velocity

806

app_vel = 1.0 / slow # km/s

807

808

print(f"Mean back-azimuth: {np.mean(baz):.1f} degrees")

809

print(f"Mean apparent velocity: {np.mean(app_vel):.2f} km/s")

810

```

811

812

## Types

813

814

```python { .api }

815

# Poles and zeros dictionary structure

816

PoleZeroDict = {

817

'poles': list[complex], # List of complex poles

818

'zeros': list[complex], # List of complex zeros

819

'gain': float, # System gain

820

'sensitivity': float # Instrument sensitivity (optional)

821

}

822

823

# Array processing result structure (structured NumPy array)

824

ArrayProcessingResult = np.dtype([

825

('time', 'f8'), # Time stamp

826

('rel_power', 'f8'), # Relative power

827

('abs_power', 'f8'), # Absolute power

828

('baz', 'f8'), # Back-azimuth in degrees

829

('slow', 'f8') # Slowness magnitude in s/km

830

])

831

832

# Trigger onset result structure

833

TriggerOnset = np.dtype([

834

('time_on', 'i4'), # Trigger on time (sample index)

835

('time_off', 'i4') # Trigger off time (sample index)

836

])

837

```