Skip to content

Commit 43a66bb

Browse files
authored
Merge pull request #1039 from OSOceanAcoustics/dev
Release/v0.7.1
2 parents 053d322 + d1f21ca commit 43a66bb

22 files changed

+423
-316
lines changed

.ci_helpers/py3.10.yaml

Lines changed: 3 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -3,14 +3,6 @@ channels:
33
- conda-forge
44
dependencies:
55
- python=3.10
6-
- dask
7-
- netCDF4
8-
- pynmea2
9-
- pytz
10-
- scipy
11-
- xarray==2022.3.0
12-
- zarr
13-
- fsspec
14-
- s3fs==2022.5.0
15-
- matplotlib-base
16-
- cmocean
6+
- pip
7+
- pip:
8+
- -r ../requirements.txt

.ci_helpers/py3.8.yaml

Lines changed: 3 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -3,14 +3,6 @@ channels:
33
- conda-forge
44
dependencies:
55
- python=3.8
6-
- dask
7-
- netCDF4
8-
- pynmea2
9-
- pytz
10-
- scipy
11-
- xarray==2022.3.0
12-
- zarr
13-
- fsspec
14-
- s3fs==2022.5.0
15-
- matplotlib-base
16-
- cmocean
6+
- pip
7+
- pip:
8+
- -r ../requirements.txt

.ci_helpers/py3.9.yaml

Lines changed: 3 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -3,14 +3,6 @@ channels:
33
- conda-forge
44
dependencies:
55
- python=3.9
6-
- dask
7-
- netCDF4
8-
- pynmea2
9-
- pytz
10-
- scipy
11-
- xarray==2022.3.0
12-
- zarr
13-
- fsspec
14-
- s3fs==2022.5.0
15-
- matplotlib-base
16-
- cmocean
6+
- pip
7+
- pip:
8+
- -r ../requirements.txt

docs/source/whats-new.md

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,34 @@ What's new
44
See [GitHub releases page](https://github.com/OSOceanAcoustics/echopype/releases) for the complete history.
55

66

7+
# v0.7.1 (2023 May 1)
8+
9+
## Overview
10+
11+
This release includes important updates to the requirements, small bug fixes, and refactoring of AZFP parser code to handle files from glider deployment and improve code coherence.
12+
13+
## Enhancement and bug fixes
14+
- AZFP conversion enhancements
15+
- Add error catch to handle AZFP files with no temperature or tilt, such as those from glider deployments (#1020)
16+
- Refactor AZFP parser code to improve code coherence (#1024)
17+
- Correct and add missing SONAR-netCDF4 variable attributes for AZFP (#1023)
18+
- Improve impedance parameter handling for EK80 files (#1019)
19+
- allow impedance data type to be float
20+
- unify naming of impedance parameters
21+
- Allow only one chirp generation option for EK80 broadband processing (#1019)
22+
- previously there was an option to use the implementation from Matlab echolab
23+
- starting from this version only the implementation identical to those from Lars Andersen ([repo](https://github.com/CRIMAC-WP4-Machine-learning/CRIMAC-Raw-To-Svf-TSf))
24+
- Remove unneeded return self in processing level decorator wrapper-inner function for class method (#1037)
25+
26+
## Tests and infrastructure
27+
- Unpin xarray version and pin pandas < 2 (#981)
28+
- allow v0.7.x in `map_ep_version` checks
29+
30+
31+
32+
33+
34+
735
# v0.7.0 (2023 March 25)
836

937
## Overview

echopype/calibrate/cal_params.py

Lines changed: 23 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -25,16 +25,16 @@
2525
"angle_sensitivity_athwartship",
2626
"beamwidth_alongship",
2727
"beamwidth_athwartship",
28-
"impedance_transmit", # z_et
29-
"impedance_receive", # z_er
28+
"impedance_transducer", # z_et
29+
"impedance_transceiver", # z_er
3030
"receiver_sampling_frequency",
3131
),
3232
"AZFP": ("EL", "DS", "TVR", "VTX", "equivalent_beam_angle", "Sv_offset"),
3333
}
3434

3535
EK80_DEFAULT_PARAMS = {
36-
"impedance_transmit": 75,
37-
"impedance_receive": 1000,
36+
"impedance_transducer": 75,
37+
"impedance_transceiver": 1000,
3838
"receiver_sampling_frequency": { # default full sampling frequency [Hz]
3939
"default": 1500000,
4040
"GPT": 500000,
@@ -203,7 +203,7 @@ def _get_interp_da(
203203
204204
``alternative`` can be one of the following:
205205
206-
- scalar (int or float): this is the case for impedance_transmit
206+
- scalar (int or float): this is the case for impedance_transducer
207207
- xr.DataArray with coordinates channel, ping_time, and beam:
208208
this is the case for parameters angle_offset_alongship, angle_offset_athwartship,
209209
beamwidth_alongship, beamwidth_athwartship
@@ -308,7 +308,19 @@ def get_vend_cal_params_power(beam: xr.Dataset, vend: xr.Dataset, param: str) ->
308308

309309
# Select corresponding index and clean up the original nan elements
310310
da_param = da_param.sel(pulse_length_bin=idxmin, drop=True)
311-
return da_param.where(~transmit_isnull, np.nan) # set the nan elements back to nan
311+
312+
# Set the nan elements back to nan.
313+
# Doing the `.where` will result in float64,
314+
# which is fine since we're dealing with nan
315+
da_param = da_param.where(~transmit_isnull, np.nan)
316+
317+
# Clean up for leftover plb variable
318+
# if exists
319+
plb_var = "pulse_length_bin"
320+
if plb_var in da_param.coords:
321+
da_param = da_param.drop(plb_var)
322+
323+
return da_param
312324

313325

314326
def get_cal_params_AZFP(beam: xr.DataArray, vend: xr.DataArray, user_dict: dict) -> dict:
@@ -431,12 +443,12 @@ def _get_fs():
431443
# Those without CW or BB complications
432444
if p == "sa_correction": # pull from data file
433445
out_dict[p] = get_vend_cal_params_power(beam=beam, vend=vend, param=p)
434-
elif p == "impedance_receive": # from data file or default dict
435-
out_dict[p] = default_params[p] if p not in vend else vend["impedance_receive"]
446+
elif p == "impedance_transceiver": # from data file or default dict
447+
out_dict[p] = default_params[p] if p not in vend else vend["impedance_transceiver"]
436448
elif p == "receiver_sampling_frequency": # from data file or default_params
437449
out_dict[p] = _get_fs()
438450
else:
439-
# CW: params do not require interpolation, except for impedance_transmit
451+
# CW: params do not require interpolation, except for impedance_transducer
440452
if waveform_mode == "CW":
441453
if p in PARAM_BEAM_NAME_MAP.keys():
442454
p_beam = PARAM_BEAM_NAME_MAP[p]
@@ -448,7 +460,7 @@ def _get_fs():
448460
elif p == "gain_correction":
449461
# pull from data file narrowband table
450462
out_dict[p] = get_vend_cal_params_power(beam=beam, vend=vend, param=p)
451-
elif p == "impedance_transmit":
463+
elif p == "impedance_transducer":
452464
# assemble each channel from data file or default dict
453465
out_dict[p] = _get_interp_da(
454466
da_param=None if p not in vend else vend[p],
@@ -497,7 +509,7 @@ def _get_fs():
497509
freq_center=freq_center,
498510
alternative=get_vend_cal_params_power(beam=beam, vend=vend, param=p),
499511
)
500-
elif p == "impedance_transmit":
512+
elif p == "impedance_transducer":
501513
out_dict[p] = _get_interp_da(
502514
da_param=None if p not in vend else vend[p],
503515
freq_center=freq_center,

echopype/calibrate/calibrate_ek.py

Lines changed: 15 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -192,8 +192,8 @@ def compute_TS(self, **kwargs):
192192
class CalibrateEK80(CalibrateEK):
193193
# Default EK80 params: these parameters are only recorded in later versions of EK80 software
194194
EK80_params = {}
195-
EK80_params["z_et"] = 75 # transmit impedance
196-
EK80_params["z_er"] = 1000 # receive impedance
195+
EK80_params["z_et"] = 75 # transducer impedance
196+
EK80_params["z_er"] = 1000 # transceiver impedance
197197
EK80_params["fs"] = { # default full sampling frequency [Hz]
198198
"default": 1500000,
199199
"GPT": 500000,
@@ -395,8 +395,8 @@ def _get_power_from_complex(
395395
self,
396396
beam: xr.Dataset,
397397
chirp: Dict,
398-
z_et,
399-
z_er,
398+
z_et: float,
399+
z_er: float,
400400
) -> xr.DataArray:
401401
"""
402402
Get power from complex samples.
@@ -407,6 +407,10 @@ def _get_power_from_complex(
407407
EchoData["Sonar/Beam_group1"] with selected channel subset
408408
chirp : dict
409409
a dictionary containing transmit chirp for BB channels
410+
z_et : float
411+
impedance of transducer [ohm]
412+
z_er : float
413+
impedance of transceiver [ohm]
410414
411415
Returns
412416
-------
@@ -441,7 +445,10 @@ def _get_B_theta_phi_m(self):
441445
"""
442446
Get transceiver gain compensation for BB mode.
443447
444-
ref: https://github.com/CI-CMG/pyEcholab/blob/RHT-EK80-Svf/echolab2/instruments/EK80.py#L4263-L4274 # noqa
448+
Source: https://github.com/CRIMAC-WP4-Machine-learning/CRIMAC-Raw-To-Svf-TSf/blob/abd01f9c271bb2dbe558c80893dbd7eb0d06fe38/Core/EK80DataContainer.py#L261-L273 # noqa
449+
From conversation with Lars Andersen, this correction is based on a longstanding
450+
empirical formula used for fitting beampattern during calibration, based on
451+
physically meaningful parameters such as the angle offset and beamwidth.
445452
"""
446453
fac_along = (
447454
np.abs(-self.cal_params["angle_offset_alongship"])
@@ -477,12 +484,12 @@ def _cal_complex_samples(self, cal_type: str) -> xr.Dataset:
477484
tx_coeff = get_filter_coeff(vend)
478485
fs = self.cal_params["receiver_sampling_frequency"]
479486

480-
# Switch to use Anderson implementation for transmit chirp starting v0.6.4
487+
# Switch to use Andersen implementation for transmit chirp starting v0.6.4
481488
tx, tx_time = get_transmit_signal(beam, tx_coeff, self.waveform_mode, fs)
482489

483490
# Params to clarity in use below
484-
z_er = self.cal_params["impedance_receive"]
485-
z_et = self.cal_params["impedance_transmit"]
491+
z_er = self.cal_params["impedance_transceiver"]
492+
z_et = self.cal_params["impedance_transducer"]
486493
gain = self.cal_params["gain_correction"]
487494

488495
# Transceiver gain compensation for BB mode

echopype/calibrate/ek80_complex.py

Lines changed: 27 additions & 56 deletions
Original file line numberDiff line numberDiff line change
@@ -10,68 +10,41 @@ def tapered_chirp(
1010
fs,
1111
transmit_duration_nominal,
1212
slope,
13-
transmit_power,
14-
implementation="Anderson",
15-
z_et=None,
1613
frequency_nominal=None,
1714
frequency_start=None,
1815
frequency_end=None,
1916
):
20-
"""Create a baseline chirp template."""
17+
"""
18+
Create the chirp replica following implementation from Lars Anderson.
19+
20+
Ref source: https://github.com/CRIMAC-WP4-Machine-learning/CRIMAC-Raw-To-Svf-TSf/blob/main/Core/Calculation.py # noqa
21+
"""
2122
if frequency_start is None and frequency_end is None: # CW waveform
2223
frequency_start = frequency_nominal
2324
frequency_end = frequency_nominal
2425

25-
if implementation == "Macaulay":
26-
# z_et is required for Macaulay implementation
27-
if z_et is None:
28-
raise ValueError("z_et is needed for Macaulay implementation of transmit chirp!")
29-
30-
t = np.arange(0, transmit_duration_nominal, 1 / fs)
31-
nwtx = int(2 * np.floor(slope * t.size)) # length of tapering window
32-
wtx_tmp = np.hanning(nwtx) # hanning window
33-
nwtxh = int(np.round(nwtx / 2)) # half length of the hanning window
34-
wtx = np.concatenate(
35-
[wtx_tmp[0:nwtxh], np.ones((t.size - nwtx)), wtx_tmp[nwtxh:]]
36-
) # assemble full tapering window
37-
chirp_fac = (
38-
(frequency_end - frequency_start) / transmit_duration_nominal
39-
) * t / 2 + frequency_start
40-
y_tmp = (
41-
np.sqrt((transmit_power / 4) * (2 * z_et)) # amplitude
42-
* np.cos(2 * np.pi * chirp_fac * t) # chirp
43-
* wtx # tapering
44-
) # taper and scale linear chirp
45-
return y_tmp / np.max(np.abs(y_tmp)), t # amplitude needs to be normalized
46-
47-
elif implementation == "Anderson":
48-
# Substitute to keep original form in Anderson implementation
49-
# source: https://github.com/CRIMAC-WP4-Machine-learning/CRIMAC-Raw-To-Svf-TSf/blob/main/Core/Calculation.py # noqa
50-
tau = transmit_duration_nominal
51-
f0 = frequency_start
52-
f1 = frequency_end
53-
54-
nsamples = int(np.floor(tau * fs))
55-
t = np.linspace(0, nsamples - 1, num=nsamples) * 1 / fs
56-
a = np.pi * (f1 - f0) / tau
57-
b = 2 * np.pi * f0
58-
y = np.cos(a * t * t + b * t)
59-
L = int(np.round(tau * fs * slope * 2.0)) # Length of hanning window
60-
w = 0.5 * (1.0 - np.cos(2.0 * np.pi * np.arange(0, L, 1) / (L - 1)))
61-
N = len(y)
62-
w1 = w[0 : int(len(w) / 2)]
63-
w2 = w[int(len(w) / 2) : -1]
64-
i0 = 0
65-
i1 = len(w1)
66-
i2 = N - len(w2)
67-
i3 = N
68-
y[i0:i1] = y[i0:i1] * w1
69-
y[i2:i3] = y[i2:i3] * w2
70-
71-
return y / np.max(y), t # amplitude needs to be normalized
72-
73-
else:
74-
raise ValueError("Input implementation type not recognized!")
26+
tau = transmit_duration_nominal
27+
f0 = frequency_start
28+
f1 = frequency_end
29+
30+
nsamples = int(np.floor(tau * fs))
31+
t = np.linspace(0, nsamples - 1, num=nsamples) * 1 / fs
32+
a = np.pi * (f1 - f0) / tau
33+
b = 2 * np.pi * f0
34+
y = np.cos(a * t * t + b * t)
35+
L = int(np.round(tau * fs * slope * 2.0)) # Length of hanning window
36+
w = 0.5 * (1.0 - np.cos(2.0 * np.pi * np.arange(0, L, 1) / (L - 1)))
37+
N = len(y)
38+
w1 = w[0 : int(len(w) / 2)]
39+
w2 = w[int(len(w) / 2) : -1]
40+
i0 = 0
41+
i1 = len(w1)
42+
i2 = N - len(w2)
43+
i3 = N
44+
y[i0:i1] = y[i0:i1] * w1
45+
y[i2:i3] = y[i2:i3] * w2
46+
47+
return y / np.max(y), t # amplitude needs to be normalized
7548

7649

7750
def filter_decimate_chirp(coeff_ch: Dict, y_ch: np.array, fs: float):
@@ -253,15 +226,13 @@ def get_transmit_signal(
253226
tx_param_names = [
254227
"transmit_duration_nominal",
255228
"slope",
256-
"transmit_power",
257229
"frequency_start",
258230
"frequency_end",
259231
]
260232
else:
261233
tx_param_names = [
262234
"transmit_duration_nominal",
263235
"slope",
264-
"transmit_power",
265236
"frequency_nominal",
266237
]
267238
tx_params = {}

echopype/calibrate/env_params_old.py

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -105,8 +105,10 @@ def _apply(self, echodata) -> Dict[str, xr.DataArray]:
105105
if self.data_kind == "mobile":
106106
if np.isnan(echodata["Platform"]["time1"]).all():
107107
raise ValueError("cannot perform mobile interpolation without time1")
108+
# only grab needed variables for the interpolation
109+
platform_data = echodata["Platform"][["latitude", "longitude"]]
108110
# compute_range needs indexing by ping_time
109-
interp_plat = echodata["Platform"].interp(
111+
interp_plat = platform_data.interp(
110112
{"time1": echodata["Sonar/Beam_group1"]["ping_time"]}
111113
)
112114

0 commit comments

Comments
 (0)