.. DO NOT EDIT. .. THIS FILE WAS AUTOMATICALLY GENERATED BY SPHINX-GALLERY. .. TO MAKE CHANGES, EDIT THE SOURCE PYTHON FILE: .. "auto_gallery/plot_adcp_data.py" .. LINE NUMBERS ARE GIVEN BELOW. .. only:: html .. note:: :class: sphx-glr-download-link-note :ref:`Go to the end ` to download the full example code. .. rst-class:: sphx-glr-example-title .. _sphx_glr_auto_gallery_plot_adcp_data.py: Estimating directional spectra from ADCP data ============================================= This example show how to compute the wavelet-based directional wave spectra from bottom-mounted ADCP (Acoustic Doppler Current Profilers) data using different approaches. First, as ADCP usually have 3 to 5 (sometimes more) slanted acoustic beams, the surface elevation at different spatial points can be extracted. This is done considering that the acoustic backscatter is maximum when is reflected by the sea surface. The spatial array is then constructed projecting the beam geometry onto the sea surface. The second approach consider the triplet formed by the horizontal components of the wave-induced velocty and the echo-based surface elevation from the vertical beam (see `Pelaez-Zapata et al. 2024`_ for more details.) .. _Pelaez-Zapata et al. 2024: https://doi.org/10.1175/JTECH-D-23-0058.1 .. GENERATED FROM PYTHON SOURCE LINES 22-32 .. code-block:: Python import numpy as np import xarray as xr from matplotlib import pyplot as plt import ewdm from ewdm.plots import plot_directional_spectrum .. GENERATED FROM PYTHON SOURCE LINES 33-41 Exploring ADCP dataset ---------------------- As you can see, the typical ADCP data contains echo-based sea surface elevation at each acoustic beam so we can try to compute the directional spectrum using our `ewdm.Arrays` approach, but also we see the three velocty components, which means that we can also compute the directional spectra using our `ewdm.Triplets` approach. .. GENERATED FROM PYTHON SOURCE LINES 41-45 .. code-block:: Python adcp_dataset = xr.open_dataset("../../data/adcp_test_data.nc") print(adcp_dataset) .. rst-class:: sphx-glr-script-out .. code-block:: none Size: 2MB Dimensions: (beam: 5, time: 3720, cell: 38) Coordinates: * time (time) datetime64[ns] 30kB 2017-02-23 ... 2017-02-23T00:30:59.5... * cell (cell) int32 152B 1 2 3 4 5 6 7 8 9 ... 30 31 32 33 34 35 36 37 38 * beam (beam) int32 20B 1 2 3 4 5 Data variables: eta (beam, time) float32 74kB ... vel_x (cell, time) float32 565kB ... vel_y (cell, time) float32 565kB ... vel_z (cell, time) float32 565kB ... pressure (time) float32 15kB ... z_cell (cell) float32 152B ... Attributes: title: ADCP deployment winter 2016/2017 coast off of In... summary: ADCP deployment winter 2016/2017 coast off of In... latitude: 53.0671 longitude: -9.6266 institution: UCD Wave Group date_created: 2020-09-16 convention: CF-1.8 keywords: adcp, ocean currents, sea_surface_waves, aran_is... platform: ADCP Teledyne RDI Sentinel V creator: Daniel Pelaez-Zapata principal_investigator: Frederic Dias .. GENERATED FROM PYTHON SOURCE LINES 47-52 .. code-block:: Python water_depth = adcp_dataset["pressure"].mean("time").item() print(f"The total water depth is {water_depth:.2f} m") print(f"The number of vertical cells is: {len(adcp_dataset['cell'])}") print(f"The number acoustic beams is: {len(adcp_dataset['beam'])}") .. rst-class:: sphx-glr-script-out .. code-block:: none The total water depth is 46.09 m The number of vertical cells is: 38 The number acoustic beams is: 5 .. GENERATED FROM PYTHON SOURCE LINES 53-57 Triplets approach ----------------- Let's first try the triplets approach as it is more direct. .. GENERATED FROM PYTHON SOURCE LINES 57-89 .. code-block:: Python norm = lambda x: x - np.nanmean(x) time = adcp_dataset["time"].data surface_elevation = norm(adcp_dataset["eta"].sel(beam=5).data) fig, ax = plt.subplots(1, 3, figsize=(8,3), layout="constrained") for i, cell in enumerate([5, 10, 20]): cell_depth = water_depth-adcp_dataset["z_cell"].isel(cell=cell).item() eastward_velocity = norm(adcp_dataset["vel_x"].isel(cell=cell).data) northward_velocity = norm(adcp_dataset["vel_y"].isel(cell=cell).data) spec = ewdm.Triplets.from_numpy( time = time, surface_elevation = surface_elevation, eastward_velocity = eastward_velocity, northward_velocity = northward_velocity, ) output_triplets = spec.compute(use="velocities") plot_directional_spectrum( output_triplets.directional_spectrum, ax=ax[i], levels=None, colorbar=True, vmin=0, vmax=0.1, axes_kw={"rmin": 0.1, "rmax": 0.35, "rstep": 0.1, "angle": 225}, cbar_kw={"label": ""} ) ax[i].set(title=f"$z={-cell_depth:.2f}$ m", ylabel="") .. image-sg:: /auto_gallery/images/sphx_glr_plot_adcp_data_001.png :alt: $z=-23.74$ m, $z=-17.64$ m, $z=-5.44$ m :srcset: /auto_gallery/images/sphx_glr_plot_adcp_data_001.png :class: sphx-glr-single-img .. GENERATED FROM PYTHON SOURCE LINES 90-98 Arrays approach --------------- Now let's see the array-based approach. First, we need to project the ADCP beam geomtry on the sea surface and then compute the x-y coordinates of each element of the array. For this, we must know the tilt angle (which is generally 25 degrees), the water depth and the location of each beam. I will compute first the x-y-coordinates passing from polar to cartesian coordinates. .. GENERATED FROM PYTHON SOURCE LINES 98-118 .. code-block:: Python # compute beam distribution tilt_angle = 25 radius = water_depth * np.sin(np.radians(tilt_angle)) # angles = np.array([0, 180, 90, 270, 0]) angles = np.array([180, 0, 90, 270, 0]) radii = np.array([radius, radius, radius, radius, 0]) x = radii * np.cos(np.radians(angles)) y = radii * np.sin(np.radians(angles)) # compute spectra eta = adcp_dataset["eta"].interpolate_na("time").data.T spec = ewdm.Arrays.from_numpy( time = time, surface_elevation = eta, position_x = x, position_y = y ) output_array = spec.compute() .. GENERATED FROM PYTHON SOURCE LINES 119-120 Let's plot array distribution .. GENERATED FROM PYTHON SOURCE LINES 120-129 .. code-block:: Python fig, ax = plt.subplots(1, 1, figsize=(5,5)) for i, (ix, iy) in enumerate(zip(x, y)): ax.plot(ix, iy, "o", color="#6145b5", ms=20) ax.text(ix, iy, f"{i+1}", color="w", ha="center", va="center") ax.margins(0.2) ax.set_xlabel("x [m]") ax.set_ylabel("y [m]") ax.set_title("Beam distribution") .. image-sg:: /auto_gallery/images/sphx_glr_plot_adcp_data_002.png :alt: Beam distribution :srcset: /auto_gallery/images/sphx_glr_plot_adcp_data_002.png :class: sphx-glr-single-img .. rst-class:: sphx-glr-script-out .. code-block:: none Text(0.5, 1.0, 'Beam distribution') .. GENERATED FROM PYTHON SOURCE LINES 130-131 Finally, let's plot the directional spectra .. GENERATED FROM PYTHON SOURCE LINES 131-148 .. code-block:: Python fig, (ax1, ax2) = plt.subplots(1, 2, figsize=(8,3)) ax1.set_title("Array-based approach") ax2.set_title(f"Triplet-based $z={-cell_depth:.2f}$ m") plot_directional_spectrum( output_array.directional_spectrum, ax=ax1, levels=None, colorbar=True, vmin=0, vmax=0.1, axes_kw={"rmin": 0.1, "rmax": 0.35, "rstep": 0.1, "angle": 225}, cbar_kw={"label": ""} ) plot_directional_spectrum( output_triplets.directional_spectrum, ax=ax2, levels=None, colorbar=True, vmin=0, vmax=0.1, axes_kw={"rmin": 0.1, "rmax": 0.35, "rstep": 0.1, "angle": 225}, cbar_kw={"label": ""} ) .. image-sg:: /auto_gallery/images/sphx_glr_plot_adcp_data_003.png :alt: Array-based approach, Triplet-based $z=-5.44$ m :srcset: /auto_gallery/images/sphx_glr_plot_adcp_data_003.png :class: sphx-glr-single-img .. rst-class:: sphx-glr-timing **Total running time of the script:** (0 minutes 1.987 seconds) .. _sphx_glr_download_auto_gallery_plot_adcp_data.py: .. only:: html .. container:: sphx-glr-footer sphx-glr-footer-example .. container:: sphx-glr-download sphx-glr-download-jupyter :download:`Download Jupyter notebook: plot_adcp_data.ipynb ` .. container:: sphx-glr-download sphx-glr-download-python :download:`Download Python source code: plot_adcp_data.py ` .. container:: sphx-glr-download sphx-glr-download-zip :download:`Download zipped: plot_adcp_data.zip ` .. only:: html .. rst-class:: sphx-glr-signature `Gallery generated by Sphinx-Gallery `_