diff --git a/.gitignore b/.gitignore index d32ae4e..647a13a 100644 --- a/.gitignore +++ b/.gitignore @@ -6,6 +6,9 @@ __pycache__/ # C extensions *.so +# Notebook example datasets downloaded locally +example_data/*/ + # Distribution / packaging .Python build/ diff --git a/conda/environment-ep-main.yml b/conda/environment-ep-main.yml index ff8889a..63902aa 100644 --- a/conda/environment-ep-main.yml +++ b/conda/environment-ep-main.yml @@ -12,6 +12,7 @@ dependencies: - numba # Helps ensure a recent version is installed - numpy<2 - pip + - pooch # -- holoviz -- - jupyter_bokeh - datashader diff --git a/conda/environment.yml b/conda/environment.yml index 7d86500..6bd6644 100644 --- a/conda/environment.yml +++ b/conda/environment.yml @@ -10,6 +10,7 @@ dependencies: - cartopy - scipy - numba # Helps ensure a recent version is installed + - pooch # -- holoviz -- - jupyter_bokeh - datashader diff --git a/notebooks/_config.yml b/notebooks/_config.yml index 4b38e9a..aeb562c 100644 --- a/notebooks/_config.yml +++ b/notebooks/_config.yml @@ -22,9 +22,9 @@ latex: # Information about where the book exists on the web repository: - url: https://github.com/OSOceanAcoustics/echopype-examples # Online location of your book - path_to_book: notebooks # Optional path to your book, relative to the repository root - branch: main # Which branch of the repository should be used when creating links (optional) + url: https://github.com/echostack-org/echopype-examples + path_to_book: notebooks + branch: main # Add GitHub buttons to your book # See https://jupyterbook.org/customize/config.html#add-a-link-to-your-repository diff --git a/notebooks/_toc.yml b/notebooks/_toc.yml index e112d10..26ea450 100644 --- a/notebooks/_toc.yml +++ b/notebooks/_toc.yml @@ -16,6 +16,7 @@ parts: - file: krill_freq_diff - file: hake_mask - file: glider_AZFP + - file: resample_to_geometry - caption: Community showcase numbered: False diff --git a/notebooks/gallery.yml b/notebooks/gallery.yml index a13da1c..3830b45 100644 --- a/notebooks/gallery.yml +++ b/notebooks/gallery.yml @@ -1,8 +1,8 @@ - section: Getting started items: - name: Getting Started with Echopype - website: https://echopype-examples.readthedocs.io/en/latest/getting_started.html - repository: https://github.com/OSOceanAcoustics/echopype-examples/blob/main/notebooks/getting_started.ipynb + website: getting_started.html + repository: https://github.com/echostack-org/echopype-examples/blob/main/notebooks/getting_started.ipynb notebook: getting_started.ipynb summary: A minimum example to get started on Echopype functions. image: images/gallery/01_getting_started.png @@ -10,53 +10,60 @@ - section: Processing items: - name: Watching Eclipse from a Moored Echosounder - website: https://echopype-examples.readthedocs.io/en/latest/OOI_eclipse.html - repository: https://github.com/OSOceanAcoustics/echopype-examples/blob/main/notebooks/OOI_eclipse.ipynb + website: OOI_eclipse.html + repository: https://github.com/echostack-org/echopype-examples/blob/main/notebooks/OOI_eclipse.ipynb notebook: OOI_eclipse.ipynb summary: Pairing acoustic data from an upward-looking echosounder and shortwave irradiance measured by a pyrometer on a surface mooring to observe the movement response of zooplankton to a solar eclipse. (Not binder friendly.) image: images/gallery/02_OOI_eclipse.png - name: Seafloor Detection - website: https://echopype-examples.readthedocs.io/en/latest/seafloor_detection.html - repository: https://github.com/OSOceanAcoustics/echopype-examples/blob/main/notebooks/seafloor_detection.ipynb + website: seafloor_detection.html + repository: https://github.com/echostack-org/echopype-examples/blob/main/notebooks/seafloor_detection.ipynb notebook: seafloor_detection.ipynb summary: Seafloor detection with echopype (two algorithms) and use of echoregions; compute a bottom line and mask below-bottom data. image: images/gallery/07_seafloor.png - name: Transient Noise Removal - website: https://echopype-examples.readthedocs.io/en/latest/transient_noise.html - repository: https://github.com/OSOceanAcoustics/echopype-examples/blob/main/notebooks/transient_noise.ipynb + website: transient_noise.html + repository: https://github.com/echostack-org/echopype-examples/blob/main/notebooks/transient_noise.ipynb notebook: transient_noise.ipynb summary: Transient noise removal with echopype (two algorithms) and exploring the effects on Sv profiles. image: images/gallery/08_transient_noise.png - name: Ship Tracks Visualisation - website: https://echopype-examples.readthedocs.io/en/latest/ship_tracks.html - repository: https://github.com/OSOceanAcoustics/echopype-examples/blob/main/notebooks/ship_tracks.ipynb + website: ship_tracks.html + repository: https://github.com/echostack-org/echopype-examples/blob/main/notebooks/ship_tracks.ipynb notebook: ship_tracks.ipynb summary: Subselect sections of echo data based on ship GPS data embedded in the echosounder raw files to demonstrate the power of label-aware data processing based on standardized netCDF data model. (Not binder friendly.) image: images/gallery/03_subselection.png - name: Krill Frequency Differencing - website: https://echopype-examples.readthedocs.io/en/latest/krill_freq_diff.html - repository: https://github.com/OSOceanAcoustics/echopype-examples/blob/main/notebooks/krill_freq_diff.ipynb + website: krill_freq_diff.html + repository: https://github.com/echostack-org/echopype-examples/blob/main/notebooks/krill_freq_diff.ipynb notebook: krill_freq_diff.ipynb summary: Perform frequency-differencing analysis to identify fluid-like zooplankton scatterers (likely krill) in ship echosounder data, and compute nautical acoustic scattering coefficient (NASC) based on the classification. (Not binder friendly.) image: images/gallery/04_krill.png - name: Masking Echogram and Computing NASC - website: https://echopype-examples.readthedocs.io/en/latest/hake_mask.html - repository: https://github.com/OSOceanAcoustics/echopype-examples/blob/main/notebooks/hake_mask.ipynb + website: hake_mask.html + repository: https://github.com/echostack-org/echopype-examples/blob/main/notebooks/hake_mask.ipynb notebook: hake_mask.ipynb summary: Incorporate an externally generated mask that identify the occurrence of Pacific hake in ship echosounder data, and compute NASC based on the masked outputs. image: images/gallery/05_NASC.png - name: Glider AZFP Processing - website: https://echopype-examples.readthedocs.io/en/latest/glider_AZFP.html - repository: https://github.com/OSOceanAcoustics/echopype-examples/blob/main/notebooks/glider_AZFP.ipynb + website: glider_AZFP.html + repository: https://github.com/echostack-org/echopype-examples/blob/main/notebooks/glider_AZFP.ipynb notebook: glider_AZFP.ipynb summary: Process acoustic data from a Slocum glider by incorporating external position, motion, and environmental data and identify zooplankton shoals. image: images/gallery/06_glider.png + - name: Resample Channels to a Common Range Geometry + website: resample_to_geometry.html + repository: https://github.com/echostack-org/echopype-examples/blob/main/notebooks/resample_to_geometry.ipynb + notebook: resample_to_geometry.ipynb + summary: Resample acoustic variables across channels to a reference channel geometry or a custom ping-dependent range grid. + image: images/gallery/10_resample_to_geometry.png + - section: Community showcase items: [] \ No newline at end of file diff --git a/notebooks/images/gallery/10_resample_to_geometry.png b/notebooks/images/gallery/10_resample_to_geometry.png new file mode 100644 index 0000000..dac8eb7 Binary files /dev/null and b/notebooks/images/gallery/10_resample_to_geometry.png differ diff --git a/notebooks/resample_to_geometry.ipynb b/notebooks/resample_to_geometry.ipynb new file mode 100644 index 0000000..1398379 --- /dev/null +++ b/notebooks/resample_to_geometry.ipynb @@ -0,0 +1,5772 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "id": "1755b086", + "metadata": {}, + "source": [ + "## Resample channels to a common range geometry" + ] + }, + { + "cell_type": "markdown", + "id": "193fcd24", + "metadata": {}, + "source": [ + "```{important}\n", + "This notebook uses development-version functionality that is not yet available in the latest released version of `echopype`.\n", + "\n", + "Users need to install `echopype` from source to reproduce the examples shown here.\n", + "```" + ] + }, + { + "cell_type": "markdown", + "id": "4bf4663c", + "metadata": {}, + "source": [ + "### Introduction\n", + "\n", + "Different frequencies may not share the same vertical sampling resolution or maximum range. When comparing channels directly, it is often useful to express them on a common range geometry. This notebook demonstrates three approaches:\n", + "\n", + "1. Resampling to the exact geometry of the 200 kHz channel.\n", + "2. Resampling to a custom regular grid using the 200 kHz spacing while extending the range support.\n", + "3. Resampling to a custom irregular `echo_range` grid whose spacing varies along range and between pings.\n", + "\n", + "The examples also verify the output dimensions and attributes, demonstrate the handling of linear variables such as angles, and illustrate how each choice affects the final data geometry." + ] + }, + { + "cell_type": "code", + "execution_count": 1, + "id": "6ec7b13c-3310-4f22-82b6-8c636441cf19", + "metadata": {}, + "outputs": [], + "source": [ + "import warnings\n", + "\n", + "import echopype as ep\n", + "import matplotlib.pyplot as plt\n", + "import numpy as np\n", + "import pandas as pd\n", + "import xarray as xr\n", + "\n", + "from echopype.commongrid import resample_to_geometry" + ] + }, + { + "cell_type": "markdown", + "id": "2dd1f5b5-7d8b-43d5-bc86-0455ca36c512", + "metadata": {}, + "source": [ + "#### Load an EK80 dataset\n", + "\n", + "We first load a multi-frequency EK80 dataset and compute calibrated volume backscattering strength (`Sv`).\n", + "Depth is then added to the dataset to simplify comparisons between channels with different acquisition geometries." + ] + }, + { + "cell_type": "code", + "execution_count": 2, + "id": "2d0b2ac9-4fba-4337-8f41-6e4edef56676", + "metadata": {}, + "outputs": [ + { + "data": { + "text/html": [ + "
<xarray.Dataset> Size: 926MB\n", + "Dimensions: (channel: 5, ping_time: 213,\n", + " range_sample: 36198, filenames: 1)\n", + "Coordinates:\n", + " * channel (channel) object 40B 'WBT 400140-15 ES120-...\n", + " * ping_time (ping_time) datetime64[ns] 2kB 2023-08-11T...\n", + " * range_sample (range_sample) int64 290kB 0 1 ... 36197\n", + " * filenames (filenames) int64 8B 0\n", + "Data variables: (12/26)\n", + " Sv (channel, ping_time, range_sample) float64 308MB ...\n", + " echo_range (channel, ping_time, range_sample) float64 308MB ...\n", + " tau_effective (channel) float64 40B 0.0009239 ... 0.0009306\n", + " frequency_nominal (channel) float64 40B 1.2e+05 ... 2e+05\n", + " sound_speed float64 8B 1.48e+03\n", + " sound_absorption (channel) float64 40B 0.03281 ... 0.0463\n", + " ... ...\n", + " impedance_transducer (channel) float64 40B 75.0 75.0 ... 75.0 75.0\n", + " impedance_transceiver (channel) int64 40B 5400 5400 5400 5400 5400\n", + " receiver_sampling_frequency (channel) float64 40B 1.5e+06 ... 1.5e+06\n", + " source_filenames (filenames) <U82 328B 's3://noaa-wcsd-pds/...\n", + " water_level float64 8B 0.0\n", + " depth (channel, ping_time, range_sample) float64 308MB ...\n", + "Attributes:\n", + " processing_software_name: echopype\n", + " processing_software_version: 0.11.2.dev62+gbd8d709e7\n", + " processing_time: 2026-07-17T22:15:48+00:00\n", + " processing_function: calibrate.compute_Sv
<xarray.Dataset> Size: 926MB\n", + "Dimensions: (ping_time: 213, range_sample: 36198, channel: 5)\n", + "Coordinates:\n", + " * ping_time (ping_time) datetime64[ns] 2kB 2023-08-11T16:57:27.277...\n", + " * range_sample (range_sample) int64 290kB 0 1 2 3 ... 36195 36196 36197\n", + " * channel (channel) object 40B 'WBT 400140-15 ES120-7C_ES' ... '...\n", + "Data variables:\n", + " Sv (channel, ping_time, range_sample) float64 308MB dask.array<chunksize=(1, 213, 36198), meta=np.ndarray>\n", + " echo_range (channel, ping_time, range_sample) float64 308MB dask.array<chunksize=(5, 213, 36198), meta=np.ndarray>\n", + " frequency_nominal (channel) float64 40B dask.array<chunksize=(1,), meta=np.ndarray>\n", + " water_level float64 8B 0.0\n", + " depth (channel, ping_time, range_sample) float64 308MB dask.array<chunksize=(5, 213, 36198), meta=np.ndarray>\n", + "Attributes:\n", + " processing_software_name: echopype\n", + " processing_software_version: 0.11.2.dev62+gbd8d709e7\n", + " processing_time: 2026-07-17T23:12:13+00:00\n", + " processing_function: commongrid.resample_to_geometry
<xarray.DataArray 'echo_range' (ping_time: 213, range_sample: 36198)> Size: 62MB\n", + "array([[0. , 0.02367923, 0.04735847, ..., nan, nan,\n", + " nan],\n", + " [0. , 0.02367923, 0.04735847, ..., nan, nan,\n", + " nan],\n", + " [0. , 0.02367923, 0.04735847, ..., nan, nan,\n", + " nan],\n", + " ...,\n", + " [0. , 0.02367923, 0.04735847, ..., nan, nan,\n", + " nan],\n", + " [0. , 0.02367923, 0.04735847, ..., nan, nan,\n", + " nan],\n", + " [0. , 0.02367923, 0.04735847, ..., nan, nan,\n", + " nan]], shape=(213, 36198))\n", + "Coordinates:\n", + " * ping_time (ping_time) datetime64[ns] 2kB 2023-08-11T16:57:27.277163 ....\n", + " * range_sample (range_sample) int64 290kB 0 1 2 3 ... 36194 36195 36196 36197
<xarray.Dataset> Size: 926MB\n", + "Dimensions: (ping_time: 213, range_sample: 36198, channel: 5)\n", + "Coordinates:\n", + " * ping_time (ping_time) datetime64[ns] 2kB 2023-08-11T16:57:27.277...\n", + " * range_sample (range_sample) int64 290kB 0 1 2 3 ... 36195 36196 36197\n", + " * channel (channel) object 40B 'WBT 400140-15 ES120-7C_ES' ... '...\n", + "Data variables:\n", + " Sv (channel, ping_time, range_sample) float64 308MB dask.array<chunksize=(1, 213, 36198), meta=np.ndarray>\n", + " echo_range (channel, ping_time, range_sample) float64 308MB 0.0 ....\n", + " frequency_nominal (channel) float64 40B dask.array<chunksize=(1,), meta=np.ndarray>\n", + " water_level float64 8B 0.0\n", + " depth (channel, ping_time, range_sample) float64 308MB 0.0 ....\n", + "Attributes:\n", + " processing_software_name: echopype\n", + " processing_software_version: 0.11.2.dev62+gbd8d709e7\n", + " processing_time: 2026-07-17T23:16:53+00:00\n", + " processing_function: commongrid.resample_to_geometry
| \n", + " | frequency_kHz | \n", + "original_grid_max_m | \n", + "strict_200_grid_max_m | \n", + "custom_grid_max_m | \n", + "original_last_finite_Sv_m | \n", + "strict_last_finite_Sv_m | \n", + "custom_last_finite_Sv_m | \n", + "
|---|---|---|---|---|---|---|---|
| 0 | \n", + "120.0 | \n", + "749.980496 | \n", + "299.968519 | \n", + "749.992335 | \n", + "749.980496 | \n", + "299.968519 | \n", + "749.992335 | \n", + "
| 1 | \n", + "18.0 | \n", + "749.977536 | \n", + "299.968519 | \n", + "749.992335 | \n", + "749.977536 | \n", + "299.968519 | \n", + "749.992335 | \n", + "
| 2 | \n", + "70.0 | \n", + "749.980496 | \n", + "299.968519 | \n", + "749.992335 | \n", + "749.980496 | \n", + "299.968519 | \n", + "749.992335 | \n", + "
| 3 | \n", + "38.0 | \n", + "749.980496 | \n", + "299.968519 | \n", + "749.992335 | \n", + "749.980496 | \n", + "299.968519 | \n", + "749.992335 | \n", + "
| 4 | \n", + "200.0 | \n", + "299.968519 | \n", + "299.968519 | \n", + "749.992335 | \n", + "299.968519 | \n", + "299.968519 | \n", + "299.968519 | \n", + "
| \n", + " | frequency_kHz | \n", + "sample_interval_s | \n", + "expected_spacing_m | \n", + "original_spacing_m | \n", + "resampled_spacing_m | \n", + "original_max_range_m | \n", + "resampled_max_range_m | \n", + "
|---|---|---|---|---|---|---|---|
| 0 | \n", + "120.0 | \n", + "0.000040 | \n", + "0.029599 | \n", + "0.029599 | \n", + "0.023679 | \n", + "749.980496 | \n", + "299.968519 | \n", + "
| 1 | \n", + "18.0 | \n", + "0.000028 | \n", + "0.020719 | \n", + "0.020719 | \n", + "0.023679 | \n", + "749.977536 | \n", + "299.968519 | \n", + "
| 2 | \n", + "70.0 | \n", + "0.000048 | \n", + "0.035519 | \n", + "0.035519 | \n", + "0.023679 | \n", + "749.980496 | \n", + "299.968519 | \n", + "
| 3 | \n", + "38.0 | \n", + "0.000040 | \n", + "0.029599 | \n", + "0.029599 | \n", + "0.023679 | \n", + "749.980496 | \n", + "299.968519 | \n", + "
| 4 | \n", + "200.0 | \n", + "0.000032 | \n", + "0.023679 | \n", + "0.023679 | \n", + "0.023679 | \n", + "299.968519 | \n", + "299.968519 | \n", + "
<xarray.Dataset> Size: 617MB\n", + "Dimensions: (ping_time: 213, range_sample: 36198, channel: 5)\n", + "Coordinates:\n", + " * ping_time (ping_time) datetime64[ns] 2kB 2023-08-11T16:57:27.277...\n", + " * range_sample (range_sample) int64 290kB 0 1 2 3 ... 36195 36196 36197\n", + " * channel (channel) object 40B 'WBT 400140-15 ES120-7C_ES' ... '...\n", + "Data variables:\n", + " Sv (channel, ping_time, range_sample) float64 308MB dask.array<chunksize=(1, 100, 36198), meta=np.ndarray>\n", + " echo_range (channel, ping_time, range_sample) float64 308MB 0.0 ....\n", + " frequency_nominal (channel) float64 40B dask.array<chunksize=(1,), meta=np.ndarray>\n", + " water_level float64 8B 0.0\n", + "Attributes:\n", + " processing_software_name: echopype\n", + " processing_software_version: 0.11.2.dev62+gbd8d709e7\n", + " processing_time: 2026-07-17T23:00:09+00:00\n", + " processing_function: commongrid.resample_to_geometry