ADCP Example
The following example shows a typical workflow for analyzing ADCP data using DOLfYN’s tools.
A typical ADCP data workflow is broken down into 1. Review the raw data - Check timestamps - Calculate/check that the depth bin locations are correct - Look at velocity, beam amplitude and/or beam correlation data quality 2. Remove data located above the water surface or below the seafloor 3. Check for spurious datapoints and remove if necessary 4. If not already done within the instrument, average the data into bins of a set time length (normally 5 to 10 min) 5. Conduct further analysis as required
Start by importing the necessary DOLfYN tools through MHKiT:
[1]:
# Import core DOLfYN functions
import dolfyn as dlfn
# Import ADCP-specific API tools
from dolfyn.adp import api
Read Raw Instrument Data
The core benefit of DOLfYN is that it can read in raw data directly after transferring it off of the ADCP. The ADCP used here is a Nortek Signature 1000, with the file extension ‘.ad2cp’. This specific dataset contains several hours worth of velocity data collected at 1 Hz from the ADCP mounted on a bottom lander in a tidal inlet. The instruments that DOLfYN supports are listed in the docs.
Start by reading in the raw datafile downloaded from the instrument. The read
function reads the raw file and dumps the information into an xarray Dataset, which contains a few groups of variables:
Velocity in the instrument-saved coordinate system (beam, XYZ, ENU)
Beam amplitude and correlation data
Measurements of the instrument’s bearing and environment
Orientation matrices DOLfYN uses for rotating through coordinate frames.
The “nens” (number of ensembles) option is specified here to read the first 50k profiles for this notebook example, and can be left out to read the entire datafile
[2]:
dat = dlfn.read('../dolfyn/example_data/Sig1000_tidal.ad2cp')
Indexing ../dolfyn/example_data/Sig1000_tidal.ad2cp... Done.
Reading file ../dolfyn/example_data/Sig1000_tidal.ad2cp ...
To see what’s in an xarray Dataset, simply type the dataset’s name. To access a particular variable in a dataset, use dict-style (ds['vel']
) or attribute-style syntax (ds.vel
). See the xarray docs for more details on how to use the xarray format.
[3]:
# print the dataset
dat
[3]:
<xarray.Dataset> Dimensions: (time: 55000, time_b5: 55000, dirIMU: 3, range_b5: 28, beam: 4, range: 28, dir: 4, inst: 3, earth: 3, q: 4, x*: 4) Coordinates: * time (time) float64 1.597e+09 1.597e+09 ... 1.598e+09 * time_b5 (time_b5) float64 1.597e+09 1.597e+09 ... 1.598e+09 * dirIMU (dirIMU) <U1 'E' 'N' 'U' * range_b5 (range_b5) float64 0.6 1.1 1.6 2.1 ... 13.1 13.6 14.1 * beam (beam) int32 1 2 3 4 * range (range) float64 0.6 1.1 1.6 2.1 ... 12.6 13.1 13.6 14.1 * dir (dir) <U2 'E' 'N' 'U1' 'U2' * inst (inst) <U1 'X' 'Y' 'Z' * earth (earth) <U1 'E' 'N' 'U' * q (q) <U1 'w' 'x' 'y' 'z' * x* (x*) int32 1 2 3 4 Data variables: (12/35) c_sound (time) float32 1.502e+03 1.502e+03 ... 1.498e+03 temp (time) float32 14.55 14.55 14.55 ... 13.47 13.47 13.47 pressure (time) float32 9.713 9.718 9.718 ... 9.596 9.594 9.596 mag (dirIMU, time) float32 72.5 72.7 72.6 ... -197.2 -195.7 accel (dirIMU, time) float32 -0.00479 -0.01437 ... 9.729 batt (time) float32 16.6 16.6 16.6 16.6 ... 16.4 16.4 15.2 ... ... quaternion_b5 (q, time_b5) float32 0.6245 0.6245 ... 0.7787 0.7786 status0_b5 (time_b5) uint16 32768 32768 32768 ... 32768 32768 heading (time) float32 -12.52 -12.51 -12.51 ... -12.52 -12.5 pitch (time) float32 -0.065 -0.06 -0.06 ... -0.06 -0.05 -0.05 roll (time) float32 -7.425 -7.42 -7.42 ... -6.45 -6.45 -6.45 beam2inst_orientmat (beam, x*) float32 1.183 0.0 -1.183 ... 0.0 0.5518 Attributes: (12/35) filehead_config: {'CLOCKSTR': {'TIME': '"2020-08-13 13:56:21"'}, 'ID':... inst_model: Signature1000 inst_make: Nortek inst_type: ADCP rotate_vars: ['vel', 'accel', 'accel_b5', 'angrt', 'angrt_b5', 'ma... burst_config: {'press_valid': True, 'temp_valid': True, 'compass_va... ... ... power_level_b5: 0 coord_sys: earth orientation: AHRS orient_status: AHRS-3D has_imu: 1 fs: 1
- time: 55000
- time_b5: 55000
- dirIMU: 3
- range_b5: 28
- beam: 4
- range: 28
- dir: 4
- inst: 3
- earth: 3
- q: 4
- x*: 4
- time(time)float641.597e+09 1.597e+09 ... 1.598e+09
- description :
- seconds since 1970-01-01 00:00:00
array([1.597476e+09, 1.597476e+09, 1.597476e+09, ..., 1.597531e+09, 1.597531e+09, 1.597531e+09])
- time_b5(time_b5)float641.597e+09 1.597e+09 ... 1.598e+09
- description :
- seconds since 1970-01-01 00:00:00
array([1.597476e+09, 1.597476e+09, 1.597476e+09, ..., 1.597531e+09, 1.597531e+09, 1.597531e+09])
- dirIMU(dirIMU)<U1'E' 'N' 'U'
array(['E', 'N', 'U'], dtype='<U1')
- range_b5(range_b5)float640.6 1.1 1.6 2.1 ... 13.1 13.6 14.1
- units :
- m
array([ 0.6, 1.1, 1.6, 2.1, 2.6, 3.1, 3.6, 4.1, 4.6, 5.1, 5.6, 6.1, 6.6, 7.1, 7.6, 8.1, 8.6, 9.1, 9.6, 10.1, 10.6, 11.1, 11.6, 12.1, 12.6, 13.1, 13.6, 14.1])
- beam(beam)int321 2 3 4
array([1, 2, 3, 4])
- range(range)float640.6 1.1 1.6 2.1 ... 13.1 13.6 14.1
- units :
- m
array([ 0.6, 1.1, 1.6, 2.1, 2.6, 3.1, 3.6, 4.1, 4.6, 5.1, 5.6, 6.1, 6.6, 7.1, 7.6, 8.1, 8.6, 9.1, 9.6, 10.1, 10.6, 11.1, 11.6, 12.1, 12.6, 13.1, 13.6, 14.1])
- dir(dir)<U2'E' 'N' 'U1' 'U2'
- ref_frame :
- earth
array(['E', 'N', 'U1', 'U2'], dtype='<U2')
- inst(inst)<U1'X' 'Y' 'Z'
array(['X', 'Y', 'Z'], dtype='<U1')
- earth(earth)<U1'E' 'N' 'U'
array(['E', 'N', 'U'], dtype='<U1')
- q(q)<U1'w' 'x' 'y' 'z'
array(['w', 'x', 'y', 'z'], dtype='<U1')
- x*(x*)int321 2 3 4
array([1, 2, 3, 4])
- c_sound(time)float321.502e+03 1.502e+03 ... 1.498e+03
- units :
- m/s
array([1501.9, 1501.9, 1501.9, ..., 1498.4, 1498.3, 1498.3], dtype=float32)
- temp(time)float3214.55 14.55 14.55 ... 13.47 13.47
- units :
- deg C
array([14.55, 14.55, 14.55, ..., 13.47, 13.47, 13.47], dtype=float32)
- pressure(time)float329.713 9.718 9.718 ... 9.594 9.596
- units :
- dbar
array([9.713, 9.718, 9.718, ..., 9.596, 9.594, 9.596], dtype=float32)
- mag(dirIMU, time)float3272.5 72.7 72.6 ... -197.2 -195.7
- units :
- uT
array([[ 72.5, 72.7, 72.6, ..., 72.3, 72.8, 72.4], [ 9.3, 9.4, 8.9, ..., 5.9, 6.3, 6.4], [-198. , -196.3, -198.1, ..., -197.4, -197.2, -195.7]], dtype=float32)
- accel(dirIMU, time)float32-0.00479 -0.01437 ... 9.685 9.729
- units :
- m/s^2
array([[-4.7900393e-03, -1.4370117e-02, -2.3950195e-02, ..., -1.4370117e-02, -4.7900393e-03, -2.3950195e-02], [-1.2933105e+00, -1.2549902e+00, -1.2645704e+00, ..., -1.1017090e+00, -1.0873389e+00, -1.0969189e+00], [ 9.7285690e+00, 9.7141991e+00, 9.7237797e+00, ..., 9.6710892e+00, 9.6854591e+00, 9.7285690e+00]], dtype=float32)
- batt(time)float3216.6 16.6 16.6 ... 16.4 16.4 15.2
- units :
- V
array([16.6, 16.6, 16.6, ..., 16.4, 16.4, 15.2], dtype=float32)
- temp_mag(time)float64-8.062e+03 ... -8.332e+03
- units :
- deg C
array([-8062. , -8062. , -8013. , ..., -8331.5, -8405. , -8331.5])
- temp_clock(time)float3220.0 20.0 20.0 ... 19.5 19.5 19.5
- units :
- deg C
array([20. , 20. , 20. , ..., 19.5, 19.5, 19.5], dtype=float32)
- error(time)uint160 0 0 0 0 0 0 0 ... 0 0 0 0 0 0 0 0
- units :
array([0, 0, 0, ..., 0, 0, 0], dtype=uint16)
- status(time)uint321053556738 ... 1053557762
- units :
- binary
array([1053556738, 1053556738, 1053556738, ..., 1053556738, 1053556738, 1053557762], dtype=uint32)
- ensemble_count(time)uint321 1 1 1 1 1 1 1 ... 1 1 1 1 1 1 1 1
- units :
array([1, 1, 1, ..., 1, 1, 1], dtype=uint32)
- vel(dir, range, time)float32-0.015 -0.048 ... -0.015 -0.012
- units :
- m/s
array([[[-0.015, -0.048, 0.008, ..., -0.176, -0.071, -0.027], [-0.093, -0.124, -0.031, ..., -0.175, -0.16 , -0.03 ], [-0.163, -0.135, -0.105, ..., -0.129, -0.089, -0.116], ..., [-0.169, -0.013, -0.124, ..., -0.062, 0.091, -0.009], [-0.16 , -0.043, -0.111, ..., 0.012, 0.089, 0.021], [-0.158, -0.057, -0.13 , ..., -0.055, 0.104, 0.013]], [[ 0.243, 0.204, 0.234, ..., -0.163, -0.135, -0.18 ], [ 0.272, 0.248, 0.236, ..., -0.254, -0.169, -0.204], [ 0.257, 0.294, 0.333, ..., -0.299, -0.226, -0.273], ..., [ 0.305, 0.377, 0.283, ..., -0.198, -0.229, -0.121], [ 0.328, 0.33 , 0.294, ..., -0.161, -0.292, -0.103], [ 0.31 , 0.314, 0.226, ..., -0.219, -0.292, -0.049]], [[ 0.016, 0.012, 0.01 , ..., 0.009, 0.006, -0.018], [ 0.01 , 0.011, -0.013, ..., 0.002, -0.027, 0.009], [ 0.01 , 0.009, 0.023, ..., -0.018, -0.002, -0.024], ..., [ 0.034, -0.061, -0.024, ..., -0.014, 0.086, 0.01 ], [ 0.032, -0.04 , -0.027, ..., -0.014, 0.063, -0.01 ], [ 0.004, -0.037, -0.018, ..., -0.001, 0.059, 0.021]], [[ 0.003, -0.007, 0.046, ..., -0.032, -0.008, -0.029], [ 0.017, 0.033, 0.035, ..., -0.016, -0.022, -0.034], [ 0.016, -0.012, 0.005, ..., 0.002, -0.045, -0.026], ..., [-0.044, 0.015, -0.04 , ..., -0.015, 0.006, 0.012], [-0.013, 0.014, -0.032, ..., 0.01 , 0. , -0.015], [ 0.007, 0.016, -0.027, ..., -0.002, -0.015, -0.012]]], dtype=float32)
- amp(beam, range, time)float3281.0 80.0 80.5 ... 43.5 42.5 42.0
- units :
- dB
array([[[81. , 80. , 80.5, ..., 81.5, 81.5, 81.5], [75. , 74.5, 75. , ..., 79. , 77. , 77.5], [73.5, 72. , 72. , ..., 75. , 74.5, 75. ], ..., [54.5, 55.5, 54.5, ..., 50. , 50. , 49.5], [53.5, 54.5, 54.5, ..., 46.5, 47. , 46.5], [53. , 54. , 53. , ..., 45. , 46. , 44.5]], [[81.5, 80. , 80.5, ..., 82. , 81.5, 82. ], [76. , 77. , 76.5, ..., 79. , 77.5, 77.5], [73.5, 74. , 73. , ..., 75.5, 74.5, 74.5], ..., [57. , 58.5, 58. , ..., 53.5, 52. , 52.5], [55.5, 56.5, 55.5, ..., 50. , 49. , 49. ], [52.5, 54. , 54. , ..., 47.5, 47.5, 47. ]], [[80.5, 79.5, 80. , ..., 81.5, 82.5, 81.5], [76. , 75.5, 75. , ..., 77. , 78.5, 77. ], [72. , 73.5, 72. , ..., 74. , 75. , 73.5], ..., [56.5, 56.5, 57. , ..., 47.5, 47. , 48. ], [56. , 55.5, 56.5, ..., 46.5, 47. , 47. ], [54.5, 54. , 55.5, ..., 45. , 45.5, 45.5]], [[80. , 81. , 80. , ..., 81. , 81. , 81.5], [75.5, 75.5, 74.5, ..., 76.5, 76.5, 77.5], [73. , 72.5, 73. , ..., 75.5, 74.5, 74. ], ..., [51.5, 51. , 51. , ..., 46. , 46. , 45. ], [51. , 50. , 51. , ..., 45. , 44. , 43.5], [50.5, 49.5, 50. , ..., 43.5, 42.5, 42. ]]], dtype=float32)
- corr(beam, range, time)uint8100 91 91 97 99 ... 96 98 98 98 96
- units :
- %
array([[[100, 91, 91, ..., 89, 90, 96], [ 74, 92, 96, ..., 100, 97, 100], [100, 100, 99, ..., 99, 100, 100], ..., [ 99, 100, 100, ..., 96, 96, 99], [ 99, 97, 100, ..., 94, 97, 96], [ 98, 100, 100, ..., 100, 100, 98]], [[ 94, 90, 89, ..., 91, 92, 90], [ 94, 100, 100, ..., 96, 100, 93], [ 99, 95, 97, ..., 98, 98, 100], ..., [100, 100, 100, ..., 98, 99, 100], [ 99, 100, 99, ..., 97, 94, 94], [ 96, 99, 96, ..., 97, 100, 97]], [[ 92, 93, 93, ..., 93, 97, 89], [ 99, 100, 99, ..., 96, 88, 98], [ 97, 100, 98, ..., 100, 99, 97], ..., [100, 100, 99, ..., 97, 94, 95], [100, 100, 100, ..., 96, 100, 100], [100, 100, 100, ..., 96, 95, 94]], [[ 87, 97, 87, ..., 91, 87, 90], [100, 93, 93, ..., 96, 96, 97], [100, 100, 100, ..., 100, 100, 97], ..., [100, 99, 96, ..., 98, 100, 100], [100, 100, 100, ..., 94, 93, 95], [100, 98, 99, ..., 98, 98, 96]]], dtype=uint8)
- orientmat(inst, earth, time)float32-0.2167 -0.2164 ... 0.9937 0.9937
array([[[-2.16688156e-01, -2.16397047e-01, -2.16593146e-01, ..., -2.16118217e-01, -2.16699123e-01, -2.16318965e-01], [-9.67970312e-01, -9.68004048e-01, -9.67982769e-01, ..., -9.70095694e-01, -9.69992876e-01, -9.70033050e-01], [-1.26469478e-01, -1.26385525e-01, -1.26422524e-01, ..., -1.10033900e-01, -1.10009573e-01, -1.09963998e-01]], [[ 9.76196468e-01, 9.76219118e-01, 9.76202846e-01, ..., 9.76315439e-01, 9.76210594e-01, 9.76245522e-01], [-2.15024590e-01, -2.14734554e-01, -2.14924574e-01, ..., -2.14874983e-01, -2.15436578e-01, -2.15052128e-01], [-2.68291458e-02, -2.68030688e-02, -2.68616974e-02, ..., -2.31788009e-02, -2.33813375e-02, -2.34001204e-02]], [[-1.22870505e-03, -1.20262802e-03, -1.17563456e-03, ..., -1.16243958e-03, -1.02279335e-03, -9.55920666e-04], [-1.29278094e-01, -1.29190803e-01, -1.29239410e-01, ..., -1.12442717e-01, -1.12462208e-01, -1.12422116e-01], [ 9.91607308e-01, 9.91618454e-01, 9.91612315e-01, ..., 9.93657291e-01, 9.93655324e-01, 9.93659675e-01]]], dtype=float32)
- angrt(dirIMU, time)float32-0.001953 -0.001953 ... -0.00293
- units :
- rad/s
array([[-0.00195312, -0.00195312, -0.00195312, ..., -0.00390625, -0.00292969, -0.00195312], [ 0.00097656, 0. , 0. , ..., 0. , 0.00097656, 0.00097656], [-0.00292969, -0.00292969, -0.00292969, ..., -0.00292969, -0.00195312, -0.00292969]], dtype=float32)
- quaternion(q, time)float320.6245 0.6245 ... 0.7787 0.7786
array([[ 0.6244507 , 0.62454224, 0.6244812 , ..., 0.625 , 0.6247864 , 0.62490845], [-0.04101562, -0.04098511, -0.04098511, ..., -0.03570557, -0.03564453, -0.03561401], [-0.05014038, -0.05010986, -0.05014038, ..., -0.04354858, -0.04360962, -0.04360962], [ 0.77835083, 0.7782593 , 0.7783203 , ..., 0.77856445, 0.77874756, 0.7786255 ]], dtype=float32)
- status0(time)uint1632768 32768 32768 ... 32768 32768
- units :
- binary
array([32768, 32768, 32768, ..., 32768, 32768, 32768], dtype=uint16)
- temp_press(time)float3212.8 12.8 12.8 ... 12.0 12.0 12.0
- units :
- deg C
array([12.8, 12.8, 12.8, ..., 12. , 12. , 12. ], dtype=float32)
- mag_b5(dirIMU, time_b5)float3272.9 72.8 72.4 ... -198.0 -195.7
- units :
- uT
array([[ 72.9, 72.8, 72.4, ..., 73. , 73. , 72.7], [ 9.5, 9.5, 9.8, ..., 6. , 6.4, 5.9], [-197.1, -197.2, -197.7, ..., -197.4, -198. , -195.7]], dtype=float32)
- accel_b5(dirIMU, time_b5)float32-0.01437 0.0 ... 9.709 9.724
- units :
- m/s^2
array([[-1.4370117e-02, 0.0000000e+00, -1.4370117e-02, ..., -4.7900393e-03, -1.9160157e-02, -1.4370117e-02], [-1.2693603e+00, -1.2885205e+00, -1.2837305e+00, ..., -1.0825489e+00, -1.1017090e+00, -1.1064991e+00], [ 9.7189894e+00, 9.7046194e+00, 9.7094088e+00, ..., 9.7141991e+00, 9.7094088e+00, 9.7237797e+00]], dtype=float32)
- error_b5(time_b5)uint160 0 0 0 0 0 0 0 ... 0 0 0 0 0 0 0 0
- units :
array([0, 0, 0, ..., 0, 0, 0], dtype=uint16)
- status_b5(time_b5)uint321053556738 ... 1053557762
- units :
- binary
array([1053556738, 1053556738, 1053556738, ..., 1053556738, 1053556738, 1053557762], dtype=uint32)
- ensemble_count_b5(time_b5)uint321 1 1 1 1 1 1 1 ... 1 1 1 1 1 1 1 1
- units :
array([1, 1, 1, ..., 1, 1, 1], dtype=uint32)
- vel_b5(range_b5, time_b5)float320.003 0.021 0.018 ... -0.048 0.09
- units :
- m/s
array([[ 0.003, 0.021, 0.018, ..., 0. , -0.044, 0.009], [ 0.057, 0.034, 0.017, ..., 0.01 , 0.001, -0.002], [ 0.039, 0.022, 0.02 , ..., 0.039, -0.008, 0.018], ..., [-0.036, -0.013, 0.058, ..., 0.058, -0.013, 0.028], [-0.043, -0.009, 0.028, ..., 0.092, -0.021, 0.019], [-0.073, 0.003, 0. , ..., 0.049, -0.048, 0.09 ]], dtype=float32)
- amp_b5(range_b5, time_b5)float3280.5 80.5 80.0 ... 46.5 46.0 47.5
- units :
- dB
array([[80.5, 80.5, 80. , ..., 82. , 81.5, 81. ], [75.5, 76.5, 76. , ..., 78.5, 78. , 77.5], [72.5, 73.5, 73.5, ..., 75. , 76.5, 75.5], ..., [57.5, 57.5, 57. , ..., 49. , 49. , 48.5], [56.5, 57. , 56. , ..., 47.5, 48. , 48. ], [55.5, 55.5, 55. , ..., 46.5, 46. , 47.5]], dtype=float32)
- corr_b5(range_b5, time_b5)uint898 100 92 93 98 ... 100 99 94 100
- units :
- %
array([[ 98, 100, 92, ..., 88, 90, 91], [ 97, 94, 98, ..., 97, 95, 97], [100, 100, 100, ..., 93, 100, 96], ..., [100, 100, 100, ..., 100, 100, 98], [100, 100, 100, ..., 99, 100, 98], [100, 100, 100, ..., 99, 94, 100]], dtype=uint8)
- orientmat_b5(inst, earth, time_b5)float32-0.2167 -0.2165 ... 0.9937 0.9937
array([[[-2.16694236e-01, -2.16498137e-01, -2.16593146e-01, ..., -2.16118217e-01, -2.16699123e-01, -2.16318965e-01], [-9.67967808e-01, -9.68039632e-01, -9.68030274e-01, ..., -9.70095694e-01, -9.69992876e-01, -9.70033050e-01], [-1.26507595e-01, -1.26426160e-01, -1.26425594e-01, ..., -1.10033900e-01, -1.10009573e-01, -1.09963998e-01]], [[ 9.76198971e-01, 9.76259708e-01, 9.76250350e-01, ..., 9.76315439e-01, 9.76210594e-01, 9.76245522e-01], [-2.15024590e-01, -2.14829564e-01, -2.14924574e-01, ..., -2.14874983e-01, -2.15436578e-01, -2.15052128e-01], [-2.68766508e-02, -2.68536285e-02, -2.68591940e-02, ..., -2.31788009e-02, -2.33813375e-02, -2.34001204e-02]], [[-1.19058788e-03, -1.16700679e-03, -1.17257237e-03, ..., -1.16243958e-03, -1.02279335e-03, -9.55920666e-04], [-1.29325598e-01, -1.29241347e-01, -1.29241914e-01, ..., -1.12442717e-01, -1.12462208e-01, -1.12422116e-01], [ 9.91601229e-01, 9.91612315e-01, 9.91612315e-01, ..., 9.93657291e-01, 9.93655324e-01, 9.93659675e-01]]], dtype=float32)
- angrt_b5(dirIMU, time_b5)float32-0.001953 -0.001953 ... -0.001953
- units :
- rad/s
array([[-0.00195312, -0.00195312, -0.00195312, ..., -0.00097656, -0.00195312, -0.00390625], [ 0. , 0. , 0.00097656, ..., 0.00097656, 0. , 0.00097656], [-0.00292969, -0.00292969, -0.00292969, ..., -0.00292969, -0.00292969, -0.00195312]], dtype=float32)
- quaternion_b5(q, time_b5)float320.6245 0.6245 ... 0.7787 0.7786
array([[ 0.6244507 , 0.62454224, 0.6245117 , ..., 0.625 , 0.6247864 , 0.62490845], [-0.04101562, -0.04098511, -0.04098511, ..., -0.03570557, -0.03564453, -0.03561401], [-0.0501709 , -0.05014038, -0.05014038, ..., -0.04354858, -0.04360962, -0.04360962], [ 0.77835083, 0.7782898 , 0.7783203 , ..., 0.77856445, 0.77874756, 0.7786255 ]], dtype=float32)
- status0_b5(time_b5)uint1632768 32768 32768 ... 32768 32768
- units :
- binary
array([32768, 32768, 32768, ..., 32768, 32768, 32768], dtype=uint16)
- heading(time)float32-12.52 -12.51 ... -12.52 -12.5
- units :
- deg
array([-12.52 , -12.505001, -12.51 , ..., -12.490002, -12.52 , -12.500001], dtype=float32)
- pitch(time)float32-0.065 -0.06 -0.06 ... -0.05 -0.05
- units :
- deg
array([-0.065, -0.06 , -0.06 , ..., -0.06 , -0.05 , -0.05 ], dtype=float32)
- roll(time)float32-7.425 -7.42 -7.42 ... -6.45 -6.45
- units :
- deg
array([-7.4250007, -7.42 , -7.42 , ..., -6.45 , -6.45 , -6.45 ], dtype=float32)
- beam2inst_orientmat(beam, x*)float321.183 0.0 -1.183 ... 0.0 0.5518
array([[ 1.1831, 0. , -1.1831, 0. ], [ 0. , -1.1831, 0. , 1.1831], [ 0.5518, 0. , 0.5518, 0. ], [ 0. , 0.5518, 0. , 0.5518]], dtype=float32)
- filehead_config :
- {'CLOCKSTR': {'TIME': '"2020-08-13 13:56:21"'}, 'ID': 'STR="Signature1000",SN=101663', 'HW': {'FW': 2212, 'FPGA': 169, 'DIGITAL': '"I-3"', 'INTERFACE': '"H-2"', 'ANALOG': '"G-1"', 'SENSOR': '"D-1(AHRS)"', 'BOOT': 21, 'FWMINOR': 11}, 'BOARDSENSGET': 'AV=23,NB=5,HF=1000,TTR=2.0000,TTRB5=2.0000', 'PWR': {'PLAN': 1940.43, 'BURST': 1937.69, 'AVG': 0.0, 'PLAN1': 0.0, 'BURST1': 0.0, 'AVG1': 0.0, 'TOTAL': 1940.43}, 'MEM': {'PLAN': 2.733, 'BURST': 2.733, 'AVG': 0.0, 'PLAN1': 0.0, 'BURST1': 0.0, 'AVG1': 0.0, 'TOTAL': 2.733}, 'PRECISION': {'AVGHORZ': -9.99, 'BURSTHORZ': 2.6, 'BEAM5': 1.62, 'AVGBEAM': -9.99, 'BURSTBEAM': 1.55}, 'PLAN': {'MIAVG': 600, 'AVG': 0, 'DIAVG': 0, 'VD': 0, 'MV': 10, 'SA': 32.0, 'BURST': 1, 'MIBURST': 1, 'DIBURST': 0, 'SV': 0.0, 'FN': '"S101663A007_sea_spider.ad2cp"', 'SO': 0, 'FREQ': 1000, 'NSTT': 0}, 'BURST': {'NC': 28, 'NB': 5, 'CS': 0.5, 'BD': 0.1, 'CY': '"ENU"', 'PL': 0.0, 'NS': 1, 'VR': 2.5, 'VP': 0.0, 'DF': 3, 'NPING': 8, 'CH': 0, 'ALTI': 0, 'VR5': 2.5, 'BT': 0, 'DISV': 0, 'ECHO': 0, 'RAWALTI': 60, 'ALTISTART': 0.1, 'ALTIEND': 30.0, 'HR': 0, 'HR5': 0}, 'USER': {'POFF': 10.2, 'DECL': 0.0, 'HX': -48, 'HY': 48, 'HZ': 0}, 'INST': {'BR': 9600, 'RS': 232, 'LED': '"OFF"', 'ORIENT': '"AHRS3D"', 'CMTOUT': 300, 'DMTOUT': 60, 'CFMTOUT': 60}, 'COMPASSCAL': {'DX': 155, 'DY': 778, 'DZ': -486, 'M11': 31481, 'M12': 1726, 'M13': -1109, 'M21': -1955, 'M22': 32767, 'M23': 379, 'M31': 750, 'M32': -1851, 'M33': 31699}, 'READAHRS': 'STR="OSv6_a2_V5101_0.6 Oct 3 2019, SerialNumber=60004222,type=OS3DM"', 'RECSTAT': 'SS=512,CS=32768,FC=127813877760,TC=127848677376,VS=127848677376', 'BEAMCFGLIST': ['BEAM=1,THETA=25.00,PHI=0.00,FREQ=1000,BW=25,BRD=1,HWBEAM=1,ZNOM=60.00,DIA=0.0', 'BEAM=2,THETA=25.00,PHI=-90.00,FREQ=1000,BW=25,BRD=1,HWBEAM=2,ZNOM=60.00,DIA=0.0', 'BEAM=3,THETA=25.00,PHI=180.00,FREQ=1000,BW=25,BRD=1,HWBEAM=3,ZNOM=60.00,DIA=0.0', 'BEAM=4,THETA=25.00,PHI=90.00,FREQ=1000,BW=25,BRD=1,HWBEAM=4,ZNOM=60.00,DIA=0.0', 'BEAM=5,THETA=0.00,PHI=0.00,FREQ=1000,BW=25,BRD=1,HWBEAM=5,ZNOM=60.00,DIA=0.0'], 'BEAMIMPLIST': ['BEAM=1,P0=1.00000e+02,P1=0.00000e+00,P2=0.00000e+00,P3=0.00000e+00,P4=0.00000e+00,T1=0.00000e+00', 'BEAM=2,P0=1.00000e+02,P1=0.00000e+00,P2=0.00000e+00,P3=0.00000e+00,P4=0.00000e+00,T1=0.00000e+00', 'BEAM=3,P0=1.00000e+02,P1=0.00000e+00,P2=0.00000e+00,P3=0.00000e+00,P4=0.00000e+00,T1=0.00000e+00', 'BEAM=4,P0=1.00000e+02,P1=0.00000e+00,P2=0.00000e+00,P3=0.00000e+00,P4=0.00000e+00,T1=0.00000e+00', 'BEAM=5,P0=1.00000e+02,P1=0.00000e+00,P2=0.00000e+00,P3=0.00000e+00,P4=0.00000e+00,T1=0.00000e+00'], 'LISTLICENSE': ['KEY="C390Y1LU32C1B",DESC="Averaging Mode",TYPE=1', 'KEY="6F2UB3HTH2C1B",DESC="Burst Five Beams",TYPE=17', 'KEY="R0X9JSZPH2C1B",DESC="128GB Recorder",TYPE=14'], 'CALCOMPGET': 'DX=155,DY=778,DZ=-486,M11=31481,M12=1726,M13=-1109,M21=-1955,M22=32767,M23=379,M31=750,M32=-1851,M33=31699', 'CALTEMPGET': 'SC=0.99906', 'CALTILTGET': 'PO=0.00,RO=0.00,MAGG=1,HO=0.00', 'CALACCLGET': ['AX=1.000000E+00,B0X=1.791816E-02,B1X=-1.795970E-02,B2X=6.661898E-04,B3X=0.000000E+00,A1X=1.146936E-05,A2X=7.326843E-06,A3X=0.000000E+00', 'AY=1.000000E+00,B0Y=9.597497E-03,B1Y=-8.430577E-03,B2Y=9.310668E-04,B3Y=0.000000E+00,A1Y=7.215003E-05,A2Y=1.361528E-06,A3Y=0.000000E+00', 'AZ=1.000000E+00,B0Z=1.290458E-02,B1Z=2.959575E-02,B2Z=2.331257E-03,B3Z=0.000000E+00,A1Z=1.164268E-04,A2Z=-2.166612E-06,A3Z=0.000000E+00'], 'CALGYROGET': ['AX=1.094973E+00,B0X=-2.672331E+00,B1X=-1.493178E-03,B2X=9.496510E-05,B3X=0.000000E+00,A1X=2.702698E-04,A2X=8.100271E-05,A3X=0.000000E+00', 'AY=1.080807E+00,B0Y=3.432283E-01,B1Y=7.219538E-04,B2Y=1.416728E-04,B3Y=0.000000E+00,A1Y=9.466633E-04,A2Y=-4.216283E-05,A3Y=0.000000E+00', 'AZ=1.085556E+00,B0Z=-9.442614E-01,B1Z=6.433576E-04,B2Z=-1.306087E-05,B3Z=0.000000E+00,A1Z=1.430541E-03,A2Z=-7.494539E-05,A3Z=0.000000E+00'], 'CALPRESSGET': 'MT=1,RREF=4.5264760000e+02,RB0=7.7074756250e-01,RB1=-7.5541806250e-02,RB2=4.9886362500e-04,RB3=-1.4193179690e-07,T0=-2.4234620000e+03,T1=1.8815180000e+00,T2=-5.0111803130e-04,T3=4.7281500000e-08,ID="K244314"', 'CALPRESSCOEFFGET': ['A0=6.3850020000e+00,A1=-5.6274000000e-03,A2=1.6346411250e-06,A3=-1.6029240630e-10,B0=-2.6056009380e-01,B1=3.1699690630e-04,B2=-9.0774206250e-08,B3=8.5142393750e-12', 'C0=-1.2762860000e-03,C1=1.1561740000e-06,C2=-3.5109818750e-10,C3=3.5575718750e-14,D0=3.6002040630e-06,D1=-3.3359181250e-09,D2=1.0241850000e-12,D3=-1.0446648750e-16'], 'CALROTACCLGET': 'M11=0.99144,M12=0.00991,M13=-0.03081,M21=-0.00921,M22=0.99564,M23=0.01131,M31=0.03451,M32=-0.01242,M33=0.98426', 'CALROTGYROGET': 'M11=1.00000,M12=0.00803,M13=-0.02685,M21=-0.00933,M22=1.00000,M23=0.01646,M31=0.02587,M32=-0.01599,M33=1.00000', 'CALECHOGET': 'CHA0=0.00,CHB0=-17.69,CHC0=0.00'}
- inst_model :
- Signature1000
- inst_make :
- Nortek
- inst_type :
- ADCP
- rotate_vars :
- ['vel', 'accel', 'accel_b5', 'angrt', 'angrt_b5', 'mag', 'mag_b5']
- burst_config :
- {'press_valid': True, 'temp_valid': True, 'compass_valid': True, 'tilt_valid': True, 'vel': True, 'amp': True, 'corr': True, 'alt': False, 'alt_raw': False, 'ast': False, 'echo': False, 'ahrs': True, 'p_gd': False, 'std': False}
- n_cells :
- 28
- n_beams :
- 4
- xmit_energy :
- 246.0
- ambig_vel :
- 5.066
- SerialNum :
- 101663
- cell_size :
- 0.5
- blank_dist :
- 0.1
- nom_corr :
- 67
- data_desc :
- 17185
- vel_scale :
- -3
- power_level :
- 0
- burst_config_b5 :
- {'press_valid': True, 'temp_valid': True, 'compass_valid': True, 'tilt_valid': True, 'vel': True, 'amp': True, 'corr': True, 'alt': False, 'alt_raw': False, 'ast': False, 'echo': False, 'ahrs': True, 'p_gd': False, 'std': False}
- n_cells_b5 :
- 28
- coord_sys_axes_b5 :
- beam
- n_beams_b5 :
- 1
- xmit_energy_b5 :
- 65.0
- ambig_vel_b5 :
- 5.066
- SerialNum_b5 :
- 101663
- cell_size_b5 :
- 0.5
- blank_dist_b5 :
- 0.1
- nom_corr_b5 :
- 65
- data_desc_b5 :
- 5
- vel_scale_b5 :
- -3
- power_level_b5 :
- 0
- coord_sys :
- earth
- orientation :
- AHRS
- orient_status :
- AHRS-3D
- has_imu :
- 1
- fs :
- 1
First Steps and QC’ing Data
1.) Set deployment height
Because this is a Nortek instrument, the deployment software doesn’t take into account the deployment height, aka where in the water column the ADCP is. The center of the first depth bin is located at a distance = deployment height + blanking distance + cell size, so the range
coordinate needs to be corrected so that ‘0’ corresponds to the seafloor. This can be done in DOLfYN using the set_range_offset
function. This same function can be used to account for the depth of down-facing
instrument below the water surface.
Note, TRDI’s deployment software asks the user to enter the deployment height/depth, which, if needed, can be adjusted after-the-fact using set_range_offset
as well.
[4]:
# The ADCP transducers were measured to be 0.6 m from the feet of the lander
dat = api.clean.set_range_offset(dat, 0.6)
So, the center of bin 1 is located at 1.2 m:
[5]:
dat.range
[5]:
<xarray.DataArray 'range' (range: 28)> array([ 1.2, 1.7, 2.2, 2.7, 3.2, 3.7, 4.2, 4.7, 5.2, 5.7, 6.2, 6.7, 7.2, 7.7, 8.2, 8.7, 9.2, 9.7, 10.2, 10.7, 11.2, 11.7, 12.2, 12.7, 13.2, 13.7, 14.2, 14.7]) Coordinates: * range (range) float64 1.2 1.7 2.2 2.7 3.2 ... 12.7 13.2 13.7 14.2 14.7 Attributes: units: m
- range: 28
- 1.2 1.7 2.2 2.7 3.2 3.7 4.2 4.7 ... 11.7 12.2 12.7 13.2 13.7 14.2 14.7
array([ 1.2, 1.7, 2.2, 2.7, 3.2, 3.7, 4.2, 4.7, 5.2, 5.7, 6.2, 6.7, 7.2, 7.7, 8.2, 8.7, 9.2, 9.7, 10.2, 10.7, 11.2, 11.7, 12.2, 12.7, 13.2, 13.7, 14.2, 14.7])
- range(range)float641.2 1.7 2.2 2.7 ... 13.7 14.2 14.7
- units :
- m
array([ 1.2, 1.7, 2.2, 2.7, 3.2, 3.7, 4.2, 4.7, 5.2, 5.7, 6.2, 6.7, 7.2, 7.7, 8.2, 8.7, 9.2, 9.7, 10.2, 10.7, 11.2, 11.7, 12.2, 12.7, 13.2, 13.7, 14.2, 14.7])
- units :
- m
2.) Remove data beyond surface level
To reduce the amount of data the code must run through, we can remove all data at and above the water surface. Because the instrument was looking up, we can use the pressure sensor data and the function surface_from_P
. This does require that the pressure sensor was ‘zeroed’ prior to deployment. If the instrument is looking down or lacks pressure data, use the function find_surface
to detect the seabed or water surface.
ADCPs don’t record water salinity, so it will need to be added to the function. The returned dataset contains the an additional variable “depth”, which is the distance of the water surface away from the seafloor.
After the water surface has been found, data in depth bins at and above the physical water surface can be removed using nan_beyond_surface
.
[6]:
dat = api.clean.surface_from_P(dat, salinity=31)
dat = api.clean.nan_beyond_surface(dat)
3.) Correlation filter
Once beyond-surface bins have been removed, ADCP data is typically filtered by correlation clear out spurious velocity datapoints (caused by bubbles, kelp, fish, etc moving through one or multiple beams).
We can take a quick look at the data to see about where this value should be using xarray’s built-in plotting. In the following line of code, we use xarray’s slicing capabilities to show data from beam 1 between a range of 0 to 10 m from the ADCP.
[7]:
%matplotlib inline
dat.corr.sel(beam=1, range=slice(0,10)).plot()
[7]:
<matplotlib.collections.QuadMesh at 0x203ec9024f0>
It’s a good idea to check the other beams as well. Much of this data is high quality, and to not lose data will low correlation caused by natural variation, we’ll use the correlation_filter
to set velocity values corresponding to correlations below 50% to NaN.
Note that this threshold is dependent on the deployment environment and instrument, and it isn’t uncommon to use a value as low as 30%, or ~50 counts.
[8]:
dat = api.clean.correlation_filter(dat, thresh=50)
Review the Data
Now that the data has been cleaned, the next step is to rotate the velocity data into true East, North, Up coordinates.
ADCPs use an internal compass or magnetometer to determine magnetic ENU directions. The set_declination
function takes the user supplied magnetic declination (which can be looked up online for specific coordinates) and adjusts the orientation matrix saved within the Dataset. (Note: the “heading” variable will not change).
Instruments save vector data in the coordinate system specified in the deployment configuration file. To make the data useful, it must be rotated through coordinate systems (“beam”<->”inst”<->”earth”), done through the rotate2
function. If the “earth” (ENU) coordinate system is specified, DOLfYN will automatically rotate the dataset through the necessary coordinate systems to get there.
Because this ADCP data was already in the “earth” coordinate system, rotate2
will return the input dataset. set_declination
will run correctly no matter the coordinate system.
[9]:
dat = dlfn.set_declination(dat, 15.8) # 15.8 deg East
dat = dlfn.rotate2(dat, 'earth')
Data is already in the earth coordinate system
Because this deployment was set up in ‘burst mode’ (as opposed to an ‘averaging mode’) the next standard step in this analysis is to average the velocity data into time bins. If an instrument was set up to record velocity data in an averaging mode (a specific profiling and averaging interval, e.g. take 5 minutes of data every 30 minutes), this step was completed within the ADCP during deployment and can be skipped.
To average the data into time bins (aka ensembles), start by initiating the binning tool VelBinner
. “n_bin” is the number of data points in each ensemble, in this case 300 seconds worth of data, and “fs” is the sampling frequency, which is 1 Hz for this deployment. Once initiated, average the data using the binning tool’s do_avg
function.
[10]:
avg_tool = api.VelBinner(n_bin=dat.fs*300, fs=dat.fs)
dat_avg = avg_tool.do_avg(dat)
Two more variables not automatically provided that may be of interest are the horizontal velocity magnitude and its direction, U_mag
and U_dir
. There are included as “shortcut” functions, and are accessed through the keyword Veldata
, as shown in the code block below. The full list of “shorcuts” are listed here, but note all of them might not be available to ADCP data.
Because of the way ADCP coordinate systems were established, when in ENU, U_dir
is in “degrees CCW from East” (aka “Cartesian angle”), as opposed to “degrees CW from North”, which is typical for navigation. The convert_degrees
function will transform from one to the other and vice versa, and is used below to save U_dir
in place.
[11]:
dat_avg['U_mag'] = dat_avg.Veldata.U_mag
dat_avg['U_dir'] = dat_avg.Veldata.U_dir
dat_avg['U_dir'].values = dlfn.tools.misc.convert_degrees(dat_avg['U_dir'].values)
Plotting can be accomplished through the user’s preferred package. Matplotlib is shown here for simplicity, and the horizontal velocity magnitude and direction are plotted below with a blue line delineating the water surface level.
[12]:
%matplotlib inline
from matplotlib import pyplot as plt
import matplotlib.dates as dt
# Convert time to a datetime format
t = dlfn.time.epoch2date(dat_avg.time)
ax = plt.figure(figsize=(12,8)).add_axes([.14, .14, .8, .74])
# Plot the horizontal velocity magnitude
plt.pcolormesh(t, dat_avg.range, dat_avg['U_mag'], cmap='Blues', shading='nearest')
# Plot the water surface
ax.plot(t, dat_avg.depth)
# Set up time on x-axis
ax.set_xlabel('Time')
ax.xaxis.set_major_formatter(dt.DateFormatter('%H:%M'))
ax.set_ylabel('Altitude [m]')
ax.set_ylim([0, 12]);
plt.colorbar(label='Horizontal Vel [m/s]');
[13]:
# Plot horizontal velocity direction
ax = plt.figure(figsize=(12,8)).add_axes([.14, .14, .8, .74])
plt.pcolormesh(t, dat_avg.range, dat_avg['U_dir'], cmap='twilight', shading='nearest')
# Plot the water surface
ax.plot(t, dat_avg.depth)
# set up time on x-axis
ax.set_xlabel('Time')
ax.xaxis.set_major_formatter(dt.DateFormatter('%H:%M'))
ax.set_ylabel('Altitude [m]')
ax.set_ylim([0, 12]);
plt.colorbar(label='Horizontal Vel Dir [deg CW from true N]');
Saving and Loading DOLfYN datasets
Datasets can be saved and reloaded using the save
and load
functions. Xarray is saved natively in netCDF format, hence the “.nc” extension.
Note: DOLfYN datasets cannot be saved using xarray’s native ds.to_netcdf
; however, DOLfYN datasets can be opened using xarray.open_dataset
.
[14]:
# Uncomment these lines to save and load to your current working directory
#dlfn.save(ds, 'your_data.nc')
#ds_saved = dlfn.load('your_data.nc')