Skip to content

pysmo

Pysmo protocol classes and their minimal implementations.

The pysmo base namespace provides protocol classes used as type hints and a minimal reference implementation ("Mini class") for each protocol. The protocols define common seismological data structures such as locations, seismic events, stations, and seismograms.

Each Mini class is a concrete attrs class that implements exactly the attributes required by its protocol. Mini classes are named by prefixing "Mini" to the protocol name (e.g. MiniSeismogram implements the Seismogram protocol).

Classes, functions, and other tools that operate on pysmo types are provided by the pysmo.classes, pysmo.functions, and pysmo.tools subpackages.

Modules:

Name Description
classes

Concrete classes compatible with pysmo types.

functions

Building-block functions for pysmo types.

lib

Internal utilities, converters, validators, defaults, and I/O used by pysmo.

tools

Topic-specific tools that operate on pysmo types.

typing

Annotated type aliases that document value constraints.

Classes:

Name Description
Event

Protocol class to define the Event type.

Location

Protocol class to define the Location type.

LocationWithDepth

Protocol class to define the LocationWithDepth type.

MiniEvent

Minimal implementation of the Event type.

MiniLocation

Minimal implementation of the Location type.

MiniLocationWithDepth

Minimal implementation of the LocationWithDepth type.

MiniResponse

Minimal implementation of the Response type.

MiniResponseStage

Minimal implementation of the ResponseStage type.

MiniSeismogram

Minimal implementation of the Seismogram type.

MiniStagedResponse

Minimal implementation of the StagedResponse type.

MiniStation

Minimal implementation of the Station type.

MiniStationCode

Minimal implementation of the StationCode type.

Response

Protocol class to define the Response type.

ResponseStage

Protocol class to define one digital (FIR/IIR) decimation stage.

Seismogram

Protocol class to define the Seismogram type.

StagedResponse

Protocol class to define a Response with digital decimation stages.

Station

Protocol class to define the Station type.

StationCode

Protocol class to define the StationCode type.

Event

Bases: LocationWithDepth, Protocol

Protocol class to define the Event type.

A seismic event: a hypocentre from LocationWithDepth together with an origin time.

Attributes:

Name Type Description
latitude float

Latitude in degrees.

longitude float

Longitude in degrees.

depth float

Location depth in metres, positive downwards.

time Timestamp

Event origin time.

Source code in src/pysmo/_types/event.py
class Event(LocationWithDepth, Protocol):
    """Protocol class to define the `Event` type.

    A seismic event: a hypocentre from
    [`LocationWithDepth`][pysmo.LocationWithDepth] together with an origin
    time.
    """

    time: pd.Timestamp
    """Event origin time."""

latitude instance-attribute

latitude: float

Latitude in degrees.

longitude instance-attribute

longitude: float

Longitude in degrees.

depth instance-attribute

depth: float

Location depth in metres, positive downwards.

time instance-attribute

time: Timestamp

Event origin time.

Location

Bases: Protocol

Protocol class to define the Location type.

A geographic point, given as latitude and longitude in degrees.

Attributes:

Name Type Description
latitude float

Latitude in degrees.

longitude float

Longitude in degrees.

Source code in src/pysmo/_types/location.py
class Location(Protocol):
    """Protocol class to define the `Location` type.

    A geographic point, given as latitude and longitude in degrees.
    """

    latitude: float
    """Latitude in degrees."""

    longitude: float
    """Longitude in degrees."""

latitude instance-attribute

latitude: float

Latitude in degrees.

longitude instance-attribute

longitude: float

Longitude in degrees.

LocationWithDepth

Bases: Location, Protocol

Protocol class to define the LocationWithDepth type.

A Location that also carries a depth, such as an earthquake hypocentre.

Attributes:

Name Type Description
latitude float

Latitude in degrees.

longitude float

Longitude in degrees.

depth float

Location depth in metres, positive downwards.

Source code in src/pysmo/_types/location_with_depth.py
class LocationWithDepth(Location, Protocol):
    """Protocol class to define the `LocationWithDepth` type.

    A [`Location`][pysmo.Location] that also carries a depth, such as an
    earthquake hypocentre.
    """

    depth: float
    """Location depth in metres, positive downwards."""

latitude instance-attribute

latitude: float

Latitude in degrees.

longitude instance-attribute

longitude: float

Longitude in degrees.

depth instance-attribute

depth: float

Location depth in metres, positive downwards.

MiniEvent

Minimal implementation of the Event type.

See Event.

Examples:

>>> from pysmo import MiniEvent
>>> import pandas as pd
>>> from datetime import timezone
>>> now = pd.Timestamp.now(timezone.utc)
>>> event = MiniEvent(latitude=-24.68, longitude=-26.73, depth=15234.0, time=now)
>>>

Attributes:

Name Type Description
time UtcTimestamp

Event origin time.

latitude float

Event latitude from -90 to 90 degrees.

longitude float

Event longitude from -180 to 180 degrees (-180 is stored as +180).

depth float

Event depth in metres, positive downwards.

Source code in src/pysmo/_types/event.py
@define(kw_only=True)
class MiniEvent:
    """Minimal implementation of the `Event` type.

    See [`Event`][pysmo.Event].

    Examples:
        ```python
        >>> from pysmo import MiniEvent
        >>> import pandas as pd
        >>> from datetime import timezone
        >>> now = pd.Timestamp.now(timezone.utc)
        >>> event = MiniEvent(latitude=-24.68, longitude=-26.73, depth=15234.0, time=now)
        >>>
        ```
    """

    time: UtcTimestamp = field(
        converter=to_utc_timestamp,
        on_setattr=setters.pipe(setters.convert, setters.validate),
    )
    """Event origin time."""

    latitude: float = field(
        converter=float,
        validator=is_latitude,
        on_setattr=setters.pipe(setters.convert, setters.validate),
    )
    """Event latitude from -90 to 90 degrees."""

    longitude: float = field(
        converter=to_longitude,
        validator=is_longitude,
        on_setattr=setters.pipe(setters.convert, setters.validate),
    )
    """Event longitude from -180 to 180 degrees (-180 is stored as +180)."""

    depth: float = field(
        converter=float, on_setattr=setters.pipe(setters.convert, setters.validate)
    )
    """Event depth in metres, positive downwards."""

time class-attribute instance-attribute

Event origin time.

latitude class-attribute instance-attribute

latitude: float = field(
    converter=float,
    validator=is_latitude,
    on_setattr=setters.pipe(
        setters.convert, setters.validate
    ),
)

Event latitude from -90 to 90 degrees.

longitude class-attribute instance-attribute

longitude: float = field(
    converter=to_longitude,
    validator=is_longitude,
    on_setattr=setters.pipe(
        setters.convert, setters.validate
    ),
)

Event longitude from -180 to 180 degrees (-180 is stored as +180).

depth class-attribute instance-attribute

depth: float = field(
    converter=float,
    on_setattr=setters.pipe(
        setters.convert, setters.validate
    ),
)

Event depth in metres, positive downwards.

MiniLocation

Minimal implementation of the Location type.

See Location.

Examples:

>>> from pysmo import MiniLocation
>>> location = MiniLocation(latitude=41.8781, longitude=-87.6298)
>>>

Attributes:

Name Type Description
latitude float

Latitude from -90 to 90 degrees.

longitude float

Longitude from -180 to 180 degrees (-180 is stored as +180).

Source code in src/pysmo/_types/location.py
@define(kw_only=True)
class MiniLocation:
    """Minimal implementation of the `Location` type.

    See [`Location`][pysmo.Location].

    Examples:
        ```python
        >>> from pysmo import MiniLocation
        >>> location = MiniLocation(latitude=41.8781, longitude=-87.6298)
        >>>
        ```
    """

    latitude: float = field(
        converter=float,
        validator=is_latitude,
        on_setattr=setters.pipe(setters.convert, setters.validate),
    )
    """Latitude from -90 to 90 degrees."""

    longitude: float = field(
        converter=to_longitude,
        validator=is_longitude,
        on_setattr=setters.pipe(setters.convert, setters.validate),
    )
    """Longitude from -180 to 180 degrees (-180 is stored as +180)."""

latitude class-attribute instance-attribute

latitude: float = field(
    converter=float,
    validator=is_latitude,
    on_setattr=setters.pipe(
        setters.convert, setters.validate
    ),
)

Latitude from -90 to 90 degrees.

longitude class-attribute instance-attribute

longitude: float = field(
    converter=to_longitude,
    validator=is_longitude,
    on_setattr=setters.pipe(
        setters.convert, setters.validate
    ),
)

Longitude from -180 to 180 degrees (-180 is stored as +180).

MiniLocationWithDepth

Minimal implementation of the LocationWithDepth type.

See LocationWithDepth.

Examples:

>>> from pysmo import MiniLocationWithDepth
>>> hypo = MiniLocationWithDepth(latitude=-24.68, longitude=-26.73, depth=15234.0)
>>>

Attributes:

Name Type Description
latitude float

Location latitude from -90 to 90 degrees.

longitude float

Location longitude from -180 to 180 degrees (-180 is stored as +180).

depth float

Location depth in metres, positive downwards.

Source code in src/pysmo/_types/location_with_depth.py
@define(kw_only=True)
class MiniLocationWithDepth:
    """Minimal implementation of the `LocationWithDepth` type.

    See [`LocationWithDepth`][pysmo.LocationWithDepth].

    Examples:
        ```python
        >>> from pysmo import MiniLocationWithDepth
        >>> hypo = MiniLocationWithDepth(latitude=-24.68, longitude=-26.73, depth=15234.0)
        >>>
        ```
    """

    latitude: float = field(
        converter=float,
        validator=is_latitude,
        on_setattr=setters.pipe(setters.convert, setters.validate),
    )
    """Location latitude from -90 to 90 degrees."""

    longitude: float = field(
        converter=to_longitude,
        validator=is_longitude,
        on_setattr=setters.pipe(setters.convert, setters.validate),
    )
    """Location longitude from -180 to 180 degrees (-180 is stored as +180)."""

    depth: float = field(
        converter=float, on_setattr=setters.pipe(setters.convert, setters.validate)
    )
    """Location depth in metres, positive downwards."""

latitude class-attribute instance-attribute

latitude: float = field(
    converter=float,
    validator=is_latitude,
    on_setattr=setters.pipe(
        setters.convert, setters.validate
    ),
)

Location latitude from -90 to 90 degrees.

longitude class-attribute instance-attribute

longitude: float = field(
    converter=to_longitude,
    validator=is_longitude,
    on_setattr=setters.pipe(
        setters.convert, setters.validate
    ),
)

Location longitude from -180 to 180 degrees (-180 is stored as +180).

depth class-attribute instance-attribute

depth: float = field(
    converter=float,
    on_setattr=setters.pipe(
        setters.convert, setters.validate
    ),
)

Location depth in metres, positive downwards.

MiniResponse

Minimal implementation of the Response type.

See Response.

Examples:

>>> from pysmo import MiniResponse
>>> response = MiniResponse(
...     poles=[-0.037 + 0.037j, -0.037 - 0.037j],
...     zeros=[0j, 0j],
...     overall_sensitivity=3.4e9,
...     input_units="M/S",
... )
>>>

Attributes:

Name Type Description
poles list[complex]

Response poles.

zeros list[complex]

Response zeros.

overall_sensitivity NonZeroNumber

Scale factor combined with poles/zeros to reconstruct H(f).

reference_sensitivity NonZeroNumber | None

Total system sensitivity at the reference frequency, A0 excluded.

input_units str

Physical units produced by removing this response.

Source code in src/pysmo/_types/response.py
@define(kw_only=True)
class MiniResponse:
    """Minimal implementation of the `Response` type.

    See [`Response`][pysmo.Response].

    Examples:
        ```python
        >>> from pysmo import MiniResponse
        >>> response = MiniResponse(
        ...     poles=[-0.037 + 0.037j, -0.037 - 0.037j],
        ...     zeros=[0j, 0j],
        ...     overall_sensitivity=3.4e9,
        ...     input_units="M/S",
        ... )
        >>>
        ```
    """

    poles: list[complex] = field(
        converter=to_complex_list,
        on_setattr=setters.pipe(setters.convert, setters.validate),
    )
    """Response poles.

    See [`Response.poles`][pysmo.Response.poles] for more details.
    """

    zeros: list[complex] = field(
        converter=to_complex_list,
        on_setattr=setters.pipe(setters.convert, setters.validate),
    )
    """Response zeros.

    See [`Response.zeros`][pysmo.Response.zeros] for more details.
    """

    overall_sensitivity: NonZeroNumber = field(
        converter=float,
        validator=is_nonzero,
        on_setattr=setters.pipe(setters.convert, setters.validate),
    )
    """Scale factor combined with `poles`/`zeros` to reconstruct `H(f)`.

    See [`Response.overall_sensitivity`][pysmo.Response.overall_sensitivity]
    for more details.
    """

    reference_sensitivity: NonZeroNumber | None = field(
        default=None,
        converter=converters.optional(float),
        validator=validators.optional(is_nonzero),
        on_setattr=setters.pipe(setters.convert, setters.validate),
    )
    """Total system sensitivity at the reference frequency, `A0` excluded.

    See
    [`Response.reference_sensitivity`][pysmo.Response.reference_sensitivity]
    for more details.
    """

    input_units: str = field(
        validator=validators.instance_of(str),
        on_setattr=setters.pipe(setters.convert, setters.validate),
    )
    """Physical units produced by removing this response.

    See [`Response.input_units`][pysmo.Response.input_units] for more details.
    """

poles class-attribute instance-attribute

poles: list[complex] = field(
    converter=to_complex_list,
    on_setattr=setters.pipe(
        setters.convert, setters.validate
    ),
)

Response poles.

See Response.poles for more details.

zeros class-attribute instance-attribute

zeros: list[complex] = field(
    converter=to_complex_list,
    on_setattr=setters.pipe(
        setters.convert, setters.validate
    ),
)

Response zeros.

See Response.zeros for more details.

overall_sensitivity class-attribute instance-attribute

overall_sensitivity: NonZeroNumber = field(
    converter=float,
    validator=is_nonzero,
    on_setattr=setters.pipe(
        setters.convert, setters.validate
    ),
)

Scale factor combined with poles/zeros to reconstruct H(f).

See Response.overall_sensitivity for more details.

reference_sensitivity class-attribute instance-attribute

reference_sensitivity: NonZeroNumber | None = field(
    default=None,
    converter=converters.optional(float),
    validator=validators.optional(is_nonzero),
    on_setattr=setters.pipe(
        setters.convert, setters.validate
    ),
)

Total system sensitivity at the reference frequency, A0 excluded.

See Response.reference_sensitivity for more details.

input_units class-attribute instance-attribute

input_units: str = field(
    validator=validators.instance_of(str),
    on_setattr=setters.pipe(
        setters.convert, setters.validate
    ),
)

Physical units produced by removing this response.

See Response.input_units for more details.

MiniResponseStage

Minimal implementation of the ResponseStage type.

See ResponseStage.

Examples:

>>> from pysmo import MiniResponseStage
>>> stage = MiniResponseStage(
...     input_sample_rate=40.0,
...     decimation_factor=1,
...     numerator=[0.5, 0.5],
... )
>>> stage.denominator
[1.0]
>>>

Attributes:

Name Type Description
input_sample_rate PositiveNumber

Sample rate this stage's filter coefficients operate at.

decimation_factor int

Integer decimation factor applied by this stage.

numerator list[float]

Feedforward ("b") filter coefficients.

denominator list[float]

Feedback ("a") filter coefficients.

correction float

Time correction (seconds) already applied to cancel this stage's own

Source code in src/pysmo/_types/response.py
@define(kw_only=True)
class MiniResponseStage:
    """Minimal implementation of the `ResponseStage` type.

    See [`ResponseStage`][pysmo.ResponseStage].

    Examples:
        ```python
        >>> from pysmo import MiniResponseStage
        >>> stage = MiniResponseStage(
        ...     input_sample_rate=40.0,
        ...     decimation_factor=1,
        ...     numerator=[0.5, 0.5],
        ... )
        >>> stage.denominator
        [1.0]
        >>>
        ```
    """

    input_sample_rate: PositiveNumber = field(
        converter=float,
        validator=validators.gt(0),
        on_setattr=setters.pipe(setters.convert, setters.validate),
    )
    """Sample rate this stage's filter coefficients operate at.

    See [`ResponseStage.input_sample_rate`][pysmo.ResponseStage.input_sample_rate]
    for more details.
    """

    decimation_factor: int = field(
        converter=to_strict_int,
        validator=validators.gt(0),
        on_setattr=setters.pipe(setters.convert, setters.validate),
    )
    """Integer decimation factor applied by this stage.

    See [`ResponseStage.decimation_factor`][pysmo.ResponseStage.decimation_factor]
    for more details.
    """

    numerator: list[float] = field(
        converter=to_float_list,
        validator=validators.min_len(1),
        on_setattr=setters.pipe(setters.convert, setters.validate),
    )
    """Feedforward ("b") filter coefficients.

    See [`ResponseStage.numerator`][pysmo.ResponseStage.numerator] for more details.
    """

    denominator: list[float] = field(
        factory=lambda: [1.0],
        converter=to_float_list,
        validator=validators.min_len(1),
        on_setattr=setters.pipe(setters.convert, setters.validate),
    )
    """Feedback ("a") filter coefficients.

    See [`ResponseStage.denominator`][pysmo.ResponseStage.denominator] for more details.
    """

    correction: float = field(
        default=0.0,
        converter=float,
        on_setattr=setters.pipe(setters.convert, setters.validate),
    )
    """Time correction (seconds) already applied to cancel this stage's own
    filter delay.

    See [`ResponseStage.correction`][pysmo.ResponseStage.correction] for
    more details.
    """

input_sample_rate class-attribute instance-attribute

input_sample_rate: PositiveNumber = field(
    converter=float,
    validator=validators.gt(0),
    on_setattr=setters.pipe(
        setters.convert, setters.validate
    ),
)

Sample rate this stage's filter coefficients operate at.

See ResponseStage.input_sample_rate for more details.

decimation_factor class-attribute instance-attribute

decimation_factor: int = field(
    converter=to_strict_int,
    validator=validators.gt(0),
    on_setattr=setters.pipe(
        setters.convert, setters.validate
    ),
)

Integer decimation factor applied by this stage.

See ResponseStage.decimation_factor for more details.

numerator class-attribute instance-attribute

numerator: list[float] = field(
    converter=to_float_list,
    validator=validators.min_len(1),
    on_setattr=setters.pipe(
        setters.convert, setters.validate
    ),
)

Feedforward ("b") filter coefficients.

See ResponseStage.numerator for more details.

denominator class-attribute instance-attribute

denominator: list[float] = field(
    factory=lambda: [1.0],
    converter=to_float_list,
    validator=validators.min_len(1),
    on_setattr=setters.pipe(
        setters.convert, setters.validate
    ),
)

Feedback ("a") filter coefficients.

See ResponseStage.denominator for more details.

correction class-attribute instance-attribute

correction: float = field(
    default=0.0,
    converter=float,
    on_setattr=setters.pipe(
        setters.convert, setters.validate
    ),
)

Time correction (seconds) already applied to cancel this stage's own filter delay.

See ResponseStage.correction for more details.

MiniSeismogram

Bases: SeismogramEndtimeMixin

Minimal implementation of the Seismogram type.

See Seismogram.

Examples:

>>> from pysmo import MiniSeismogram
>>> import pandas as pd
>>> from datetime import timezone
>>> import numpy as np
>>> now = pd.Timestamp.now(timezone.utc)
>>> delta = pd.Timedelta(seconds=0.1)
>>> seismogram = MiniSeismogram(
...     begin_time=now, delta=delta, data=np.random.rand(100)
... )
>>>

Attributes:

Name Type Description
end_time Timestamp

Seismogram end time.

begin_time UtcTimestamp

Seismogram begin time.

delta PositiveTimedelta

Seismogram sampling interval.

data NDArray[floating]

Seismogram data.

Source code in src/pysmo/_types/seismogram.py
@define(kw_only=True)
class MiniSeismogram(SeismogramEndtimeMixin):
    """Minimal implementation of the `Seismogram` type.

    See [`Seismogram`][pysmo.Seismogram].

    Examples:
        ```python
        >>> from pysmo import MiniSeismogram
        >>> import pandas as pd
        >>> from datetime import timezone
        >>> import numpy as np
        >>> now = pd.Timestamp.now(timezone.utc)
        >>> delta = pd.Timedelta(seconds=0.1)
        >>> seismogram = MiniSeismogram(
        ...     begin_time=now, delta=delta, data=np.random.rand(100)
        ... )
        >>>
        ```
    """

    begin_time: UtcTimestamp = field(
        default=SeismogramDefaults.begin_time,
        converter=to_utc_timestamp,
        on_setattr=setters.convert,
    )
    """Seismogram begin time."""

    delta: PositiveTimedelta = field(
        default=SeismogramDefaults.delta,
        converter=to_timedelta,
        validator=is_positive_timedelta,
        on_setattr=setters.pipe(setters.convert, setters.validate),
    )
    """Seismogram sampling interval."""

    data: npt.NDArray[np.floating] = field(
        factory=lambda: np.array([]),
        converter=to_ndarray,
        validator=validators.instance_of(np.ndarray),
        on_setattr=setters.pipe(setters.convert, setters.validate),
        eq=cmp_using(eq=np.array_equal),
    )
    """Seismogram data."""

end_time property

end_time: Timestamp

Seismogram end time.

begin_time class-attribute instance-attribute

begin_time: UtcTimestamp = field(
    default=SeismogramDefaults.begin_time,
    converter=to_utc_timestamp,
    on_setattr=setters.convert,
)

Seismogram begin time.

delta class-attribute instance-attribute

delta: PositiveTimedelta = field(
    default=SeismogramDefaults.delta,
    converter=to_timedelta,
    validator=is_positive_timedelta,
    on_setattr=setters.pipe(
        setters.convert, setters.validate
    ),
)

Seismogram sampling interval.

data class-attribute instance-attribute

data: NDArray[floating] = field(
    factory=lambda: np.array([]),
    converter=to_ndarray,
    validator=validators.instance_of(np.ndarray),
    on_setattr=setters.pipe(
        setters.convert, setters.validate
    ),
    eq=cmp_using(eq=np.array_equal),
)

Seismogram data.

MiniStagedResponse

Bases: MiniResponse

Minimal implementation of the StagedResponse type.

See StagedResponse.

Examples:

>>> from pysmo import MiniStagedResponse
>>> response = MiniStagedResponse(
...     poles=[-0.037 + 0.037j, -0.037 - 0.037j],
...     zeros=[0j, 0j],
...     overall_sensitivity=3.4e9,
...     input_units="M/S",
... )
>>>

Attributes:

Name Type Description
poles list[complex]

Response poles.

zeros list[complex]

Response zeros.

overall_sensitivity NonZeroNumber

Scale factor combined with poles/zeros to reconstruct H(f).

reference_sensitivity NonZeroNumber | None

Total system sensitivity at the reference frequency, A0 excluded.

input_units str

Physical units produced by removing this response.

stages list[ResponseStage]

Digital decimation stages, in signal order.

Source code in src/pysmo/_types/response.py
@define(kw_only=True)
class MiniStagedResponse(MiniResponse):
    """Minimal implementation of the `StagedResponse` type.

    See [`StagedResponse`][pysmo.StagedResponse].

    Examples:
        ```python
        >>> from pysmo import MiniStagedResponse
        >>> response = MiniStagedResponse(
        ...     poles=[-0.037 + 0.037j, -0.037 - 0.037j],
        ...     zeros=[0j, 0j],
        ...     overall_sensitivity=3.4e9,
        ...     input_units="M/S",
        ... )
        >>>
        ```
    """

    stages: list[ResponseStage] = field(
        factory=list,
        validator=validators.deep_iterable(
            member_validator=satisfies_protocol(ResponseStage),
            iterable_validator=validators.instance_of(list),
        ),
        on_setattr=setters.validate,
    )
    """Digital decimation stages, in signal order.

    See [`StagedResponse.stages`][pysmo.StagedResponse.stages] for more details.
    """

poles class-attribute instance-attribute

poles: list[complex] = field(
    converter=to_complex_list,
    on_setattr=setters.pipe(
        setters.convert, setters.validate
    ),
)

Response poles.

See Response.poles for more details.

zeros class-attribute instance-attribute

zeros: list[complex] = field(
    converter=to_complex_list,
    on_setattr=setters.pipe(
        setters.convert, setters.validate
    ),
)

Response zeros.

See Response.zeros for more details.

overall_sensitivity class-attribute instance-attribute

overall_sensitivity: NonZeroNumber = field(
    converter=float,
    validator=is_nonzero,
    on_setattr=setters.pipe(
        setters.convert, setters.validate
    ),
)

Scale factor combined with poles/zeros to reconstruct H(f).

See Response.overall_sensitivity for more details.

reference_sensitivity class-attribute instance-attribute

reference_sensitivity: NonZeroNumber | None = field(
    default=None,
    converter=converters.optional(float),
    validator=validators.optional(is_nonzero),
    on_setattr=setters.pipe(
        setters.convert, setters.validate
    ),
)

Total system sensitivity at the reference frequency, A0 excluded.

See Response.reference_sensitivity for more details.

input_units class-attribute instance-attribute

input_units: str = field(
    validator=validators.instance_of(str),
    on_setattr=setters.pipe(
        setters.convert, setters.validate
    ),
)

Physical units produced by removing this response.

See Response.input_units for more details.

stages class-attribute instance-attribute

stages: list[ResponseStage] = field(
    factory=list,
    validator=validators.deep_iterable(
        member_validator=satisfies_protocol(ResponseStage),
        iterable_validator=validators.instance_of(list),
    ),
    on_setattr=setters.validate,
)

Digital decimation stages, in signal order.

See StagedResponse.stages for more details.

MiniStation

Minimal implementation of the Station type.

See Station.

Examples:

>>> from pysmo import MiniStation
>>> station = MiniStation(
...     latitude=-21.680301,
...     longitude=-46.732601,
...     name="CACB",
...     network="BL",
...     channel="BHZ",
...     location="00",
... )
>>>

Attributes:

Name Type Description
name str

Station name.

network str

Network name.

location str

Location ID.

channel str

Channel code.

latitude float

Station latitude from -90 to 90 degrees.

longitude float

Station longitude from -180 to 180 degrees (-180 is stored as +180).

elevation float | None

Station elevation.

Source code in src/pysmo/_types/station.py
@define(kw_only=True)
class MiniStation:
    """Minimal implementation of the `Station` type.

    See [`Station`][pysmo.Station].

    Examples:
        ```python
        >>> from pysmo import MiniStation
        >>> station = MiniStation(
        ...     latitude=-21.680301,
        ...     longitude=-46.732601,
        ...     name="CACB",
        ...     network="BL",
        ...     channel="BHZ",
        ...     location="00",
        ... )
        >>>
        ```
    """

    name: str = field(
        validator=_name_code,
        on_setattr=setters.validate,
    )
    """Station name.

    See [`Station.name`][pysmo.Station.name] for more details.
    """

    network: str = field(
        validator=_network_code,
        on_setattr=setters.validate,
    )
    """Network name.

    See [`Station.network`][pysmo.Station.network] for more details.
    """

    location: str = field(
        default="  ",
        validator=_location_code,
        converter=_pad_string,
        on_setattr=setters.pipe(setters.convert, setters.validate),
    )
    """Location ID.

    See [`Station.location`][pysmo.Station.location] for more details.
    """

    channel: str = field(
        validator=_channel_code,
        on_setattr=setters.validate,
    )
    """Channel code.

    See [`Station.channel`][pysmo.Station.channel] for more details.
    """

    latitude: float = field(
        converter=float,
        validator=is_latitude,
        on_setattr=setters.pipe(setters.convert, setters.validate),
    )
    """Station latitude from -90 to 90 degrees."""

    longitude: float = field(
        converter=to_longitude,
        validator=is_longitude,
        on_setattr=setters.pipe(setters.convert, setters.validate),
    )
    """Station longitude from -180 to 180 degrees (-180 is stored as +180)."""

    elevation: float | None = field(
        default=None,
        converter=converters.optional(float),
        validator=validators.optional(validators.instance_of(float)),
        on_setattr=setters.pipe(setters.convert, setters.validate),
    )
    """Station elevation."""

name class-attribute instance-attribute

name: str = field(
    validator=_name_code, on_setattr=setters.validate
)

Station name.

See Station.name for more details.

network class-attribute instance-attribute

network: str = field(
    validator=_network_code, on_setattr=setters.validate
)

Network name.

See Station.network for more details.

location class-attribute instance-attribute

location: str = field(
    default="  ",
    validator=_location_code,
    converter=_pad_string,
    on_setattr=setters.pipe(
        setters.convert, setters.validate
    ),
)

Location ID.

See Station.location for more details.

channel class-attribute instance-attribute

channel: str = field(
    validator=_channel_code, on_setattr=setters.validate
)

Channel code.

See Station.channel for more details.

latitude class-attribute instance-attribute

latitude: float = field(
    converter=float,
    validator=is_latitude,
    on_setattr=setters.pipe(
        setters.convert, setters.validate
    ),
)

Station latitude from -90 to 90 degrees.

longitude class-attribute instance-attribute

longitude: float = field(
    converter=to_longitude,
    validator=is_longitude,
    on_setattr=setters.pipe(
        setters.convert, setters.validate
    ),
)

Station longitude from -180 to 180 degrees (-180 is stored as +180).

elevation class-attribute instance-attribute

elevation: float | None = field(
    default=None,
    converter=converters.optional(float),
    validator=validators.optional(
        validators.instance_of(float)
    ),
    on_setattr=setters.pipe(
        setters.convert, setters.validate
    ),
)

Station elevation.

MiniStationCode

Minimal implementation of the StationCode type.

See StationCode.

Examples:

>>> from pysmo import MiniStationCode
>>> code = MiniStationCode(
...     name="CACB", network="BL", channel="BHZ", location="00"
... )
>>>

Attributes:

Name Type Description
name str

Station name.

network str

Network name.

location str

Location ID.

channel str

Channel code.

Source code in src/pysmo/_types/station.py
@define(kw_only=True)
class MiniStationCode:
    """Minimal implementation of the `StationCode` type.

    See [`StationCode`][pysmo.StationCode].

    Examples:
        ```python
        >>> from pysmo import MiniStationCode
        >>> code = MiniStationCode(
        ...     name="CACB", network="BL", channel="BHZ", location="00"
        ... )
        >>>
        ```
    """

    name: str = field(
        validator=_name_code,
        on_setattr=setters.validate,
    )
    """Station name.

    See [`StationCode.name`][pysmo.StationCode.name] for more details.
    """

    network: str = field(
        validator=_network_code,
        on_setattr=setters.validate,
    )
    """Network name.

    See [`StationCode.network`][pysmo.StationCode.network] for more details.
    """

    location: str = field(
        default="  ",
        validator=_location_code,
        converter=_pad_string,
        on_setattr=setters.pipe(setters.convert, setters.validate),
    )
    """Location ID.

    See [`StationCode.location`][pysmo.StationCode.location] for more details.
    """

    channel: str = field(
        validator=_channel_code,
        on_setattr=setters.validate,
    )
    """Channel code.

    See [`StationCode.channel`][pysmo.StationCode.channel] for more details.
    """

name class-attribute instance-attribute

name: str = field(
    validator=_name_code, on_setattr=setters.validate
)

Station name.

See StationCode.name for more details.

network class-attribute instance-attribute

network: str = field(
    validator=_network_code, on_setattr=setters.validate
)

Network name.

See StationCode.network for more details.

location class-attribute instance-attribute

location: str = field(
    default="  ",
    validator=_location_code,
    converter=_pad_string,
    on_setattr=setters.pipe(
        setters.convert, setters.validate
    ),
)

Location ID.

See StationCode.location for more details.

channel class-attribute instance-attribute

channel: str = field(
    validator=_channel_code, on_setattr=setters.validate
)

Channel code.

See StationCode.channel for more details.

Response

Bases: Protocol

Protocol class to define the Response type.

Represents an analog instrument response (Laplace domain), equivalent to a SAC PZ file: poles/zeros plus the total system sensitivity.

Attributes:

Name Type Description
poles list[complex]

Response poles, in radians/second.

zeros list[complex]

Response zeros, in radians/second.

overall_sensitivity NonZeroNumber

Scale factor combined with poles/zeros to reconstruct the full,

reference_sensitivity NonZeroNumber | None

Total system sensitivity (counts per physical unit) at the response's

input_units str

Physical units produced by removing this response (e.g. "M/S", "M/S**2").

Source code in src/pysmo/_types/response.py
class Response(Protocol):
    """Protocol class to define the `Response` type.

    Represents an analog instrument response (Laplace domain), equivalent to
    a SAC PZ file: poles/zeros plus the total system sensitivity.
    """

    poles: list[complex]
    """Response poles, in radians/second.

    SAC PZ / `LAPLACE (RADIANS/SECOND)` convention.
    """

    zeros: list[complex]
    """Response zeros, in radians/second."""

    overall_sensitivity: NonZeroNumber
    """Scale factor combined with `poles`/`zeros` to reconstruct the full,
    frequency-dependent transfer function `H(f)`.

    Equivalent to `CONSTANT` in a SAC PZ file (`A0 * sensitivity`, the
    analog stage's normalisation factor times the reference-frequency
    sensitivity), or FDSN StationXML's `NormalizationFactor *
    InstrumentSensitivity`. This is *not* the instrument's plain flat-band
    gain (see [`reference_sensitivity`][pysmo.Response.reference_sensitivity]
    for that), so dividing raw data by `overall_sensitivity` directly
    (rather than combining it with `poles`/`zeros`, or using
    `reference_sensitivity` instead) mis-scales the result by the `A0`
    factor, often several orders of magnitude.

    Negative values are permitted (but not zero): a negative `CONSTANT`/
    `NormalizationFactor` is how a reversed-polarity channel is recorded in
    the wild, not an error.
    """

    reference_sensitivity: NonZeroNumber | None
    """Total system sensitivity (counts per physical unit) at the response's
    own reference/normalisation frequency, with no `A0` normalisation folded
    in.

    Equivalent to SAC PZ's `SENSITIVITY` header value, or FDSN StationXML's
    `InstrumentSensitivity/Value`. This (not `overall_sensitivity`, which
    has `A0` folded in) is the correct divisor for a flat, zero-phase
    approximation of the response (e.g.
    [`remove_response`][pysmo.tools.signal.remove_response]'s
    sensitivity-only path). `None` if unavailable (e.g. a SAC PZ file
    without a `SENSITIVITY` header): callers needing it should raise rather
    than silently substituting `overall_sensitivity`. As with
    `overall_sensitivity`, a negative value indicates reversed polarity
    rather than an error; zero is not permitted.
    """

    input_units: str
    """Physical units produced by removing this response (e.g. `"M/S"`, `"M/S**2"`).

    Informational only: not validated against a fixed set of units, and not
    read by [`remove_response`][pysmo.tools.signal.remove_response] or
    [`integrate`][pysmo.tools.signal.integrate]/
    [`differentiate`][pysmo.tools.signal.differentiate]; callers are
    responsible for interpreting it themselves.
    """

poles instance-attribute

poles: list[complex]

Response poles, in radians/second.

SAC PZ / LAPLACE (RADIANS/SECOND) convention.

zeros instance-attribute

zeros: list[complex]

Response zeros, in radians/second.

overall_sensitivity instance-attribute

overall_sensitivity: NonZeroNumber

Scale factor combined with poles/zeros to reconstruct the full, frequency-dependent transfer function H(f).

Equivalent to CONSTANT in a SAC PZ file (A0 * sensitivity, the analog stage's normalisation factor times the reference-frequency sensitivity), or FDSN StationXML's NormalizationFactor * InstrumentSensitivity. This is not the instrument's plain flat-band gain (see reference_sensitivity for that), so dividing raw data by overall_sensitivity directly (rather than combining it with poles/zeros, or using reference_sensitivity instead) mis-scales the result by the A0 factor, often several orders of magnitude.

Negative values are permitted (but not zero): a negative CONSTANT/ NormalizationFactor is how a reversed-polarity channel is recorded in the wild, not an error.

reference_sensitivity instance-attribute

reference_sensitivity: NonZeroNumber | None

Total system sensitivity (counts per physical unit) at the response's own reference/normalisation frequency, with no A0 normalisation folded in.

Equivalent to SAC PZ's SENSITIVITY header value, or FDSN StationXML's InstrumentSensitivity/Value. This (not overall_sensitivity, which has A0 folded in) is the correct divisor for a flat, zero-phase approximation of the response (e.g. remove_response's sensitivity-only path). None if unavailable (e.g. a SAC PZ file without a SENSITIVITY header): callers needing it should raise rather than silently substituting overall_sensitivity. As with overall_sensitivity, a negative value indicates reversed polarity rather than an error; zero is not permitted.

input_units instance-attribute

input_units: str

Physical units produced by removing this response (e.g. "M/S", "M/S**2").

Informational only: not validated against a fixed set of units, and not read by remove_response or integrate/ differentiate; callers are responsible for interpreting it themselves.

ResponseStage

Bases: Protocol

Protocol class to define one digital (FIR/IIR) decimation stage.

Attributes:

Name Type Description
input_sample_rate PositiveNumber

Sample rate (Hz) this stage's filter coefficients operate at.

decimation_factor int

Integer decimation factor applied by this stage.

numerator list[float]

Feedforward ("b") filter coefficients.

denominator list[float]

Feedback ("a") filter coefficients. [1.0] for a pure FIR stage.

correction float

Time correction (seconds) already applied to the recorded data to

Source code in src/pysmo/_types/response.py
class ResponseStage(Protocol):
    """Protocol class to define one digital (FIR/IIR) decimation stage."""

    input_sample_rate: PositiveNumber
    """Sample rate (Hz) this stage's filter coefficients operate at."""

    decimation_factor: int
    """Integer decimation factor applied by this stage.

    [`MiniResponseStage`][pysmo.MiniResponseStage] requires it to be positive.
    """

    numerator: list[float]
    """Feedforward ("b") filter coefficients.

    [`MiniResponseStage`][pysmo.MiniResponseStage] requires at least one.
    """

    denominator: list[float]
    """Feedback ("a") filter coefficients. `[1.0]` for a pure FIR stage."""

    correction: float
    """Time correction (seconds) already applied to the recorded data to
    cancel this stage's own filter delay.

    Equivalent to FDSN StationXML's `Decimation/Correction` (SEED Blockette
    57 field 8). Real digitisers timestamp their output as if this stage
    had zero delay, by shifting the data earlier by this amount; evaluating
    `numerator`/`denominator` alone (e.g. via `scipy.signal.freqz`) instead
    reproduces the filter's own, uncorrected delay. `0.0` (the default,
    correct for a stage with no such correction, e.g. a symmetric FIR
    stage where the coefficients themselves carry no net delay) leaves the
    coefficient-derived transfer function unchanged."""

input_sample_rate instance-attribute

input_sample_rate: PositiveNumber

Sample rate (Hz) this stage's filter coefficients operate at.

decimation_factor instance-attribute

decimation_factor: int

Integer decimation factor applied by this stage.

MiniResponseStage requires it to be positive.

numerator instance-attribute

numerator: list[float]

Feedforward ("b") filter coefficients.

MiniResponseStage requires at least one.

denominator instance-attribute

denominator: list[float]

Feedback ("a") filter coefficients. [1.0] for a pure FIR stage.

correction instance-attribute

correction: float

Time correction (seconds) already applied to the recorded data to cancel this stage's own filter delay.

Equivalent to FDSN StationXML's Decimation/Correction (SEED Blockette 57 field 8). Real digitisers timestamp their output as if this stage had zero delay, by shifting the data earlier by this amount; evaluating numerator/denominator alone (e.g. via scipy.signal.freqz) instead reproduces the filter's own, uncorrected delay. 0.0 (the default, correct for a stage with no such correction, e.g. a symmetric FIR stage where the coefficients themselves carry no net delay) leaves the coefficient-derived transfer function unchanged.

Seismogram

Bases: Protocol

Protocol class to define the Seismogram type.

Examples:

A function annotated with Seismogram accepts any compatible class. This one returns the begin time in ISO format:

>>> from pysmo import Seismogram
>>> from pysmo.classes import SAC  # SAC implements the Seismogram protocol
>>>
>>> def example_function(seis_in: Seismogram) -> str:
...     return seis_in.begin_time.isoformat()
...
>>> sac = SAC.from_file("example.sac")
>>> seismogram = sac.seismogram
>>> example_function(seismogram)
'2010-02-27T06:44:06.069538+00:00'
>>>

Attributes:

Name Type Description
begin_time Timestamp

Seismogram begin time.

data NDArray[floating]

Seismogram data.

delta Timedelta

Seismogram sampling interval.

end_time Timestamp

Seismogram end time.

Source code in src/pysmo/_types/seismogram.py
class Seismogram(Protocol):
    """Protocol class to define the `Seismogram` type.

    Examples:
        A function annotated with `Seismogram` accepts any compatible class.
        This one returns the begin time in ISO format:

        ```python
        >>> from pysmo import Seismogram
        >>> from pysmo.classes import SAC  # SAC implements the Seismogram protocol
        >>>
        >>> def example_function(seis_in: Seismogram) -> str:
        ...     return seis_in.begin_time.isoformat()
        ...
        >>> sac = SAC.from_file("example.sac")
        >>> seismogram = sac.seismogram
        >>> example_function(seismogram)
        '2010-02-27T06:44:06.069538+00:00'
        >>>
        ```
    """

    begin_time: pd.Timestamp
    """Seismogram begin time."""

    data: npt.NDArray[np.floating]
    """Seismogram data."""

    delta: pd.Timedelta
    """Seismogram sampling interval.

    Must be a positive `pd.Timedelta`.
    """

    @property
    def end_time(self) -> pd.Timestamp:
        """Seismogram end time."""
        ...

begin_time instance-attribute

begin_time: Timestamp

Seismogram begin time.

data instance-attribute

Seismogram data.

delta instance-attribute

delta: Timedelta

Seismogram sampling interval.

Must be a positive pd.Timedelta.

end_time property

end_time: Timestamp

Seismogram end time.

StagedResponse

Bases: Response, Protocol

Protocol class to define a Response with digital decimation stages.

Extends Response with the digital FIR/IIR stages of the instrument's full signal chain, in stage (signal) order.

Attributes:

Name Type Description
poles list[complex]

Response poles, in radians/second.

zeros list[complex]

Response zeros, in radians/second.

overall_sensitivity NonZeroNumber

Scale factor combined with poles/zeros to reconstruct the full,

reference_sensitivity NonZeroNumber | None

Total system sensitivity (counts per physical unit) at the response's

input_units str

Physical units produced by removing this response (e.g. "M/S", "M/S**2").

stages list[ResponseStage]

Digital decimation stages, in signal order (stage 1 = closest to the

Source code in src/pysmo/_types/response.py
class StagedResponse(Response, Protocol):
    """Protocol class to define a `Response` with digital decimation stages.

    Extends `Response` with the digital FIR/IIR stages of the instrument's
    full signal chain, in stage (signal) order.
    """

    stages: list[ResponseStage]
    """Digital decimation stages, in signal order (stage 1 = closest to the
    analog sensor)."""

poles instance-attribute

poles: list[complex]

Response poles, in radians/second.

SAC PZ / LAPLACE (RADIANS/SECOND) convention.

zeros instance-attribute

zeros: list[complex]

Response zeros, in radians/second.

overall_sensitivity instance-attribute

overall_sensitivity: NonZeroNumber

Scale factor combined with poles/zeros to reconstruct the full, frequency-dependent transfer function H(f).

Equivalent to CONSTANT in a SAC PZ file (A0 * sensitivity, the analog stage's normalisation factor times the reference-frequency sensitivity), or FDSN StationXML's NormalizationFactor * InstrumentSensitivity. This is not the instrument's plain flat-band gain (see reference_sensitivity for that), so dividing raw data by overall_sensitivity directly (rather than combining it with poles/zeros, or using reference_sensitivity instead) mis-scales the result by the A0 factor, often several orders of magnitude.

Negative values are permitted (but not zero): a negative CONSTANT/ NormalizationFactor is how a reversed-polarity channel is recorded in the wild, not an error.

reference_sensitivity instance-attribute

reference_sensitivity: NonZeroNumber | None

Total system sensitivity (counts per physical unit) at the response's own reference/normalisation frequency, with no A0 normalisation folded in.

Equivalent to SAC PZ's SENSITIVITY header value, or FDSN StationXML's InstrumentSensitivity/Value. This (not overall_sensitivity, which has A0 folded in) is the correct divisor for a flat, zero-phase approximation of the response (e.g. remove_response's sensitivity-only path). None if unavailable (e.g. a SAC PZ file without a SENSITIVITY header): callers needing it should raise rather than silently substituting overall_sensitivity. As with overall_sensitivity, a negative value indicates reversed polarity rather than an error; zero is not permitted.

input_units instance-attribute

input_units: str

Physical units produced by removing this response (e.g. "M/S", "M/S**2").

Informational only: not validated against a fixed set of units, and not read by remove_response or integrate/ differentiate; callers are responsible for interpreting it themselves.

stages instance-attribute

Digital decimation stages, in signal order (stage 1 = closest to the analog sensor).

Station

Bases: Location, StationCode, Protocol

Protocol class to define the Station type.

A seismic station: NSLC identity from StationCode, position from Location, and an optional elevation.

Attributes:

Name Type Description
name str

Station name or identifier.

network str

Network name or identifier.

location str

Location ID.

channel str

Channel code.

latitude float

Latitude in degrees.

longitude float

Longitude in degrees.

elevation int | float | None

Station elevation in metres.

Source code in src/pysmo/_types/station.py
class Station(Location, StationCode, Protocol):
    """Protocol class to define the `Station` type.

    A seismic station: NSLC identity from
    [`StationCode`][pysmo.StationCode], position from
    [`Location`][pysmo.Location], and an optional elevation.
    """

    elevation: int | float | None
    """Station elevation in metres."""

name instance-attribute

name: str

Station name or identifier.

A 1- to 5-character identifier for the station recording the data.

network instance-attribute

network: str

Network name or identifier.

A 1- or 2-character code identifying the network that owns the data.

location instance-attribute

location: str

Location ID.

A 2-character code used to identify different data streams at a single station.

channel instance-attribute

channel: str

Channel code.

A 3-character combination that identifies:

  1. Band and general sample rate.
  2. Instrument type.
  3. Orientation of the sensor.

latitude instance-attribute

latitude: float

Latitude in degrees.

longitude instance-attribute

longitude: float

Longitude in degrees.

elevation instance-attribute

elevation: int | float | None

Station elevation in metres.

StationCode

Bases: Protocol

Protocol class to define the StationCode type.

Network/station/location/channel (NSLC) identity for a data stream, independent of geographic location; the subset of Station a format like miniSEED can provide without coordinates.

Attributes:

Name Type Description
name str

Station name or identifier.

network str

Network name or identifier.

location str

Location ID.

channel str

Channel code.

Source code in src/pysmo/_types/station.py
class StationCode(Protocol):
    """Protocol class to define the `StationCode` type.

    Network/station/location/channel (NSLC) identity for a data stream,
    independent of geographic location; the subset of `Station` a format
    like miniSEED can provide without coordinates.
    """

    name: str
    """Station name or identifier.

    A 1- to 5-character identifier for the station recording the data.
    """

    network: str
    """Network name or identifier.

    A 1- or 2-character code identifying the network that owns the data.
    """

    location: str
    """Location ID.

    A 2-character code used to identify different data streams at a single
    station.
    """

    channel: str
    """Channel code.

    A 3-character combination that identifies:

    1. Band and general sample rate.
    2. Instrument type.
    3. Orientation of the sensor.
    """

name instance-attribute

name: str

Station name or identifier.

A 1- to 5-character identifier for the station recording the data.

network instance-attribute

network: str

Network name or identifier.

A 1- or 2-character code identifying the network that owns the data.

location instance-attribute

location: str

Location ID.

A 2-character code used to identify different data streams at a single station.

channel instance-attribute

channel: str

Channel code.

A 3-character combination that identifies:

  1. Band and general sample rate.
  2. Instrument type.
  3. Orientation of the sensor.