Skip to content

Commit 295111b

Browse files
committed
Merge branch 'dev' into preprocess-reorg
2 parents 3dc0f55 + edc1d15 commit 295111b

15 files changed

+891
-236
lines changed

echopype/calibrate/cal_params.py

Lines changed: 2 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -49,10 +49,6 @@
4949
}
5050

5151

52-
# TODO: need a function (something like "_check_param_freq_dep")
53-
# to check user input cal_params and env_params
54-
55-
5652
def param2da(p_val: Union[int, float, list], channel: Union[list, xr.DataArray]) -> xr.DataArray:
5753
"""
5854
Organize individual parameter in scalar or list to xr.DataArray with channel coordinate.
@@ -88,7 +84,7 @@ def param2da(p_val: Union[int, float, list], channel: Union[list, xr.DataArray])
8884

8985
def sanitize_user_cal_dict(
9086
sonar_type: Literal["EK60", "EK80", "AZFP"],
91-
user_dict: Dict[str, Union[int, float, xr.DataArray]],
87+
user_dict: Dict[str, Union[int, float, list, xr.DataArray]],
9288
channel: Union[List, xr.DataArray],
9389
) -> Dict[str, Union[int, float, xr.DataArray]]:
9490
"""
@@ -126,7 +122,7 @@ def sanitize_user_cal_dict(
126122

127123
# Screen parameters: only retain those defined in CAL_PARAMS
128124
# -- transform params in scalar or list to xr.DataArray
129-
# -- directly pass through those that are xr.DataArray
125+
# -- directly pass through those that are xr.DataArray and pass the check for coordinates
130126
out_dict = dict.fromkeys(CAL_PARAMS[sonar_type])
131127
for p_name, p_val in user_dict.items():
132128
if p_name in out_dict:

echopype/calibrate/calibrate_azfp.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,7 @@ def __init__(self, echodata: EchoData, env_params=None, cal_params=None, **kwarg
1515
self.sonar_type = "AZFP"
1616

1717
# load env and cal parameters
18-
self.env_params = get_env_params_AZFP(echodata=self.echodata, user_env_dict=self.env_params)
18+
self.env_params = get_env_params_AZFP(echodata=self.echodata, user_dict=self.env_params)
1919
self.cal_params = get_cal_params_AZFP(
2020
beam=self.echodata["Sonar/Beam_group1"],
2121
vend=self.echodata["Vendor_specific"],

echopype/calibrate/calibrate_ek.py

Lines changed: 41 additions & 35 deletions
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@
99
from .cal_params import get_cal_params_EK
1010
from .calibrate_base import CalibrateBase
1111
from .ek80_complex import compress_pulse, get_filter_coeff, get_tau_effective, get_transmit_signal
12-
from .env_params import get_env_params_EK60, get_env_params_EK80
12+
from .env_params import get_env_params_EK
1313
from .range import compute_range_EK, range_mod_TVG_EK
1414

1515
logger = _init_logger(__name__)
@@ -19,6 +19,8 @@ class CalibrateEK(CalibrateBase):
1919
def __init__(self, echodata: EchoData, env_params, cal_params):
2020
super().__init__(echodata, env_params, cal_params)
2121

22+
self.ed_beam_group = None # will be assigned in child class
23+
2224
def compute_echo_range(self, chan_sel: xr.DataArray = None):
2325
"""
2426
Compute echo range for EK echosounders.
@@ -36,24 +38,22 @@ def compute_echo_range(self, chan_sel: xr.DataArray = None):
3638
chan_sel=chan_sel,
3739
)
3840

39-
def _cal_power_samples(self, cal_type: str, power_ed_group: str = None) -> xr.Dataset:
41+
def _cal_power_samples(self, cal_type: str) -> xr.Dataset:
4042
"""Calibrate power data from EK60 and EK80.
4143
4244
Parameters
4345
----------
4446
cal_type: str
4547
'Sv' for calculating volume backscattering strength, or
4648
'TS' for calculating target strength
47-
power_ed_group:
48-
The ``EchoData`` beam group path containing the power data
4949
5050
Returns
5151
-------
5252
xr.Dataset
5353
The calibrated dataset containing Sv or TS
5454
"""
5555
# Select source of backscatter data
56-
beam = self.echodata[power_ed_group]
56+
beam = self.echodata[self.ed_beam_group]
5757

5858
# Derived params
5959
wavelength = self.env_params["sound_speed"] / beam["frequency_nominal"] # wavelength
@@ -63,7 +63,7 @@ def _cal_power_samples(self, cal_type: str, power_ed_group: str = None) -> xr.Da
6363
sound_speed = self.env_params["sound_speed"]
6464
absorption = self.env_params["sound_absorption"]
6565
tvg_mod_range = range_mod_TVG_EK(
66-
self.echodata, self.ed_group, self.range_meter, sound_speed
66+
self.echodata, self.ed_beam_group, self.range_meter, sound_speed
6767
)
6868
tvg_mod_range = tvg_mod_range.where(tvg_mod_range > 0, np.nan)
6969

@@ -130,26 +130,31 @@ class CalibrateEK60(CalibrateEK):
130130
def __init__(self, echodata, env_params, cal_params, **kwargs):
131131
super().__init__(echodata, env_params, cal_params)
132132

133-
# Set sonar_type
133+
# Set sonar_type and waveform/encode mode
134134
self.sonar_type = "EK60"
135-
136-
# Get env_params
137-
self.env_params = get_env_params_EK60(echodata=echodata, user_env_dict=self.env_params)
138135
self.waveform_mode = "CW"
139136
self.encode_mode = "power"
140137

141-
# Compute range
142-
self.compute_echo_range()
143-
144-
# Get the right ed_group for CW power samples
145-
self.ed_group = retrieve_correct_beam_group(
138+
# Get the right ed_beam_group for CW power samples
139+
self.ed_beam_group = retrieve_correct_beam_group(
146140
echodata=self.echodata, waveform_mode=self.waveform_mode, encode_mode=self.encode_mode
147141
)
148142

143+
# Get env_params
144+
self.env_params = get_env_params_EK(
145+
sonar_type=self.sonar_type,
146+
beam=self.echodata[self.ed_beam_group],
147+
env=self.echodata["Environment"],
148+
user_dict=self.env_params,
149+
)
150+
151+
# Compute range
152+
self.compute_echo_range()
153+
149154
# Set the channels to calibrate
150155
# For EK60 this is all channels
151-
self.chan_sel = self.echodata[self.ed_group]["channel"]
152-
beam = self.echodata[self.ed_group]
156+
self.chan_sel = self.echodata[self.ed_beam_group]["channel"]
157+
beam = self.echodata[self.ed_beam_group]
153158

154159
# Get cal_params
155160
self.cal_params = get_cal_params_EK(
@@ -162,10 +167,10 @@ def __init__(self, echodata, env_params, cal_params, **kwargs):
162167
)
163168

164169
def compute_Sv(self, **kwargs):
165-
return self._cal_power_samples(cal_type="Sv", power_ed_group=self.ed_group)
170+
return self._cal_power_samples(cal_type="Sv")
166171

167172
def compute_TS(self, **kwargs):
168-
return self._cal_power_samples(cal_type="TS", power_ed_group=self.ed_group)
173+
return self._cal_power_samples(cal_type="TS")
169174

170175

171176
class CalibrateEK80(CalibrateEK):
@@ -197,23 +202,23 @@ def __init__(self, echodata, env_params, cal_params, waveform_mode, encode_mode)
197202
self.encode_mode = encode_mode
198203
self.echodata = echodata
199204

200-
# Get the right ed_group given waveform and encode mode
201-
self.ed_group = retrieve_correct_beam_group(
205+
# Get the right ed_beam_group given waveform and encode mode
206+
self.ed_beam_group = retrieve_correct_beam_group(
202207
echodata=self.echodata, waveform_mode=self.waveform_mode, encode_mode=self.encode_mode
203208
)
204209

205210
# Select the channels to calibrate
206211
if self.encode_mode == "power":
207212
# Power sample only possible under CW mode,
208213
# and all power samples will live in the same group
209-
self.chan_sel = self.echodata[self.ed_group]["channel"]
214+
self.chan_sel = self.echodata[self.ed_beam_group]["channel"]
210215
else:
211216
# Complex samples can be CW or BB, so select based on waveform mode
212-
chan_dict = self._get_chan_dict(self.echodata[self.ed_group])
217+
chan_dict = self._get_chan_dict(self.echodata[self.ed_beam_group])
213218
self.chan_sel = chan_dict[self.waveform_mode]
214219

215220
# Subset of the right Sonar/Beam_groupX group given the selected channels
216-
beam = self.echodata[self.ed_group].sel(channel=self.chan_sel)
221+
beam = self.echodata[self.ed_beam_group].sel(channel=self.chan_sel)
217222

218223
# Use center frequency if in BB mode, else use nominal channel frequency
219224
if self.waveform_mode == "BB":
@@ -226,11 +231,12 @@ def __init__(self, echodata, env_params, cal_params, waveform_mode, encode_mode)
226231
self.freq_center = beam["frequency_nominal"].sel(channel=self.chan_sel)
227232

228233
# Get env_params: depends on waveform mode
229-
self.env_params = get_env_params_EK80(
230-
echodata=echodata,
234+
self.env_params = get_env_params_EK(
235+
sonar_type=self.sonar_type,
236+
beam=beam,
237+
env=self.echodata["Environment"],
238+
user_dict=self.env_params,
231239
freq=self.freq_center,
232-
user_env_dict=env_params,
233-
ed_group=self.ed_group,
234240
)
235241

236242
# Get cal_params: depends on waveform and encode mode
@@ -333,24 +339,22 @@ def _get_B_theta_phi_m(self):
333339

334340
return B_theta_phi_m
335341

336-
def _cal_complex_samples(self, cal_type: str, complex_ed_group: str) -> xr.Dataset:
342+
def _cal_complex_samples(self, cal_type: str) -> xr.Dataset:
337343
"""Calibrate complex data from EK80.
338344
339345
Parameters
340346
----------
341347
cal_type : str
342348
'Sv' for calculating volume backscattering strength, or
343349
'TS' for calculating target strength
344-
complex_ed_group : str
345-
The ``EchoData`` beam group path containing complex data
346350
347351
Returns
348352
-------
349353
xr.Dataset
350354
The calibrated dataset containing Sv or TS
351355
"""
352356
# Select source of backscatter data
353-
beam = self.echodata[complex_ed_group].sel(channel=self.chan_sel)
357+
beam = self.echodata[self.ed_beam_group].sel(channel=self.chan_sel)
354358
vend = self.echodata["Vendor_specific"].sel(channel=self.chan_sel)
355359

356360
# Get transmit signal
@@ -376,7 +380,9 @@ def _cal_complex_samples(self, cal_type: str, complex_ed_group: str) -> xr.Datas
376380
transmit_power = beam["transmit_power"]
377381

378382
# TVG compensation with modified range
379-
tvg_mod_range = range_mod_TVG_EK(self.echodata, self.ed_group, range_meter, sound_speed)
383+
tvg_mod_range = range_mod_TVG_EK(
384+
self.echodata, self.ed_beam_group, range_meter, sound_speed
385+
)
380386
tvg_mod_range = tvg_mod_range.where(tvg_mod_range > 0, np.nan)
381387

382388
spreading_loss = 20 * np.log10(tvg_mod_range)
@@ -476,10 +482,10 @@ def _compute_cal(self, cal_type) -> xr.Dataset:
476482

477483
if flag_complex:
478484
# Complex samples can be BB or CW
479-
ds_cal = self._cal_complex_samples(cal_type=cal_type, complex_ed_group=self.ed_group)
485+
ds_cal = self._cal_complex_samples(cal_type=cal_type)
480486
else:
481487
# Power samples only make sense for CW mode data
482-
ds_cal = self._cal_power_samples(cal_type=cal_type, power_ed_group=self.ed_group)
488+
ds_cal = self._cal_power_samples(cal_type=cal_type)
483489

484490
return ds_cal
485491

0 commit comments

Comments
 (0)