Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Bring more consistency in the Platform group across sensors on conversion #1058

Merged
merged 13 commits into from
Jun 9, 2023
Merged
Show file tree
Hide file tree
Changes from 12 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
93 changes: 79 additions & 14 deletions echopype/convert/set_groups_azfp.py
Original file line number Diff line number Diff line change
Expand Up @@ -139,32 +139,78 @@ def set_sonar(self) -> xr.Dataset:

def set_platform(self) -> xr.Dataset:
"""Set the Platform group."""
platform_dict = {
"platform_name": self.ui_param["platform_name"],
"platform_type": self.ui_param["platform_type"],
"platform_code_ICES": self.ui_param["platform_code_ICES"],
}
platform_dict = {"platform_name": "", "platform_type": "", "platform_code_ICES": ""}
unpacked_data = self.parser_obj.unpacked_data
time2 = self.parser_obj.ping_time
time1 = [time2[0]]

# If tilt_x and/or tilt_y are all nan, create single-value time2 dimension
# and single-value (np.nan) tilt_x and tilt_y
tilt_x = [np.nan] if np.isnan(unpacked_data["tilt_x"]).all() else unpacked_data["tilt_x"]
tilt_y = [np.nan] if np.isnan(unpacked_data["tilt_y"]).all() else unpacked_data["tilt_y"]
if (len(tilt_x) == 1 and np.isnan(tilt_x)) and (len(tilt_y) == 1 and np.isnan(tilt_y)):
time2 = [time2[0]]

ds = xr.Dataset(
{
"latitude": (
["time1"],
[np.nan],
self._varattrs["platform_var_default"]["latitude"],
),
"longitude": (
["time1"],
[np.nan],
self._varattrs["platform_var_default"]["longitude"],
),
"pitch": (
["time2"],
[np.nan] * len(time2),
self._varattrs["platform_var_default"]["pitch"],
),
"roll": (
["time2"],
[np.nan] * len(time2),
self._varattrs["platform_var_default"]["roll"],
),
"vertical_offset": (
["time2"],
[np.nan] * len(time2),
self._varattrs["platform_var_default"]["vertical_offset"],
),
emiliom marked this conversation as resolved.
Show resolved Hide resolved
"water_level": (
[],
np.nan,
self._varattrs["platform_var_default"]["water_level"],
),
"tilt_x": (
["time2"],
unpacked_data["tilt_x"],
tilt_x,
{
"long_name": "Tilt X",
"units": "degree",
"units": "arc_degree",
},
),
"tilt_y": (
["time2"],
unpacked_data["tilt_y"],
tilt_y,
{
"long_name": "Tilt Y",
"units": "degree",
"units": "arc_degree",
},
),
**{
var: (
["channel"],
[np.nan] * len(self.channel_ids_sorted),
self._varattrs["platform_var_default"][var],
)
for var in [
"transducer_offset_x",
"transducer_offset_y",
"transducer_offset_z",
]
},
**{
var: ([], np.nan, self._varattrs["platform_var_default"][var])
for var in [
Expand All @@ -177,15 +223,34 @@ def set_platform(self) -> xr.Dataset:
"position_offset_x",
"position_offset_y",
"position_offset_z",
"transducer_offset_x",
"transducer_offset_y",
"transducer_offset_z",
"vertical_offset",
"water_level",
]
},
"frequency_nominal": (
["channel"],
self.freq_sorted,
{
"units": "Hz",
"long_name": "Transducer frequency",
"valid_min": 0.0,
"standard_name": "sound_frequency",
},
),
},
coords={
"channel": (
["channel"],
self.channel_ids_sorted,
self._varattrs["beam_coord_default"]["channel"],
),
"time1": (
["time1"],
# xarray and probably CF don't accept time coordinate variable with Nan values
time1,
{
**self._varattrs["platform_coord_default"]["time1"],
"comment": "Time coordinate corresponding to NMEA position data.",
},
),
"time2": (
["time2"],
time2,
Expand Down
140 changes: 61 additions & 79 deletions echopype/convert/set_groups_ek60.py
Original file line number Diff line number Diff line change
Expand Up @@ -240,7 +240,11 @@ def set_platform(self) -> xr.Dataset:
# Read lat/long from NMEA datagram
time1, msg_type, lat, lon = self._extract_NMEA_latlon()

# NMEA dataset: variables filled with nan if do not exist
# NMEA dataset: variables filled with np.nan if they do not exist
platform_dict = {"platform_name": "", "platform_type": "", "platform_code_ICES": ""}
# Values for the variables below having a channel (ch) dependence
# are identical across channels
ch = list(self.sorted_channel.keys())[0]
ds = xr.Dataset(
{
"latitude": (
Expand All @@ -253,7 +257,46 @@ def set_platform(self) -> xr.Dataset:
lon,
self._varattrs["platform_var_default"]["longitude"],
),
"sentence_type": (["time1"], msg_type),
"sentence_type": (
["time1"],
msg_type,
self._varattrs["platform_var_default"]["sentence_type"],
),
"pitch": (
["time2"],
self.parser_obj.ping_data_dict["pitch"][ch],
self._varattrs["platform_var_default"]["pitch"],
),
"roll": (
["time2"],
self.parser_obj.ping_data_dict["roll"][ch],
self._varattrs["platform_var_default"]["roll"],
),
"vertical_offset": (
["time2"],
self.parser_obj.ping_data_dict["heave"][ch],
self._varattrs["platform_var_default"]["vertical_offset"],
),
"water_level": (
[],
# a scalar, assumed to be a constant in the source transducer_depth data
self.parser_obj.ping_data_dict["transducer_depth"][ch][0],
self._varattrs["platform_var_default"]["water_level"],
),
**{
var: ([], np.nan, self._varattrs["platform_var_default"][var])
for var in [
"MRU_offset_x",
"MRU_offset_y",
"MRU_offset_z",
"MRU_rotation_x",
"MRU_rotation_y",
"MRU_rotation_z",
"position_offset_x",
"position_offset_y",
"position_offset_z",
]
},
},
coords={
"time1": (
Expand All @@ -263,43 +306,26 @@ def set_platform(self) -> xr.Dataset:
**self._varattrs["platform_coord_default"]["time1"],
"comment": "Time coordinate corresponding to NMEA position data.",
},
)
),
"time2": (
["time2"],
self.parser_obj.ping_time[ch],
{
"axis": "T",
"long_name": "Timestamps for platform motion and orientation data",
"standard_name": "time",
"comment": "Time coordinate corresponding to platform motion and "
"orientation data.",
},
),
},
)

# TODO: consider allow users to set water_level like in EK80?
# if self.ui_param['water_level'] is not None:
# water_level = self.ui_param['water_level']
# else:
# water_level = np.nan
# print('WARNING: The water_level_draft was not in the file. Value '
# 'set to None.')

# Loop over channels and merge all
ds_plat = []
for ch in self.sorted_channel.keys():
ds_tmp = xr.Dataset(
{
"pitch": (
["time2"],
self.parser_obj.ping_data_dict["pitch"][ch],
self._varattrs["platform_var_default"]["pitch"],
),
"roll": (
["time2"],
self.parser_obj.ping_data_dict["roll"][ch],
self._varattrs["platform_var_default"]["roll"],
),
"vertical_offset": (
["time2"],
self.parser_obj.ping_data_dict["heave"][ch],
self._varattrs["platform_var_default"]["vertical_offset"],
),
"water_level": (
["time3"],
self.parser_obj.ping_data_dict["transducer_depth"][ch],
self._varattrs["platform_var_default"]["water_level"],
),
"transducer_offset_x": (
[],
self.parser_obj.config_datagram["transceivers"][ch].get("pos_x", np.nan),
Expand All @@ -315,58 +341,10 @@ def set_platform(self) -> xr.Dataset:
self.parser_obj.config_datagram["transceivers"][ch].get("pos_z", np.nan),
self._varattrs["platform_var_default"]["transducer_offset_z"],
),
**{
var: ([], np.nan, self._varattrs["platform_var_default"][var])
for var in [
"MRU_offset_x",
"MRU_offset_y",
"MRU_offset_z",
"MRU_rotation_x",
"MRU_rotation_y",
"MRU_rotation_z",
"position_offset_x",
"position_offset_y",
"position_offset_z",
]
},
},
coords={
"time2": (
["time2"],
self.parser_obj.ping_time[ch],
{
"axis": "T",
"long_name": "Timestamps for platform motion and orientation data",
"standard_name": "time",
"comment": "Time coordinate corresponding to platform motion and "
"orientation data.",
},
),
"time3": (
["time3"],
self.parser_obj.ping_time[ch],
{
"axis": "T",
"long_name": "Timestamps for platform-related sampling environment",
"standard_name": "time",
"comment": "Time coordinate corresponding to platform-related "
"sampling environment.",
},
),
},
attrs={
"platform_code_ICES": self.ui_param["platform_code_ICES"],
"platform_name": self.ui_param["platform_name"],
"platform_type": self.ui_param["platform_type"],
},
)

# Attach channel dimension/coordinate
ds_tmp = ds_tmp.expand_dims({"channel": [self.sorted_channel[ch]]})
ds_tmp["channel"] = ds_tmp["channel"].assign_attrs(
self._varattrs["beam_coord_default"]["channel"]
)

ds_tmp["frequency_nominal"] = (
["channel"],
[self.parser_obj.config_datagram["transceivers"][ch]["frequency"]],
Expand All @@ -385,9 +363,13 @@ def set_platform(self) -> xr.Dataset:
# pitch/roll/heave are the same for all freq channels
# consider only saving those from the first channel
ds_plat = xr.merge(ds_plat)
ds_plat["channel"] = ds_plat["channel"].assign_attrs(
self._varattrs["beam_coord_default"]["channel"]
)

# Merge with NMEA data
ds = xr.merge([ds, ds_plat], combine_attrs="override")
ds = ds.assign_attrs(platform_dict)

return set_time_encodings(ds)

Expand Down
Loading