pysmo.tools.noise
Generate realistic synthetic noise that matches the naturally observed amplitude spectrum.
Examples:
Given the spectral amplitude in observed seismic noise on Earth is not flat (i.e. not consisting of white noise), it makes sense to calculate more realistic noise for things like resolution tests with synthetic data.
In this example, random noise seismograms are generated from three different noise models. These are Peterson's NHNM (red), NLNM (blue), and an interpolated model that lies between the two (green).

Example source code
"""
Example script for pysmo.tools.noise
"""
#!/usr/bin/env python
import matplotlib.pyplot as plt
import numpy as np
import pandas as pd
from pysmo.tools.noise import generate_noise, peterson
from pysmo.tools.signal import psd
def main(outfile: str = "peterson.png") -> None:
# Set parameters
npts: int = 200000 # multiple of 4
delta = pd.Timedelta(seconds=0.1)
nperseg = int(npts / 4)
nfft = int(npts / 2)
time_in_seconds = np.linspace(0, npts * delta.total_seconds(), npts)
# Calculate noise models
low_noise_model = peterson(noise_level=0)
mid_noise_model = peterson(noise_level=0.5)
high_noise_model = peterson(noise_level=1)
# Generate random noise seismograms
low_noise_seismogram = generate_noise(npts=npts, model=low_noise_model, delta=delta)
mid_noise_seismogram = generate_noise(npts=npts, model=mid_noise_model, delta=delta)
high_noise_seismogram = generate_noise(
npts=npts, model=high_noise_model, delta=delta
)
# Calculate power spectral density
f_low, Pxx_dens_low = psd(low_noise_seismogram, nperseg=nperseg, nfft=nfft)
f_mid, Pxx_dens_mid = psd(mid_noise_seismogram, nperseg=nperseg, nfft=nfft)
f_high, Pxx_dens_high = psd(high_noise_seismogram, nperseg=nperseg, nfft=nfft)
_ = plt.figure(figsize=(13, 9), layout="tight")
# Plot random high and low noise seismograms
ax1 = plt.subplot2grid((4, 3), (0, 0))
plt.plot(time_in_seconds, high_noise_seismogram.data, "r", linewidth=0.2)
plt.ylabel("Ground Accelaration")
plt.xlabel("Time [s]")
plt.xlim(time_in_seconds[0], time_in_seconds[-1])
xticks = np.arange(
tmin := time_in_seconds[0], (tmax := time_in_seconds[-1]) + 1, (tmax - tmin) / 5
)
ax1.set_xticks(xticks)
ax2 = plt.subplot2grid((4, 3), (0, 1))
ax2.set_xticks(xticks)
plt.plot(time_in_seconds, mid_noise_seismogram.data, "g", linewidth=0.2)
plt.xlabel("Time [s]")
plt.xlim(time_in_seconds[0], time_in_seconds[-1])
ax3 = plt.subplot2grid((4, 3), (0, 2))
ax3.set_xticks(xticks)
plt.plot(time_in_seconds, low_noise_seismogram.data, "b", linewidth=0.2)
plt.xlabel("Time [s]")
plt.xlim(time_in_seconds[0], time_in_seconds[-1])
# Plot PSD of noise
_ = plt.subplot2grid((4, 3), (1, 0), rowspan=3, colspan=3)
plt.plot(
1 / f_high,
10 * np.log10(Pxx_dens_high),
"r",
linewidth=0.5,
label="generated high noise",
)
plt.plot(
1 / f_mid,
10 * np.log10(Pxx_dens_mid),
"g",
linewidth=0.5,
label="generated medium noise",
)
plt.plot(
1 / f_low,
10 * np.log10(Pxx_dens_low),
"b",
linewidth=0.5,
label="generated low noise",
)
plt.plot(
high_noise_model.T.total_seconds(),
high_noise_model.psd,
color=plt.rcParams["text.color"],
linewidth=1,
linestyle="dotted",
label="NHNM",
)
plt.plot(
mid_noise_model.T.total_seconds(),
mid_noise_model.psd,
color=plt.rcParams["text.color"],
linewidth=1,
linestyle="dashdot",
label="Interpolated noise model",
)
plt.plot(
low_noise_model.T.total_seconds(),
low_noise_model.psd,
color=plt.rcParams["text.color"],
linewidth=1,
linestyle="dashed",
label="NLNM",
)
plt.gca().set_xscale("log")
plt.xlim(
low_noise_model.T.total_seconds()[0], low_noise_model.T.total_seconds()[-1]
)
plt.xlabel("Period [s]")
plt.ylabel("Power Spectral Density (dB/Hz)")
plt.legend()
plt.savefig(outfile, transparent=True)
plt.show()
if __name__ == "__main__":
main()
Classes:
| Name | Description |
|---|---|
NoiseModel |
Class to store seismic noise models. |
Functions:
| Name | Description |
|---|---|
generate_noise |
Generate a random seismogram from a noise model. |
peterson |
Generate a noise model by interpolating between Peterson's[^1] |
NoiseModel
dataclass
Class to store seismic noise models.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
psd
|
ndarray
|
Power spectral density of ground acceleration [dB]. |
(lambda: array([]))()
|
T
|
TimedeltaIndex
|
Period. |
(lambda: TimedeltaIndex([]))()
|
Examples:
A NoiseModel freezes its own copy of psd, so the array passed in
remains writeable and independent of the stored copy:
>>> import numpy as np
>>> import pandas as pd
>>> from pysmo.tools.noise import NoiseModel
>>> psd = np.array([-150.0, -140.0, -130.0])
>>> T = pd.to_timedelta([1.0, 10.0, 100.0], unit="s")
>>> model = NoiseModel(psd=psd, T=T)
>>> model.psd
array([-150., -140., -130.])
>>> psd[0] = -999.0 # does not affect the NoiseModel's own copy
>>> model.psd[0]
np.float64(-150.0)
>>>
Source code in src/pysmo/tools/noise.py
generate_noise
generate_noise(
model: NoiseModel,
npts: int,
delta: Timedelta = delta,
begin_time: Timestamp = begin_time,
return_velocity: bool = False,
seed: int | None = None,
) -> MiniSeismogram
Generate a random seismogram from a noise model.
The amplitude spectrum is prescribed by the noise model and random phases
are drawn uniformly from [-π, π]. The combined spectrum is transformed
back to the time domain via an inverse FFT. Internally the computation is
performed on the next power-of-two length greater than or equal to npts
to ensure an efficient FFT; the central npts samples are then extracted
from the result to avoid edge artefacts near the start and end of the
generated buffer.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
model
|
NoiseModel
|
Noise model used to compute seismic noise. |
required |
npts
|
int
|
Number of samples in the output seismogram. |
required |
delta
|
Timedelta
|
Sampling interval of the generated noise. |
delta
|
begin_time
|
Timestamp
|
Begin time of the output seismogram. |
begin_time
|
return_velocity
|
bool
|
If |
False
|
seed
|
int | None
|
Random seed for reproducibility (e.g. in tests). |
None
|
Raises:
| Type | Description |
|---|---|
ValueError
|
If |
Returns:
| Type | Description |
|---|---|
MiniSeismogram
|
Seismogram containing the generated noise. Data represent ground |
MiniSeismogram
|
acceleration (arbitrary units matching the noise model's PSD) unless |
MiniSeismogram
|
|
Examples:
>>> import pandas as pd
>>> from pysmo import MiniSeismogram
>>> from pysmo.tools.noise import peterson, generate_noise
>>> model = peterson(0.0)
>>> noise = generate_noise(
... model=model, npts=64, delta=pd.Timedelta(seconds=1.0), seed=42
... )
>>> isinstance(noise, MiniSeismogram)
True
>>> len(noise.data)
64
>>> noise.data[:3]
array([-4.20418403e-09, -1.25152943e-08, -8.42501771e-09])
>>>
Source code in src/pysmo/tools/noise.py
264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 | |
peterson
peterson(noise_level: float) -> NoiseModel
Generate a noise model by interpolating between Peterson's1 New Low Noise Model (NLNM) and New High Noise Model (NHNM).
-
Peterson, Jon R. Observations and Modeling of Seismic Background Noise. Report, 93–322, 1993, https://doi.org/10.3133/ofr93322. USGS Publications Warehouse. ↩
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
noise_level
|
float
|
Determines the noise level of the generated noise model. A noise level of 0 returns the NLNM, 1 returns the NHNM, and anything > 0 and < 1 returns an interpolated model that lies between the NLNM and NHNM. |
required |
Returns:
| Type | Description |
|---|---|
NoiseModel
|
Noise model. |
Examples:
>>> from pysmo.tools.noise import peterson, NLNM, NHNM
>>> peterson(0.0) == NLNM
True
>>> peterson(1.0) == NHNM
True
>>> model = peterson(0.5)
>>> model.psd[0] # midpoint of NLNM and NHNM at the shortest period
np.float64(-129.75)
>>>