Getting Started#

Welcome to the NoisePy Colab Tutorial!

This tutorial will walk you through the basic steps of using NoisePy to compute ambient noise cross correlation functions.

First, we install the noisepy-seis package

# Uncomment and run this line if the environment doesn't have noisepy already installed:
# ! pip install noisepy-seis 

Warning: NoisePy uses obspy as a core Python module to manipulate seismic data. Restart the runtime now for proper installation of obspy on Colab.

Then we import the basic modules

from noisepy.seis import download, cross_correlate, stack_cross_correlations, __version__
from noisepy.seis.io import plotting_modules
from noisepy.seis.io.asdfstore import ASDFRawDataStore, ASDFCCStore, ASDFStackStore
from noisepy.seis.io.datatypes import CCMethod, ConfigParameters, FreqNorm, RmResp, TimeNorm
from datetime import datetime, timezone
from datetimerange import DateTimeRange
import os
import shutil
print(f"Using NoisePy version {__version__}")

path = os.path.join(".", "get_started_data")

os.makedirs(path,exist_ok=True)
raw_data_path = os.path.join(path, "RAW_DATA")
cc_data_path = os.path.join(path, "CCF")
stack_data_path = os.path.join(path, "STACK")
/opt/hostedtoolcache/Python/3.10.20/x64/lib/python3.10/site-packages/noisepy/seis/io/utils.py:13: TqdmExperimentalWarning: Using `tqdm.autonotebook.tqdm` in notebook mode. Use `tqdm.tqdm` instead to force console mode (e.g. in jupyter console)
  from tqdm.autonotebook import tqdm
Using NoisePy version 0.1.dev1

Ambient Noise Project Configuration#

We store the metadata information about the ambient noise cross correlation workflow in a ConfigParameters() object. We first initialize it, then we tune the parameters for this cross correlation.

config = ConfigParameters() # default config parameters which can be customized
config.inc_hours = 12
config.sampling_rate = 20  # (int) Sampling rate in Hz of desired processing (it can be different than the data sampling rate)
config.cc_len = 3600  # (float) basic unit of data length for fft (sec)
    # criteria for data selection
config.ncomp = 3  # 1 or 3 component data (needed to decide whether do rotation)

config.acorr_only = False  # only perform auto-correlation or not
config.xcorr_only = True  # only perform cross-correlation or not

config.inc_hours = 12 # if the data is first 

config.lamin = 31       # min latitude
config.lamax = 42       # max latitude
config.lomin = -124     # min longitude
config.lomax = -115     # max longitude

# pre-processing parameters
config.step = 1800.0  # (float) overlapping between each cc_len (sec)
config.stationxml = False  # station.XML file used to remove instrument response for SAC/miniseed data
config.rm_resp = RmResp.INV  # select 'no' to not remove response and use 'inv' if you use the stationXML,'spectrum',
config.freqmin = 0.05
config.freqmax = 2.0
config.max_over_std  = 10  # threshold to remove window of bad signals: set it to 10*9 if prefer not to remove them

# TEMPORAL and SPECTRAL NORMALISATION
config.freq_norm = FreqNorm.RMA # choose between "rma" for a soft whitenning or "no" for no whitening. Pure whitening is not implemented correctly at this point.
config.smoothspect_N = 10  # moving window length to smooth spectrum amplitude (points)
    # here, choose smoothspect_N for the case of a strict whitening (e.g., phase_only)

config.time_norm = TimeNorm.NO  # 'no' for no normalization, or 'rma', 'one_bit' for normalization in time domain,
    # TODO: change time_norm option from "no" to "None"
config.smooth_N = 10  # moving window length for time domain normalization if selected (points)

config.cc_method = CCMethod.XCORR # 'xcorr' for pure cross correlation OR 'deconv' for deconvolution;
    # FOR "COHERENCY" PLEASE set freq_norm to "rma", time_norm to "no" and cc_method to "xcorr"

# OUTPUTS:
config.substack = True  # True = smaller stacks within the time chunk. False: it will stack over inc_hours
config.substack_windows = 1  # how long to stack over (for monitoring purpose)
    # if substack=True, substack_windows=2, then you pre-stack every 2 correlation windows.
    # for instance: substack=True, substack_windows=1 means that you keep ALL of the correlations

config.maxlag = 200  # lags of cross-correlation to save (sec)
config.substack = True

Step 0: download data#

This step will download data using obspy and save them into ASDF files locally. The data will be stored for each time chunk defined in hours by inc_hours.

The download will clean up the raw data by detrending, removing the mean, bandpassing (broadly), removing the instrumental response, merging gaps, ignoring too-gappy data.

Use the function download with the following arguments:

  • path:where to put the data

  • config: configuration settings, in particular:

    • channel: list of the seismic channels to download, and example is shown below

    • stations: list of the seismic stations, it can be “*” (not “all”)

    • start_time

    • end_time

  • client_url_key: the string for FDSN clients

config.networks = ["*"]
config.stations = ["A*"]
config.channels = ["BH?"]
config.start_date = datetime(2019, 2, 1, tzinfo=timezone.utc)
config.end_date = datetime(2019, 2, 2, tzinfo=timezone.utc)
timerange = DateTimeRange(config.start_date, config.end_date)

# Download data locally. Enters raw data path, channel types, stations, config, and fdsn server.
download(raw_data_path, config)
2026-05-01 23:00:21 | INFO | fdsn_download.download() | Download
        From: 2019-02-01T00:00:00.000000Z
        To: 2019-02-02T00:00:00.000000Z
        Networks: ['*']
        Stations: ['A*']
        Channels: ['BH?']
        
2026-05-01 23:00:24 | INFO | fdsn_download.download() | Fetched inventory
2026-05-01 23:00:29 | INFO | fdsn_download.download() | Downloaded BHE/bhe_00
2026-05-01 23:00:29 | INFO | fdsn_download.download() | Downloaded BHN/bhn_00
2026-05-01 23:00:29 | INFO | fdsn_download.download() | Downloaded BHE/bhe_00
2026-05-01 23:00:30 | INFO | fdsn_download.download() | Downloaded BHE/bhe_00
2026-05-01 23:00:30 | INFO | fdsn_download.download() | Downloaded BHN/bhn_00
2026-05-01 23:00:30 | INFO | fdsn_download.download() | Downloaded BHZ/bhz_00
2026-05-01 23:00:30 | INFO | fdsn_download.download() | Downloaded BHZ/bhz_00
2026-05-01 23:00:30 | INFO | fdsn_download.download() | Downloaded BHN/bhn_00
2026-05-01 23:00:32 | INFO | fdsn_download.download() | Downloaded BHE/bhe_00
2026-05-01 23:00:32 | INFO | fdsn_download.download() | Downloaded BHZ/bhz_00
2026-05-01 23:00:32 | INFO | fdsn_download.download() | Downloaded BHZ/bhz_00
2026-05-01 23:00:33 | INFO | fdsn_download.download() | Downloaded BHN/bhn_00
2026-05-01 23:00:37 | INFO | fdsn_download.download() | Downloaded BHN/bhn_00
2026-05-01 23:00:37 | INFO | fdsn_download.download() | Downloaded BHN/bhn_00
2026-05-01 23:00:37 | INFO | fdsn_download.download() | Downloaded BHE/bhe_00
2026-05-01 23:00:37 | INFO | fdsn_download.download() | Downloaded BHZ/bhz_00
2026-05-01 23:00:38 | INFO | fdsn_download.download() | Downloaded BHE/bhe_00
2026-05-01 23:00:38 | INFO | fdsn_download.download() | Downloaded BHE/bhe_00
2026-05-01 23:00:38 | INFO | fdsn_download.download() | Downloaded BHN/bhn_00
2026-05-01 23:00:39 | INFO | fdsn_download.download() | Downloaded BHZ/bhz_00
2026-05-01 23:00:40 | INFO | fdsn_download.download() | Downloaded BHZ/bhz_00
2026-05-01 23:00:40 | INFO | fdsn_download.download() | Downloaded BHN/bhn_00
2026-05-01 23:00:41 | INFO | fdsn_download.download() | Downloaded BHE/bhe_00
2026-05-01 23:00:41 | INFO | fdsn_download.download() | Downloaded BHZ/bhz_00

List the files that were downloaded, just to make sure !

print(os.listdir(raw_data_path))
['2019_02_01_00_00_00T2019_02_01_12_00_00.h5', 'station.csv', '2019_02_01_12_00_00T2019_02_02_00_00_00.h5']

Plot the raw data, make sure it’s noise!

file = os.path.join(raw_data_path, "2019_02_01_00_00_00T2019_02_01_12_00_00.h5")
raw_store = ASDFRawDataStore(raw_data_path) # Store for reading raw data
timespans = raw_store.get_timespans()
plotting_modules.plot_waveform(raw_store, timespans[0], 'CI','ADO', 0.01, 0.4) # this function takes for input: filename, network, station, freqmin, freqmax for a bandpass filter
_images/088d36a7f8d2106453ae49a5a350c1cd912e128ae54f3654a2838b745fd8af72.png

Step 1: Cross-correlation#

This step will perform the cross correlation. For each time chunk, it will read the data, perform classic ambient noise pre-processing (time and frequency normalization), FFT, cross correlation, substacking, saving cross correlations in to a temp ASDF file (this is not fast and will be improved).

# For this tutorial make sure the previous run is empty
if os.path.exists(cc_data_path):
    shutil.rmtree(cc_data_path)
config.freq_norm = FreqNorm.RMA
cc_store = ASDFCCStore(cc_data_path) # Store for writing CC data

# print the configuration parameters. Some are chosen by default but we cab modify them
print(config)
client_url_key='SCEDC' start_date=datetime.datetime(2019, 2, 1, 0, 0, tzinfo=datetime.timezone.utc) end_date=datetime.datetime(2019, 2, 2, 0, 0, tzinfo=datetime.timezone.utc) sampling_rate=20 single_freq=True cc_len=3600 lamin=31 lamax=42 lomin=-124 lomax=-115 down_list=False networks=['*'] stations=['A*'] channels=['BH?'] step=1800.0 freqmin=0.05 freqmax=2.0 freq_norm=<FreqNorm.RMA: 'rma'> time_norm=<TimeNorm.NO: 'no'> cc_method=<CCMethod.XCORR: 'xcorr'> smooth_N=10 smoothspect_N=10 substack=True substack_windows=1 maxlag=200 inc_hours=12 max_over_std=10 ncomp=3 stationxml=False rm_resp=<RmResp.INV: 'inv'> rm_resp_out='VEL' respdir=None acorr_only=False xcorr_only=True stack_method=<StackMethod.LINEAR: 'linear'> keep_substack=False rotation=True correction=False correction_csv=None storage_options=defaultdict(<class 'dict'>, {})

Perform the cross correlation

cross_correlate(raw_store, config, cc_store)
2026-05-01 23:00:42 | INFO | correlate.cross_correlate() | Starting cross-correlation with 4 cores
2026-05-01 23:00:42 | INFO | correlate.cc_timespan() | Checking for stations already done: 10 pairs
2026-05-01 23:00:42 | INFO | correlate.cc_timespan() | Still need to process: 4/4 stations, 12/12 channels, 10/10 pairs for 2019-02-01T00:00:00+0000 - 2019-02-01T12:00:00+0000
2026-05-01 23:00:47 | INFO | correlate.cc_timespan() | Starting CC with 10 station pairs
2026-05-01 23:00:49 | INFO | correlate.cc_timespan() | Checking for stations already done: 10 pairs
2026-05-01 23:00:49 | INFO | correlate.cc_timespan() | Still need to process: 4/4 stations, 12/12 channels, 10/10 pairs for 2019-02-01T12:00:00+0000 - 2019-02-02T00:00:00+0000
2026-05-01 23:00:54 | INFO | correlate.cc_timespan() | Starting CC with 10 station pairs

Plot a single set of the cross correlation

pairs = cc_store.get_station_pairs()
timespans = cc_store.get_timespans(*pairs[0])
plotting_modules.plot_substack_cc(cc_store, timespans[0], 0.1, 1, 200, False)
_images/96313c270e094e012bfd5c53bee55bd7fed8ffad5d35bca5807715f900dcaa27.png _images/518e1ee44371d51c4858653f41bce64d02f22ad9cd2e1b9ef20d815a0235429c.png _images/bf403d5919b60c7477b528e017d5cf8d598859e607f15a2018dbc09ba9297a66.png _images/ca0f92dedd678115d2eceae5dd0cf5b5d8028bda266bafb06879a318b53e26f3.png _images/43d03895546cddf1c9b596145ce53f3e6a47bbcc7c8c944e812d1d3a8469ebca.png _images/d5777e98d2fbd9e67e749beb5082513599252d83a05ccdbaa61593d08a89643c.png _images/579aee46dd0a1233f0d68fa40820c2ae9ad7d3153a8253e5715d7b39dcb15647.png _images/8665b541cd5ae6d127e35caa7fbad7540b44407b058ba3ab35c2d01105f1fdf7.png _images/86f3149b58b3b77b82b68214a6cc1408d568dfbbcf55e7858b311c6a64c82712.png _images/3a4283672b02ad8687c4691bb1725db68e100331652822765bd8a5c5b7d79a1d.png _images/f1358b4a967b28f9f6188f9a424f577cea390a3b1e3516bff6c7ecb7a8acb168.png _images/4a99a956b129697c12f32a29eff040958c5bbc02960a844c975193e70c041d9e.png _images/08da6ce90298a8bab1290fdfe714f0223a33628363632dc08edf996de46db969.png _images/e1085954704efba5a38d5bacc55560fec522704dbc4d254928a2f19ccf77d02b.png _images/f5c57f14e411401f1d92ee6988efc6a7e264a7f75409851752ff93429fc4c191.png _images/da3a9040de1e2e83756941b00c7ea23efb495b76b0332435bb5d6b36d6fd095b.png _images/c7ebbaa4ff0e7f26e1f27f9c1799f2df1b06126923bb64304e1a7a0ab5246ace.png _images/3a3610ebe4f6a5def6f3cf5f029459d4762dd7264a094413abcf7d37591f3fed.png _images/29b0fda1eb682436177fddd1735c198c7b1e228501fcfe7b052963636b1701eb.png _images/b2b88bdbf8ca3bb435c0b5d96d178b53fdd839845134ae45c48b59e2539e0986.png _images/a0c0841302bfa109e0a214e8a474bfbb2e71ca76fb3e32a923a15b274c733252.png _images/2cf8d7173ca7cf0cf66d82ae05834446529535d201f6040d59eff1342c0be6aa.png _images/be528d6f1207d68ae1fc5ca00e90ad80d1effacfabdc4f8a5dd9f5781417aad8.png _images/7e86c74bc840128909a380f2b905070456c4af1df3ab33d50a0e9aa54f1beba8.png _images/588efacd30396141e2e62ee87ef713ee96bd7cd81bd1328dc00b684efe30c2cc.png _images/45dc5c7b7ece8707feaa3fce1a79eaac5ee9a1566f303acc8bdf36250f2d7ee8.png _images/06a20657ddf96be2304e44854bef7d7ac2423775c1a4789f286fdfded44d7b5c.png _images/1eaf7fee4f2687b5f9b7ed500f30b4df87eec7062aec8807b3dac533805faca8.png _images/9c051c293cbad1583b7d09779e3a01cd17558947ea7c73ae3d9a9ec0720aabf9.png _images/b1d441e2058c430bf7252afc945fa662672094a4b46babb649d531ccfc4729fe.png _images/bdb466b592436934ce72f9dc184f594bae5361c03ada4f22e0f6110ff81477c6.png _images/5e9c64917f131380110ff235075b11bc79b020464ae54c3576772d2e1785fc41.png _images/ec05071903eba01f582743476d735bde0290db64ef7e2655d396e3abe8c4691d.png _images/286ee3975c922402c39d65cf92e2374f13d729563d5f0f74e53ff35e1ebb6a9f.png _images/b09513ecff9a7b6113eba9c8ba98c6ceada09648632ff32d53f2e69afd7e7929.png _images/9c6070170a97a0019e0c853bf29dcd010e0dd5a9a2548d10bb565e30a38faa36.png _images/9df73d9734bd7649d7a69beb2cd2734f22802b8a2cd7bde0765344f374db2b70.png _images/81091cfc0e498d7b2b9bb148a3816571cb17774d5bd955f0554076611732c2d6.png _images/5e77cf0e5cb7ece30a6430ea75f762154dce565d28536dea72f4ebc4214ac3ec.png _images/a59d8d1c51bf699c3df4f90c4b2e459bb55174e2ae3680e1abec280fc0afa1e8.png _images/3edb2d7366d2b176d0a18f7d2a14942a783170c5ce3b975f1ac3b4fd7557503d.png _images/ec378066a2c5ff32cbfeb9cd77cfc3c41829f19ddb6ba69ce621f7f3f89e1296.png _images/d8c3c9a93db2d3d867374469b7d6ba8e623dd4d5f8d98bd7bdcb3479a85df29e.png _images/fbe214708d7e91dc5a9068a90e3c96e8900c6fae10856d58f82babdc0c95c955.png _images/5150bbe98e089d56169039511991d17bc340468bdbedde70f00b515afe2a2866.png _images/a1c227b33a31d8ee4680c4047b645c6aaab441a80bd3f7766c7697d8ed395c50.png _images/35f0fbb13a69b4bcf8ccdc19d94850d839872e961d7f64aa0793d1274501383c.png _images/6e006953a5a6e5b4781c04906b42659de04d3feccff5b1c8c8da06078bcb410c.png _images/5abb5ad9a4a1c25efac7296a438c31cb2d89289050163428a5b3c0dd45628bd6.png _images/e77d32dcd0719f11c54190ec38bb18f6f6ec96477933fde83d6153b37bdd3b19.png _images/9e159b956d28f9c3975513c57d28f23af3e99681e5c948b76ef35ac7861be035.png _images/1b976fe33383cdd6c6b6fabea02d48ee388268d6de436c68556736da205ebcbe.png _images/8d2d95f7ac4af290ed009579d867877a10dfdc4c2cc7ebc5bde923acc6fe73c1.png _images/8c803de1a29db3e0381b8fb5815f5f048dffa5d3a714db19caaca48974160ea4.png _images/88699a202947ddd9edf3628ed522c8f567d35d3e7471ceb6dff49204889f2a59.png _images/f0e85c8af8588d9d383a603e1cb9aa15ca1e98d1e01f6f00d6a7275e2ac19a4a.png _images/5fa42fa25fab5e27e2174f3c437959b7775b220abae5c1d1e248ce189280a54d.png _images/7c2aa9a1633b43368c167b9eaa86adb5d0dcc084d291db4725a4bce7568a23a7.png _images/11d70e49164c161ca3442e59547b302c5a5d97d2154103f10c395fb1f688a6bf.png _images/d8fd8bbd8f938450ecd54a3ad4efb3f9106b3ed562d409d655f752f6d14d7c83.png _images/50ec2c52d4b5c2e962c40f0fa4d0a0e742419d20f1c5958ea99a654fa0da2451.png _images/3974f6280f165bdc60dad5573515dbbc34bbb9dfc1f56f35cbea72a25fa33a05.png _images/b6aad4e4156bb11bf294938435b3f87d0a3ff0745ed5c148f56cdc8cc8250073.png _images/bd39ded41ff8473738468badaa596a00125c7a0d3798ba53965b02d0ac48c3a2.png _images/89dbc187f0cf9ad5d909d7eea62426641f0128c962f896173040f76f695b3d48.png _images/8e67e95e3181a141883d78d69e75dc83609240facfb7fd28098634e86e6b0850.png _images/73a5b601552485dee8b1e244a7ad7da90b00f636da03125d77afb4c684f2e2a1.png _images/4a6c9fb089b2b1df805afa8859294fb2092dfd30d1cf21bb63693e068dfb2bc6.png _images/87989c07a30c376ad65c45cafa14b3f25284f2aecfc313ba78215774eb751fc1.png _images/91613b93af3fb29302bc27df56f3e16f90374ccfecb30fecc71020d4b4dd1017.png _images/25e3d06f1fee1842fe7bc6eb0c96c21129678e46c699a2a5d0c43609973bc0c7.png _images/12676a9cd20324c6f7a586556b9bd554de4b9e889282f6201172144131b42538.png _images/89ddadf5804abba4c7c55e2f7acdf8a248da3a9228eef1da906c017544c01ec7.png _images/18b3cee831852c990972ef967122d6a581b6e8a1ba71b412ee040c4e1f1e6b87.png _images/fb5a182c14cb7e8aeba44ae0419dd40f5402c0656e39115d2ed42252feba2a0a.png _images/3ccea9e5d500055c322254edcf539391cf93b8afeea3ca5a7b673a258f256ca1.png _images/a9a30109abcae6373fc80658729aa308dd3f23eb3e368774a619c67eac722ebc.png _images/d3625e525d6443301e0943a62cc049d42a921bc94fa07c6e823d577a06ff4fc0.png

Step 2: Stack the cross correlation#

This combines the time-chunked ASDF files to stack over each time chunk and at each station pair.

# open a new cc store in read-only mode since we will be doing parallel access for stacking
cc_store = ASDFCCStore(cc_data_path, mode="r")
print(cc_store.get_station_pairs())
stack_store = ASDFStackStore(stack_data_path)
config.stations = ["*"] # stacking doesn't support prefixes yet, so allow all stations
stack_cross_correlations(cc_store, stack_store, config)
2026-05-01 23:01:16 | INFO | stack.initializer() | Station pairs: 10
[(CI.ALP, CI.AVM), (CI.ALP, CI.ARV), (CI.ADO, CI.ARV), (CI.ARV, CI.AVM), (CI.AVM, CI.AVM), (CI.ALP, CI.ALP), (CI.ARV, CI.ARV), (CI.ADO, CI.AVM), (CI.ADO, CI.ALP), (CI.ADO, CI.ADO)]
pairs = stack_store.get_station_pairs()
print(f"Found {len(pairs)} station pairs")
sta_stacks = stack_store.read_bulk(timerange, pairs) # no timestamp used in ASDFStackStore
Found 10 station pairs

Plot the stacks

print(os.listdir(cc_data_path))
print(os.listdir(stack_data_path))
['2019_02_01_00_00_00T2019_02_01_12_00_00.h5', '2019_02_01_12_00_00T2019_02_02_00_00_00.h5']
['CI.ARV', 'CI.ADO', 'CI.AVM', 'CI.ALP']
plotting_modules.plot_all_moveout(sta_stacks, 'Allstack_linear', 0.1, 0.2, 'ZZ', 1)
2026-05-01 23:01:21 | INFO | plotting_modules.plot_all_moveout() | Plotting 10 pairs from Allstack_linear
200 8001
_images/1b214b0046a94b3ba798ee3230117a2b56ef159c51fda31a057ee2e8fa30844e.png