Echopype: A quick exercise#

In this exercise we will do 4 things:

  • convert a .raw file collected by an EK80 echosounder

  • compute volume backscattering strength (Sv) from the parsed raw data

  • regrid the Sv data to mean volume backscattering strength (MVBS)

  • visualize using interactive plot

The details verbally discussed during the workshop can be found in the Getting started with Echopype notebook with some additional information, in the “echopype-examples” repository.

import echopype as ep  # we recommend using "ep"
import xarray as xr
import hvplot.xarray  # for interactive plots

import matplotlib.pyplot as plt

Convert a .raw file#

Echopype supports accessing data directly from multiple sources, such as a local filesystem (e.g., hard disk), a cloud object store (e.g., AWS S3), an http server, etc.

# Convert from an S3 bucket
raw_path = "s3://noaa-wcsd-pds/data/raw/Bell_M._Shimada/SH2306/EK80/Hake-D20230811-T165727.raw"
ed = ep.open_raw(
    raw_path,
    sonar_model="EK80",
    storage_options={"anon": True},  # open bucket, otherwise need credential
)

Check what’s in the raw file#

ed
EchoData: standardized raw data from Internal Memory
    • <xarray.DatasetView> Size: 0B
      Dimensions:  ()
      Data variables:
          *empty*
      Attributes:
          conventions:                 CF-1.7, SONAR-netCDF4-1.0, ACDD-1.3
          keywords:                    EK80
          sonar_convention_authority:  ICES
          sonar_convention_name:       SONAR-netCDF4
          sonar_convention_version:    1.0
          summary:                     
          title:                       
          date_created:                2023-08-11T16:57:27Z
          processing_level:            Level 1A
          processing_level_url:        https://echopype.readthedocs.io/en/stable/pr...

      • <xarray.DatasetView> Size: 156B
        Dimensions:                       (time1: 1, sound_velocity_profile_depth: 2)
        Coordinates:
          * time1                         (time1) datetime64[ns] 8B 2023-08-11T16:57:...
          * sound_velocity_profile_depth  (sound_velocity_profile_depth) float64 16B ...
        Data variables:
            depth                         (time1) float64 8B 200.0
            acidity                       (time1) float64 8B 8.0
            salinity                      (time1) float64 8B 33.7
            temperature                   (time1) float64 8B 6.9
            sound_speed_indicative        (time1) float64 8B 1.48e+03
            sound_velocity_profile        (time1, sound_velocity_profile_depth) float64 16B ...
            sound_velocity_source         (time1) <U10 40B 'Calculated'
            transducer_name               (time1) <U7 28B 'Unknown'
            transducer_sound_speed        (time1) float64 8B 1.48e+03

      • <xarray.DatasetView> Size: 127kB
        Dimensions:                      (time1: 1451, time2: 1837, channel: 5, time3: 1)
        Coordinates:
          * channel                      (channel) <U25 500B 'WBT 400140-15 ES120-7C_...
          * time1                        (time1) datetime64[ns] 12kB 2023-08-11T16:57...
          * time2                        (time2) datetime64[ns] 15kB 2023-08-11T16:57...
          * time3                        (time3) datetime64[ns] 8B 2023-08-11T16:57:2...
        Data variables: (12/26)
            latitude                     (time1) float64 12kB 43.95 43.95 ... 43.95
            longitude                    (time1) float64 12kB -125.0 -125.0 ... -124.9
            sentence_type                (time1) <U3 17kB 'GGA' 'GLL' ... 'GGA' 'GLL'
            pitch                        (time2) float64 15kB -0.01 -0.03 ... 1.38 1.46
            roll                         (time2) float64 15kB -0.11 0.26 ... 0.87 0.86
            vertical_offset              (time2) float64 15kB 0.71 0.64 ... -0.61 -0.62
            ...                           ...
            position_offset_y            float64 8B nan
            position_offset_z            float64 8B nan
            frequency_nominal            (channel) float64 40B 1.2e+05 1.8e+04 ... 2e+05
            heading                      (time2) float64 15kB 94.5 94.5 ... 91.4 91.4
            latitude_mru1                (time3) float64 8B nan
            longitude_mru1               (time3) float64 8B nan
        Attributes:
            platform_name:       
            platform_type:       
            platform_code_ICES:  

        • <xarray.DatasetView> Size: 2MB
          Dimensions:        (nmea_time: 5479, channel: 5, time1: 1451, time2: 1837,
                              time3: 1)
          Coordinates:
            * channel        (channel) <U25 500B 'WBT 400140-15 ES120-7C_ES' ... 'WBT 4...
            * time1          (time1) datetime64[ns] 12kB 2023-08-11T16:57:27.277163 ......
            * time2          (time2) datetime64[ns] 15kB 2023-08-11T16:57:28.465496 ......
            * time3          (time3) datetime64[ns] 8B 2023-08-11T16:57:27.277163
            * nmea_time      (nmea_time) datetime64[ns] 44kB 2023-08-11T16:57:27.277163...
          Data variables:
              NMEA_datagram  (nmea_time) <U70 2MB '$SDVLW,4418.987,N,4418.987,N' ... '$...
          Attributes:
              description:  All NMEA sensor datagrams

      • <xarray.DatasetView> Size: 336B
        Dimensions:           (filenames: 1)
        Coordinates:
          * filenames         (filenames) int64 8B 0
        Data variables:
            source_filenames  (filenames) <U82 328B 's3://noaa-wcsd-pds/data/raw/Bell...
        Attributes:
            conversion_software_name:     echopype
            conversion_software_version:  0.10.1
            conversion_time:              2025-04-07T02:15:25Z

      • <xarray.DatasetView> Size: 1kB
        Dimensions:                    (channel_all: 5, beam_group: 1)
        Coordinates:
          * channel_all                (channel_all) <U25 500B 'WBT 400140-15 ES120-7...
          * beam_group                 (beam_group) <U11 44B 'Beam_group1'
        Data variables:
            frequency_nominal          (channel_all) float64 40B 1.2e+05 ... 2e+05
            transceiver_serial_number  (channel_all) <U6 120B '400140' ... '400145'
            transducer_name            (channel_all) <U4 80B 'ES18' 'ES18' ... 'ES18'
            transducer_serial_number   (channel_all) <U1 20B '0' '0' '0' '0' '0'
            beam_group_descr           (beam_group) <U131 524B 'contains backscatter ...
        Attributes:
            sonar_manufacturer:      Simrad
            sonar_model:             EK80
            sonar_serial_number:     
            sonar_software_name:     EK80
            sonar_software_version:  21.15.2.0
            sonar_type:              echosounder

        • <xarray.DatasetView> Size: 465MB
          Dimensions:                        (channel: 5, ping_time: 213,
                                              range_sample: 36198, transmit_sample: 148,
                                              channel_all: 5, beam_group: 1)
          Coordinates:
            * channel_all                    (channel_all) <U25 500B 'WBT 400140-15 ES1...
            * beam_group                     (beam_group) <U11 44B 'Beam_group1'
            * channel                        (channel) <U25 500B 'WBT 400140-15 ES120-7...
            * ping_time                      (ping_time) datetime64[ns] 2kB 2023-08-11T...
            * range_sample                   (range_sample) int64 290kB 0 1 ... 36197
            * transmit_sample                (transmit_sample) int64 1kB 0 1 2 ... 146 147
          Data variables: (12/29)
              frequency_nominal              (channel) float64 40B 1.2e+05 ... 2e+05
              beam_type                      (channel) int64 40B 1 1 1 1 1
              beamwidth_twoway_alongship     (channel) float64 40B 6.63 10.92 ... 6.79
              beamwidth_twoway_athwartship   (channel) float64 40B 6.74 10.6 ... 6.81 6.07
              beam_direction_x               (channel) float64 40B nan nan nan nan nan
              beam_direction_y               (channel) float64 40B nan nan nan nan nan
              ...                             ...
              transmit_power                 (channel, ping_time) float64 9kB 250.0 ......
              transmit_duration_nominal      (channel, ping_time) float32 4kB 0.001024 ...
              slope                          (channel, ping_time) float64 9kB 0.01628 ....
              channel_mode                   (channel, ping_time) int8 1kB 0 0 0 ... 0 0 0
              transmit_type                  (channel, ping_time) <U3 13kB 'CW' ... 'CW'
              sample_time_offset             (channel, ping_time) float64 9kB 0.0 ... 0.0
          Attributes:
              beam_mode:              vertical
              conversion_equation_t:  type_3

      • <xarray.DatasetView> Size: 353kB
        Dimensions:                      (channel: 5, pulse_length_bin: 5,
                                          cal_channel_id: 3, cal_frequency: 269,
                                          WBT_filter_n: 47, PC_filter_n: 123)
        Coordinates:
          * channel                      (channel) <U25 500B 'WBT 400140-15 ES120-7C_...
          * pulse_length_bin             (pulse_length_bin) int64 40B 0 1 2 3 4
          * cal_frequency                (cal_frequency) int64 2kB 45000 ... 241459
          * cal_channel_id               (cal_channel_id) object 24B 'WBT 400140-15 E...
        Dimensions without coordinates: WBT_filter_n, PC_filter_n
        Data variables: (12/21)
            frequency_nominal            (channel) float64 40B 1.2e+05 1.8e+04 ... 2e+05
            sa_correction                (channel, pulse_length_bin) float64 200B 0.0...
            gain_correction              (channel, pulse_length_bin) float64 200B 27....
            pulse_length                 (channel, pulse_length_bin) float64 200B 6.4...
            impedance_transceiver        (channel) int64 40B 5400 5400 5400 5400 5400
            receiver_sampling_frequency  (channel) float64 40B 1.5e+06 ... 1.5e+06
            ...                           ...
            WBT_filter_r                 (channel, WBT_filter_n) float32 940B 0.00045...
            WBT_decimation               (channel) int64 40B 6 6 6 6 6
            PC_filter_i                  (channel, PC_filter_n) float32 2kB -2.988e-0...
            PC_filter_r                  (channel, PC_filter_n) float32 2kB -5.649e-0...
            PC_decimation                (channel) int64 40B 10 7 12 10 8
            config_xml                   <U74340 297kB '<?xml version="1.0" encoding=...

Save the EchoData object#

# Save to zarr
ed.to_zarr("./resources", overwrite="w")  # save with the same filename, different extension
# Save to netCDF
ed.to_netcdf("./resources/Hake-D20230811-T165727.nc", overwrite="w")  # fully specify the filename also works

Im-memory vs lazy-loaded data#

# Lazy-load EchoData using xarray kwargs (keyword arguments)
ed_lazy = ep.open_converted("./resources/Hake-D20230811-T165727.zarr", chunks={})
# In-memory
ed["Sonar/Beam_group1"]["backscatter_r"]
<xarray.DataArray 'backscatter_r' (channel: 5, ping_time: 213,
                                   range_sample: 36198)> Size: 154MB
array([[[  10.383183  ,   13.875601  ,   16.015736  , ...,
                   nan,           nan,           nan],
        [  10.430219  ,   13.910878  ,   16.051014  , ...,
                   nan,           nan,           nan],
        [  10.383183  ,   13.875601  ,   16.015736  , ...,
                   nan,           nan,           nan],
        ...,
        [  10.465496  ,   13.969673  ,   16.121567  , ...,
                   nan,           nan,           nan],
        [  10.465496  ,   13.969673  ,   16.121567  , ...,
                   nan,           nan,           nan],
        [  10.430219  ,   13.899119  ,   16.051014  , ...,
                   nan,           nan,           nan]],

       [[ -11.782502  ,   -5.7031074 ,   -0.50563633, ...,
         -125.868164  , -126.09158   , -126.29149   ],
        [ -11.711948  ,   -5.6443124 ,   -0.47035936, ...,
         -133.06467   , -130.23074   , -127.82016   ],
        [ -11.770743  ,   -5.6795893 ,   -0.49387732, ...,
         -133.14697   , -132.48848   , -131.8182    ],
...
        [   3.5394542 ,   10.41846   ,   15.780557  , ...,
                   nan,           nan,           nan],
        [   3.4689002 ,   10.383183  ,   15.757039  , ...,
                   nan,           nan,           nan],
        [   3.4924183 ,   10.383183  ,   15.757039  , ...,
                   nan,           nan,           nan]],

       [[   6.067636  ,    8.866274  ,   10.747711  , ...,
                   nan,           nan,           nan],
        [   6.079395  ,    8.842756  ,   10.747711  , ...,
                   nan,           nan,           nan],
        [   6.2087436 ,    9.019141  ,   10.912337  , ...,
                   nan,           nan,           nan],
        ...,
        [   6.3028154 ,    9.077936  ,   10.959373  , ...,
                   nan,           nan,           nan],
        [   6.2087436 ,    9.0309    ,   10.935855  , ...,
                   nan,           nan,           nan],
        [   6.3028154 ,    9.077936  ,   10.971132  , ...,
                   nan,           nan,           nan]]], dtype=float32)
Coordinates:
  * channel       (channel) <U25 500B 'WBT 400140-15 ES120-7C_ES' ... 'WBT 40...
  * ping_time     (ping_time) datetime64[ns] 2kB 2023-08-11T16:57:27.277163 ....
  * range_sample  (range_sample) int64 290kB 0 1 2 3 ... 36194 36195 36196 36197
Attributes:
    long_name:  Raw backscatter measurements (real part)
    units:      dB
# Lazy-loaded
ed_lazy["Sonar/Beam_group1"]["backscatter_r"]
<xarray.DataArray 'backscatter_r' (channel: 5, ping_time: 213,
                                   range_sample: 36198)> Size: 154MB
dask.array<open_dataset-backscatter_r, shape=(5, 213, 36198), dtype=float32, chunksize=(5, 213, 23474), chunktype=numpy.ndarray>
Coordinates:
  * channel       (channel) <U25 500B 'WBT 400140-15 ES120-7C_ES' ... 'WBT 40...
  * ping_time     (ping_time) datetime64[ns] 2kB 2023-08-11T16:57:27.277163 ....
  * range_sample  (range_sample) int64 290kB 0 1 2 3 ... 36194 36195 36196 36197
Attributes:
    long_name:  Raw backscatter measurements (real part)
    units:      dB

Compute Sv#

# Use the correct waveform_mode and encode_mode combination
ds_Sv = ep.calibrate.compute_Sv(ed, waveform_mode="CW", encode_mode="power")
ds_Sv = ep.consolidate.add_depth(ds_Sv, ed)

Check how the Sv data look like:

ds_Sv["Sv"].plot(
    x="ping_time", 
    row="channel", col_wrap=3,
    vmin=-80, vmax=-30,
    cmap="RdYlBu_r", yincrease=False
)
<xarray.plot.facetgrid.FacetGrid at 0x284e78470>
_images/e9e235932863c350d515610daa7699a70e40a5d96706e48514b695fe00319f80.png

Regrid to MVBS#

# Compute MVBS
ds_MVBS = ep.commongrid.compute_MVBS(
    ds_Sv,
    range_var="depth",
    range_bin="1m",
    ping_time_bin="5s",
    range_var_max="500m",  # max range to bin
)

See how MVBS data are now all aligned with one another (hence the name commingrid):

ds_MVBS = ds_MVBS.swap_dims({"channel": "frequency_nominal"})
ds_MVBS["Sv"].plot(
    x="ping_time",
    row="frequency_nominal", col_wrap=3,
    cmap='RdYlBu_r', yincrease=False,
    vmin=-80, vmax=-30
)
<xarray.plot.facetgrid.FacetGrid at 0x28aeac4d0>
_images/5f3042b0340c30442ea664d72a702348c400b7edf8d8927ff14c062dfd8d3093.png

Try interactive plotting#

ds_MVBS["Sv"].hvplot.quadmesh(
    x="ping_time", clim=(-80, -30), figsize=(6, 6), cmap="RdYlBu_r", rasterize=True,
    groupby="frequency_nominal"
).opts(invert_yaxis=True, height=400)

Save the MVBS dataset for future use#

ds_MVBS.to_zarr("./resources/Hake-D20230811-T165727_MVBS.zarr", mode="w")
<xarray.backends.zarr.ZarrStore at 0x28b148280>