Skip to content

Commit 3b844f8

Browse files
committed
fix(adcp): use signed int16 for AD2CP echo amplitude — fixes 500+ dB Sv bug
Raw echo_amplitude from Nortek Signature is signed int16 (0.01 dB per count), not unsigned uint16. The unsigned interpretation produced Sv values of 529-600 dB instead of the correct -130 to -79 dB range. Changes: - ad2cp_reader: parse echo data as '<i2' (signed), allocate int16 array - sv_computation: update comments to reflect signed dtype Verified against real AD2CP files — Sv now -130 to -79 dB (mean -95 dB).
1 parent 3d21242 commit 3b844f8

2 files changed

Lines changed: 6 additions & 6 deletions

File tree

oceanstream/adcp/ad2cp_reader.py

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -181,7 +181,7 @@ def _parse_echo_data_record(data: bytes) -> Ad2cpEchoPing:
181181
roll = struct.unpack_from("<h", data, 28)[0] * 0.01
182182

183183
echo_bytes = data[offset_of_data:]
184-
amplitude = np.frombuffer(echo_bytes, dtype="<u2")
184+
amplitude = np.frombuffer(echo_bytes, dtype="<i2")
185185

186186
return Ad2cpEchoPing(
187187
time=time,
@@ -544,7 +544,7 @@ def read_ad2cp(path: Path | str) -> xr.Dataset:
544544
range_m = blanking + np.arange(n_cells) * cell_size
545545

546546
# Separate pings by frequency (they alternate: freq0, freq1, freq0, ...)
547-
amplitude = np.zeros((n_freqs, n_pings, n_cells), dtype=np.uint16)
547+
amplitude = np.zeros((n_freqs, n_pings, n_cells), dtype=np.int16)
548548
times = np.empty(n_pings, dtype="datetime64[us]")
549549
sound_speed = np.empty(n_pings, dtype=np.float32)
550550
temperature = np.empty(n_pings, dtype=np.float32)
@@ -620,7 +620,7 @@ def read_ad2cp(path: Path | str) -> xr.Dataset:
620620
{
621621
"long_name": "Echo amplitude",
622622
"units": "count",
623-
"comment": "Raw uint16 echo intensity with instrument TVG applied",
623+
"comment": "Raw int16 echo level (0.01 dB per count) with instrument TVG applied",
624624
},
625625
),
626626
"sound_speed": (

oceanstream/adcp/sv_computation.py

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -27,7 +27,7 @@ def compute_sv(
2727
2828
The Nortek Signature echosounder applies TVG (Time-Varied Gain)
2929
internally before recording. The raw ``echo_amplitude`` values
30-
are proportional to signal level in 0.01 dB units, with geometric
30+
are signed int16 counts at 0.01 dB per count, with geometric
3131
spreading and a nominal absorption already compensated.
3232
3333
This function converts raw counts to Sv by applying the per-channel
@@ -55,15 +55,15 @@ def compute_sv(
5555
"""
5656
import xarray as xr
5757

58-
amp = ds["echo_amplitude"].values # (freq, ping, range) uint16
58+
amp = ds["echo_amplitude"].values # (freq, ping, range) int16
5959
cal_offsets = ds.attrs.get("cal_offsets_db", [0.0] * amp.shape[0])
6060
range_m = ds["range_sample"].values # (range,)
6161

6262
n_freqs = amp.shape[0]
6363
sv = np.full_like(amp, np.nan, dtype=np.float32)
6464

6565
for fi in range(n_freqs):
66-
# Convert raw counts to dB echo level
66+
# Convert signed int16 counts to dB echo level (0.01 dB per count)
6767
el = amp[fi].astype(np.float32) * 0.01
6868

6969
cal = cal_offsets[fi] if fi < len(cal_offsets) else 0.0

0 commit comments

Comments
 (0)