seismic-response

Evaluate seismological instrument responses specified as StationXML, SEED RESP or SAC poles-and-zeros as selected frequencies to get complex-spectra or frequency-amplitude-phase results. This package is a superset of the capability of the legacy evalresp program.

Requires Python 3.11 or newer (Linux, macOS and Windows).

Install

pip install seismic-response              # library + CLI + GUI
pip install "seismic-response[desktop]"   # also a native window for the GUI (pywebview)

Library

from datetime import datetime, timezone
import seismic_response as sr

channels = sr.read_response("RESP.IU.ANMO.00.BHZ")      # StationXML, RESP or SAC PZ, auto-detected
chan = sr.select_channel(channels, "FDSN:IU_ANMO_00_B_H_Z",
                         time=datetime(2000, 1, 1, tzinfo=timezone.utc))

freqs = sr.generate_frequencies(0.001, 50, 200)          # log spaced; linear=True for linear
result = chan.evaluate(freqs, unit="vel")                # "def" (default, as documented), "vel", "dis" or "acc"

result.frequencies          # Hz
result.values               # complex response, counts per unit of the requested ground motion
result.amplitudes
result.phases(unwrap=True)  # degrees
result.info                 # sensitivity, per-stage gains, warnings, ...

Useful options of evaluate: stages=(first, last), use_total_sensitivity=True, use_estimated_delay=True (asymmetric FIR), b62_x=... (polynomial responses) and per_stage=True (each stage’s contribution in result.stage_values; their product is the total response).

Channel selection follows evalresp: patterns are globs, and when several epochs of a channel overlap the shortest one containing the requested time wins (the latest one when no time is given):

sr.select_channels(channels, network="IU", station="ANMO", location="00,10", channel="BH?", time=t)

Errors derive from SeismicResponseError (ResponseParseError, ResponseValueError, ChannelNotFoundError, UnsupportedFeatureError).

Command line

pyevalresp takes the same arguments and options as the C evalresp and writes the same files (AMP.*/PHASE.*, FAP.* or SPECTRA.*, or the -stdio form):

pyevalresp ANMO BHZ 2000 100 0.001 50 200 -f RESP.IU.ANMO.00.BHZ -u vel -r fap
pyevalresp KONO BHN,BHE 1992 1 0.001 10 100 -f resp_dir -t 12:31:04 -v
cat station.xml | pyevalresp '*' 'BH?' 2020 5 0.01 10 50 -stdio -x

Run pyevalresp without arguments for the full option list. Differences from the C program: messages go to stderr and a request matching no channel prints a warning. Also, -u defaults to def (the units documented in the response) rather than evalresp’s vel; pass -u vel to get evalresp’s behavior. A response whose input units are not ground motion (pressure, counts, none documented, …) therefore evaluates with no -u, where evalresp fails and asks for -u def.

seismic-response is the umbrella command: seismic-response info FILE [-s] lists channels and stages, seismic-response evalresp ... is pyevalresp, and seismic-response gui [FILE ...] starts the GUI.

User Interface - Seismological Response Explorer

seismic-response gui RESP.IU.ANMO.00.BHZ       # opens your browser on a local server
seismic-response gui --app                     # native window (needs the [desktop] extra)
python -m seismic_response.gui --build site/   # static copy: host it anywhere, no Python server needed

The browser version of each release is published to GitHub Pages at https://earthscope-labs.github.io/seismic-response/app/. A static copy has to be served over HTTP (for example python -m http.server -d site/); opening index.html from disk does not work.

Load files by dropping them on the page, enter a file URL, or fetch from an FDSN station web service. Choose an epoch of an FDSN Source ID from the list, then set the frequency range, output unit and options, and tick the stages to include in the stage table. The plot shows amplitude and phase with a hover read-out; individual stages can be overlaid; tick several epochs, of the same or different Source IDs, to overlay them for comparison; results export as evalresp text (FAP, AP, complex), SVG or PNG.

A link can open the page with files already loaded using the url parameter (repeatable, percent-encoded), for example .../app/?url=https%3A%2F%2Fexample.org%2Fresponse.xml. The file server must allow cross-origin requests.

The page talks to the same Python through a small JSON API (seismic_response.web_api). With the local server that is plain HTTP on the loopback interface (requests with a foreign Host or Origin are refused). On a static host it loads Pyodide from a CDN and runs the package in the browser.

Deliberate differences from evalresp

Limitations

How closely does it match evalresp?

The numerical code is a port of evalresp’s own logic (stage consistency checks, gain/normalization handling, FIR/IIR/pole-zero evaluation, unit conversion, phase unwrapping) rather than a re-derivation. It is checked against a built evalresp in two ways:

Confirmed matching: Laplace (rad/s and Hz) and Z-transform poles/zeros, asymmetric/even/odd-symmetric FIR (including continuation blockettes and delay correction), IIR coefficients, response lists, gain-only stages, sensitivity-frequency renormalization, dis/vel/acc/def conversion including nm/mm/cm inputs, -ts, -use-estimated-delay and stage ranges.

References

Development

python -m venv .venv && . .venv/bin/activate
pip install -e ".[dev]"
pytest                      # ~550 tests, ~2 s
ruff check src tests tools

tools/make_synthetic.py and tools/make_golden.py regenerate the synthetic fixtures and the golden reference results (the latter needs a built C evalresp). tests/pyodide/ holds the WebAssembly smoke test run in CI; see .github/workflows/tests.yml.

The package is distributed under the GNU Lesser General Public License, version 3 (see LICENSE), the same license as evalresp.