acoused/View/acoustic_data_tab.py

3074 lines
128 KiB
Python

# ============================================================================== #
# acoustic_data_tab.py - AcouSed #
# Copyright (C) 2024-2025 INRAE #
# #
# This program is free software: you can redistribute it and/or modify #
# it under the terms of the GNU General Public License as published by #
# the Free Software Foundation, either version 3 of the License, or #
# (at your option) any later version. #
# #
# This program is distributed in the hope that it will be useful, #
# but WITHOUT ANY WARRANTY; without even the implied warranty of #
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the #
# GNU General Public License for more details. #
# #
# You should have received a copy of the GNU General Public License #
# along with this program. If not, see <https://www.gnu.org/licenses/>. #
# by Brahim MOUDJED #
# ============================================================================== #
# -*- coding: utf-8 -*-
import os
import locale
import logging
import numpy as np
import pandas as pd
from re import findall
from copy import deepcopy
from scipy.signal import savgol_filter
import matplotlib.pyplot as plt
from matplotlib.colors import LogNorm, CSS4_COLORS, BoundaryNorm
from matplotlib.backends.backend_qt5agg import FigureCanvasQTAgg as FigureCanvas
from matplotlib.backends.backend_qt5agg import NavigationToolbar2QT as NavigationToolBar
from PyQt5.QtWidgets import (
QWidget, QVBoxLayout, QHBoxLayout, QGroupBox,
QPushButton, QComboBox, QLineEdit, QLabel,
QGridLayout, QTableView, QSpacerItem, QSizePolicy,
QFileDialog, QMessageBox, QScrollArea,
QSlider, QMenu, QCheckBox, QAbstractItemView
)
from PyQt5.QtGui import QPixmap, QIcon
from PyQt5.QtCore import (
Qt, QCoreApplication, pyqtSignal, QEvent, QSize,
QPropertyAnimation
)
from pyqt_file_list_widget.fileListWidget import FileListWidget
import settings as stg
import Translation.constant_string as cs
from Model.TableModel import TableModel
from Model.acoustic_data_loader import AcousticDataLoader
from Model.acoustic_data_loader_UBSediFlow import AcousticDataLoaderUBSediFlow
from Model.calibration_constant_kt import CalibrationConstantKt
from tools import trace
locale.setlocale(locale.LC_ALL, '')
_translate = QCoreApplication.translate
logger = logging.getLogger("acoused")
class AcousticDataTab(QWidget):
COMPTEUR = 1
"""
This class generates the Acoustic Data Tab
"""
fileAdded = pyqtSignal(list)
fileRemoved = pyqtSignal(list)
newValueChanged = pyqtSignal(float)
def __init__(self, tab_widget):
super().__init__()
self._setup_icons()
self._setup_attrs()
self.calib_kt = CalibrationConstantKt()
### --- General layout of widgets ---
self.verticalLayoutMain = QVBoxLayout(tab_widget)
self.horizontalLayoutTop = QHBoxLayout()
self.verticalLayoutMain.addLayout(self.horizontalLayoutTop, 5) # 1O units is 100% , 1 units is 10%
self.horizontalLayoutBottom = QHBoxLayout()
self.verticalLayoutMain.addLayout(self.horizontalLayoutBottom, 5)
### --- Layout of groupbox in the Top horizontal layout box
# Download | Table of values | GPS file
# Measurement information | | Display options
self.groupbox_download = QGroupBox()
self.horizontalLayoutTop.addWidget(self.groupbox_download, 3)
self.groupbox_table = QGroupBox()
self.horizontalLayoutTop.addWidget(self.groupbox_table, 3)
self.groupbox_display_option = QGroupBox()
self.horizontalLayoutTop.addWidget(self.groupbox_display_option, 4)
### --- Layout of groupbox in the Bottom horizontal layout box
# 2D field of raw acoustic backscatter data | 2D field of Signal to Noise ratio
self.groupbox_transect_2Dplot_raw_BS_data = QGroupBox()
self.horizontalLayoutBottom.addWidget(self.groupbox_transect_2Dplot_raw_BS_data, 6)
self.groupbox_plot_the_vertical_profile_for_a_frequency = QGroupBox()
self.horizontalLayoutBottom.addWidget(self.groupbox_plot_the_vertical_profile_for_a_frequency, 4)
# =====================================================
# TOP HORIZONTAL BOX LAYOUT
# =====================================================
self.groupbox_download.setTitle("Acoustic recording")
self.verticalLayout_groupbox_download = QVBoxLayout(self.groupbox_download)
self.groupbox_acoustic_file = QGroupBox()
self.groupbox_acoustic_file.setTitle("Download file")
self.verticalLayout_groupbox_download.addWidget(self.groupbox_acoustic_file, 5)
self.groupbox_info = QGroupBox()
self.scrollbar_measurement_information = QScrollArea()
self.verticalLayout_groupbox_download.addWidget(self.scrollbar_measurement_information, 5)
# +++++++++++++++++++++++++++
# | Group box Download file |
# +++++++++++++++++++++++++++
self.gridLayout_groupbox_acoustic_file = QGridLayout(self.groupbox_acoustic_file)
self.combobox_ABS_system_choice = QComboBox()
self.combobox_ABS_system_choice.addItems([" ", "AQUAscat", "UBSediFlow"])
self.gridLayout_groupbox_acoustic_file.addWidget(self.combobox_ABS_system_choice, 0, 0, 1, 1)
self.spacerItem_FileList = QSpacerItem(5, 10, QSizePolicy.Expanding, QSizePolicy.Minimum)
self.gridLayout_groupbox_acoustic_file.addItem(self.spacerItem_FileList, 0, 1, 1, 1)
self.addBtn = QPushButton()
self.addBtn.setIcon(self.icon_add)
self.delBtn = QPushButton()
self.delBtn.setIcon(self.icon_delete)
self.clearBtn = QPushButton()
self.clearBtn.setIcon(self.icon_clear)
self.gridLayout_groupbox_acoustic_file.addWidget(self.addBtn, 0, 2, 1, 1)
self.gridLayout_groupbox_acoustic_file.addWidget(self.delBtn, 0, 3, 1, 1)
self.gridLayout_groupbox_acoustic_file.addWidget(self.clearBtn, 0, 4, 1, 1)
self.fileListWidget = FileListWidget()
self.fileListWidget.setSelectionMode(QAbstractItemView.SingleSelection)
self.gridLayout_groupbox_acoustic_file.addWidget(self.fileListWidget, 1, 0, 1, 5)
# ++++++++++++++++++++++++++++++++++++++
# | Group Box Measurements information |
# ++++++++++++++++++++++++++++++++++++++
self.scrollbar_measurement_information.setVerticalScrollBarPolicy(Qt.ScrollBarAlwaysOn)
self.scrollbar_measurement_information.setHorizontalScrollBarPolicy(Qt.ScrollBarAlwaysOn)
self.scrollbar_measurement_information.setWidgetResizable(True)
self.gridLayout_groupbox_info = QGridLayout(self.scrollbar_measurement_information)
self.groupbox_info.setLayout(self.gridLayout_groupbox_info)
self.scrollbar_measurement_information.setWidget(self.groupbox_info)
self.label_ABS_name = QLabel()
self.combobox_ABS_name = QComboBox()
self.combobox_ABS_name.addItems(self.calib_kt.data_ABS.keys())
self.label_date_acoustic_file = QLabel()
self.label_hour_acoustic_file = QLabel()
self.label_distance_from_ABS_to_free_surface = QLabel()
self.label_distance_from_ABS_to_free_surface.setText("Distance from ABS to free surface")
self.lineEdit_distance_from_ABS_to_free_surface = QLineEdit()
self.lineEdit_distance_from_ABS_to_free_surface.setText("0.00")
self.lineEdit_distance_from_ABS_to_free_surface.setMaximumWidth(100)
self.label_distance_from_ABS_to_free_surface_unit = QLabel()
self.label_distance_from_ABS_to_free_surface_unit.setText("m")
self.pushbutton_distance_from_ABS_to_free_surface = QPushButton()
self.pushbutton_distance_from_ABS_to_free_surface.setIcon(self.icon_refresh)
self.label_temperature = QLabel("Temperature : ")
self.lineEdit_temperature = QLineEdit()
self.lineEdit_temperature.setText("0.00")
self.lineEdit_temperature.setMaximumWidth(100)
self.label_temperature_unit = QLabel()
self.label_temperature_unit.setText("°C")
self.label_speed_of_sound = QLabel("Speed of sound : ")
self.lineEdit_speed_of_sound = QLineEdit()
self.lineEdit_speed_of_sound.setMaximumWidth(100)
self.label_speed_of_sound_unit = QLabel()
self.label_speed_of_sound_unit.setText("m/s")
self.label_freq = QLabel()
self.combobox_frequency_information = QComboBox()
self.combobox_frequency_information.setMaximumWidth(100)
self.label_kt = QLabel()
self.lineEdit_kt = QLineEdit()
self.lineEdit_kt.setMaximumWidth(100)
self.label_kt_unit = QLabel()
self.label_kt_unit.setText("<p>V.m<sup>1.5</sup></p>")
self.checkbox_kt = QCheckBox()
self.checkbox_kt.setChecked(True)
self.checkbox_kt.setToolTip("Checkbox checked : calibration is computed with kt value from the file (see File -> Settings -> ABS constant calibration kt) \n"
"Checkbox unchecked : calibration is computed from kt values read from the ABS")
self.label_sound_attenuation = QLabel("Sound attenuation : ")
self.lineEdit_sound_attenuation = QLineEdit()
self.lineEdit_sound_attenuation.setMaximumWidth(100)
self.label_sound_attenuation_unit = QLabel()
self.label_sound_attenuation_unit.setText("<p>m<sup>-1</sup><p>")
self.label_profiles = QLabel()
self.label_profiles_value = QLabel()
self.label_profiles_per_sec = QLabel()
self.label_profiles_per_sec_value = QLabel()
self.label_cells = QLabel() # n_cell in UBSediFlow parameters
self.label_cells_value = QLabel()
self.label_cell_size = QLabel() # r_em in UBSediFlow parameters
self.label_cell_size_value = QLabel()
self.label_pulse_length = QLabel() # n_p / PRF with n_p = n_ech, nb of pulses to calculate one instantaneous profile
self.label_pulse_length_value = QLabel()
self.label_pings_per_sec = QLabel() # PRF in UBSediFlow parameters
self.label_pings_per_sec_value = QLabel()
self.label_pings_per_profile = QLabel() # n_profile/n_avg in UBSediFlow parameters
self.label_pings_per_profile_value = QLabel()
self.label_rx = QLabel() # a0 in UBSediFlow parameters
self.lineEdit_rx = QLineEdit()
self.lineEdit_rx.setMaximumWidth(100)
self.checkbox_rx = QCheckBox()
self.label_tx = QLabel() # a1 in UBSediFlow parameters
self.lineEdit_tx = QLineEdit()
self.lineEdit_tx.setMaximumWidth(100)
self.checkbox_tx = QCheckBox()
# +++++++++++++++++++++++++++++
# | Group Box Table of values |
# +++++++++++++++++++++++++++++
self.groupbox_table.setTitle("Table of values")
self.verticalLayout_groupbox_table = QVBoxLayout(self.groupbox_table)
self.tableView = QTableView()
data = pd.DataFrame(np.zeros((10, 10)))
self.tableModel = TableModel(data)
self.tableView.setModel(self.tableModel)
self.verticalLayout_groupbox_table.addWidget(self.tableView)
# ++++++++++++++++++++++++++++
# | Group Box Display option |
# ++++++++++++++++++++++++++++
self.groupbox_display_option.setTitle("Display option")
self.verticalLayout_groupbox_display_option = QVBoxLayout(self.groupbox_display_option)
# o-o-o-o-o-o-o-o-o-o-o-o-o-o-o-o-o-o-o-o-o-o-o-o-o-o-o-o-o-o-o-o
# --- Group box GPS file ---
self.groupbox_gps = QGroupBox()
self.groupbox_gps.setTitle("Convert recording time to distance from bank")
self.horizontal_gps_input_data = QHBoxLayout(self.groupbox_gps)
self.groupbox_gps.setEnabled(False)
self.verticalLayout_groupbox_display_option.addWidget(self.groupbox_gps)
self.groupbox_gps_value = QGroupBox()
self.groupbox_gps_value.setTitle("Value")
self.groupbox_gps_value.setCheckable(True)
self.groupbox_gps_value.setChecked(True)
self.horizontal_gps_input_data.addWidget(self.groupbox_gps_value)
self.gridLayout_gps_value = QGridLayout(self.groupbox_gps_value)
self.label_distance_value = QLabel()
self.label_distance_value.setText("Distance : ")
self.gridLayout_gps_value.addWidget(self.label_distance_value, 0, 0, 1, 1)
self.lineEdit_gps_value = QLineEdit()
self.lineEdit_gps_value.setMaximumWidth(80)
self.gridLayout_gps_value.addWidget(self.lineEdit_gps_value, 0, 1, 1, 1)
self.label_m_per_record = QLabel("m / record")
self.gridLayout_gps_value.addWidget(self.label_m_per_record, 0, 2, 1, 1)
self.groupbox_gps_file = QGroupBox()
self.groupbox_gps_file.setCheckable(True)
self.groupbox_gps_file.setChecked(False)
self.groupbox_gps_file.setTitle("GPS file")
self.horizontal_gps_input_data.addWidget(self.groupbox_gps_file)
self.gridLayout_groupbox_gps_file = QGridLayout(self.groupbox_gps_file)
self.pushbutton_gps_file = QPushButton()
self.pushbutton_gps_file.setIcon(self.icon_folder)
self.gridLayout_groupbox_gps_file.addWidget(self.pushbutton_gps_file, 0, 0, 1, 1)
self.lineEdit_gps_file = QLineEdit()
self.gridLayout_groupbox_gps_file.addWidget(self.lineEdit_gps_file, 0, 1, 1, 1)
# --- Time offset line between ABS system time and GPS time ---
self.label_acoustic_gps_time = QLabel()
self.label_acoustic_gps_time.setText(
"T<span style= vertical-align:sub>acoustic</span> =" + " T<span style= vertical-align:sub>gps</span>")
self.gridLayout_groupbox_gps_file.addWidget(self.label_acoustic_gps_time, 0, 2, 1, 1)
self.combobox_plus_minus = QComboBox()
self.combobox_plus_minus.addItem("+")
self.combobox_plus_minus.addItem("-")
self.gridLayout_groupbox_gps_file.addWidget(self.combobox_plus_minus, 0, 3, 1, 1)
self.lineEdit_time_offset_value = QLineEdit()
self.lineEdit_time_offset_value.setMaximumWidth(80)
self.gridLayout_groupbox_gps_file.addWidget(self.lineEdit_time_offset_value, 0, 4, 1, 1)
self.label_seconds = QLabel()
self.label_seconds.setText("sec")
self.gridLayout_groupbox_gps_file.addWidget(self.label_seconds, 0, 5, 1, 1)
# ----------------------------------------------------------------------------
# o-o-o-o-o-o-o-o-o-o-o-o-o-o-o-o-o-o-o-o-o-o-o-o-o-o-o-o-o-o-o-o
# --- Groupbox display option limits ---
self.groupbox_display_option_limits = QGroupBox()
self.groupbox_display_option_limits.setTitle("Set the boundaries")
self.gridLayout_groupbox_display_option_limits = QGridLayout(self.groupbox_display_option_limits)
self.verticalLayout_groupbox_display_option.addWidget(self.groupbox_display_option_limits)
# --------------------------------
self.label_min = QLabel()
self.label_min.setText("min")
self.gridLayout_groupbox_display_option_limits.addWidget(self.label_min, 0, 1, 1, 1, Qt.AlignCenter)
self.label_upstream = QLabel()
self.label_upstream.setText("limit -->")
self.gridLayout_groupbox_display_option_limits.addWidget(self.label_upstream, 0, 2, 1, 1, Qt.AlignCenter)
self.label_downstream = QLabel()
self.label_downstream.setText("<-- limit")
self.gridLayout_groupbox_display_option_limits.addWidget(self.label_downstream, 0, 3, 1, 1, Qt.AlignCenter)
self.label_max = QLabel()
self.label_max.setText("max")
self.gridLayout_groupbox_display_option_limits.addWidget(self.label_max, 0, 4, 1, 1, Qt.AlignCenter)
self.label_unit = QLabel()
self.label_unit.setText("unit")
self.gridLayout_groupbox_display_option_limits.addWidget(self.label_unit, 0, 5, 1, 1, Qt.AlignCenter)
# --------------------------------
self.label_depth = QLabel("Depth")
self.gridLayout_groupbox_display_option_limits.addWidget(self.label_depth, 1, 0, 1, 1, Qt.AlignRight)
self.label_depth_min = QLabel()
self.label_depth_min.setText("0.00")
self.gridLayout_groupbox_display_option_limits.addWidget(self.label_depth_min, 1, 1, 1, 1, Qt.AlignCenter)
self.lineEdit_depth_min_limits = QLineEdit()
self.lineEdit_depth_min_limits.setText("0.00")
self.lineEdit_depth_min_limits.setMaximumWidth(80)
self.gridLayout_groupbox_display_option_limits.addWidget(self.lineEdit_depth_min_limits, 1, 2, 1, 1, Qt.AlignCenter)
self.lineEdit_depth_max_limits = QLineEdit()
self.lineEdit_depth_max_limits.setText("0.00")
self.lineEdit_depth_max_limits.setMaximumWidth(80)
self.gridLayout_groupbox_display_option_limits.addWidget(self.lineEdit_depth_max_limits, 1, 3, 1, 1, Qt.AlignCenter)
self.label_depth_max = QLabel()
self.label_depth_max.setText("0.00")
self.gridLayout_groupbox_display_option_limits.addWidget(self.label_depth_max, 1, 4, 1, 1, Qt.AlignCenter)
self.label_depth_unit_meter = QLabel("meters")
self.gridLayout_groupbox_display_option_limits.addWidget(self.label_depth_unit_meter, 1, 5, 1, 1, Qt.AlignCenter)
self.pushbutton_apply_depth_limits = QPushButton()
self.pushbutton_apply_depth_limits.setIcon(self.icon_apply_limits)
self.gridLayout_groupbox_display_option_limits.addWidget(self.pushbutton_apply_depth_limits, 1, 6, 1, 1)
# --------------------------------
self.label_recording_time = QLabel("Recording time")
self.gridLayout_groupbox_display_option_limits.addWidget(self.label_recording_time, 2, 0, 1, 1, Qt.AlignRight)
self.label_time_min = QLabel()
self.label_time_min.setText("0.00")
self.gridLayout_groupbox_display_option_limits.addWidget(self.label_time_min, 2, 1, 1, 1, Qt.AlignCenter)
self.lineEdit_time_min_limits = QLineEdit()
self.lineEdit_time_min_limits.setText("0.00")
self.lineEdit_time_min_limits.setMaximumWidth(80)
self.gridLayout_groupbox_display_option_limits.addWidget(self.lineEdit_time_min_limits, 2, 2, 1, 1,
Qt.AlignCenter)
self.lineEdit_time_max_limits = QLineEdit()
self.lineEdit_time_max_limits.setText("0.00")
self.lineEdit_time_max_limits.setMaximumWidth(80)
self.gridLayout_groupbox_display_option_limits.addWidget(self.lineEdit_time_max_limits, 2, 3, 1, 1,
Qt.AlignCenter)
self.label_time_max = QLabel()
self.label_time_max.setText("0.00")
self.gridLayout_groupbox_display_option_limits.addWidget(self.label_time_max, 2, 4, 1, 1, Qt.AlignCenter)
self.label_recording_time_unit_meter = QLabel("seconds")
self.gridLayout_groupbox_display_option_limits.addWidget(self.label_recording_time_unit_meter, 2, 5, 1, 1, Qt.AlignCenter)
self.pushbutton_apply_recording_time_limits = QPushButton()
self.pushbutton_apply_recording_time_limits.setIcon(self.icon_apply_limits)
self.gridLayout_groupbox_display_option_limits.addWidget(self.pushbutton_apply_recording_time_limits, 2, 6, 1, 1)
# ---------------------------------
self.label_distance_from_bank = QLabel("Distance from bank")
self.gridLayout_groupbox_display_option_limits.addWidget(
self.label_distance_from_bank,
3, 0, 1, 1, Qt.AlignRight
)
self.label_distance_from_bank.setEnabled(False)
self.label_distance_from_bank_min = QLabel()
self.label_distance_from_bank_min.setText("0.00")
self.gridLayout_groupbox_display_option_limits.addWidget(
self.label_distance_from_bank_min,
3, 1, 1, 1, Qt.AlignCenter
)
self.label_distance_from_bank_min.setEnabled(False)
self.lineEdit_distance_from_bank_min_limits = QLineEdit()
self.lineEdit_distance_from_bank_min_limits.setText("0.00")
self.lineEdit_distance_from_bank_min_limits.setMaximumWidth(80)
self.gridLayout_groupbox_display_option_limits.addWidget(
self.lineEdit_distance_from_bank_min_limits,
3, 2, 1, 1, Qt.AlignCenter
)
self.lineEdit_distance_from_bank_min_limits.setEnabled(False)
self.lineEdit_distance_from_bank_max_limits = QLineEdit()
self.lineEdit_distance_from_bank_max_limits.setText("0.00")
self.lineEdit_distance_from_bank_max_limits.setMaximumWidth(80)
self.gridLayout_groupbox_display_option_limits.addWidget(
self.lineEdit_distance_from_bank_max_limits,
3, 3, 1, 1, Qt.AlignCenter
)
self.lineEdit_distance_from_bank_max_limits.setEnabled(False)
self.label_distance_from_bank_max = QLabel()
self.label_distance_from_bank_max.setText("0.00")
self.gridLayout_groupbox_display_option_limits.addWidget(
self.label_distance_from_bank_max,
3, 4, 1, 1, Qt.AlignCenter
)
self.label_distance_from_bank_max.setEnabled(False)
self.label_distance_from_bank_unit_meter = QLabel("meters")
self.gridLayout_groupbox_display_option_limits.addWidget(
self.label_distance_from_bank_unit_meter,
3, 5, 1, 1, Qt.AlignCenter
)
self.label_distance_from_bank_unit_meter.setEnabled(False)
self.pushbutton_apply_distance_from_bank_limits = QPushButton()
self.pushbutton_apply_distance_from_bank_limits.setIcon(self.icon_apply_limits)
self.gridLayout_groupbox_display_option_limits.addWidget(
self.pushbutton_apply_distance_from_bank_limits,
3, 6, 1, 1
)
self.pushbutton_apply_distance_from_bank_limits.setEnabled(False)
# ---------------------------------------
self.groupbox_display_option_bathymetry = QGroupBox()
self.groupbox_display_option_bathymetry.setTitle("Detect bottom of the river")
self.gridLayout_groupbox_display_option_bathymetry = QGridLayout(self.groupbox_display_option_bathymetry)
self.verticalLayout_groupbox_display_option.addWidget(self.groupbox_display_option_bathymetry)
self.combobox_frequency_bathymetry = QComboBox()
self.combobox_frequency_bathymetry.setMaximumWidth(150)
self.gridLayout_groupbox_display_option_bathymetry.addWidget(self.combobox_frequency_bathymetry, 0, 0, 1, 1, Qt.AlignCenter)
self.label_from_bathy = QLabel()
self.label_from_bathy.setText("From")
self.gridLayout_groupbox_display_option_bathymetry.addWidget(self.label_from_bathy, 0, 1, 1, 1, Qt.AlignCenter)
self.lineEdit_depth_min_bathy = QLineEdit()
self.lineEdit_depth_min_bathy.setText("0.00")
self.lineEdit_depth_min_bathy.setMaximumWidth(80)
self.gridLayout_groupbox_display_option_bathymetry.addWidget(self.lineEdit_depth_min_bathy, 0, 2, 1, 1, Qt.AlignCenter)
self.label_depth_min_unit = QLabel()
self.label_depth_min_unit.setText("m")
self.gridLayout_groupbox_display_option_bathymetry.addWidget(self.label_depth_min_unit, 0, 3, 1, 1, Qt.AlignLeft)
self.label_to_bathy = QLabel()
self.label_to_bathy.setText("to")
self.gridLayout_groupbox_display_option_bathymetry.addWidget(self.label_to_bathy, 0, 4, 1, 1, Qt.AlignCenter)
self.lineEdit_depth_max_bathy = QLineEdit()
self.lineEdit_depth_max_bathy.setText("0.00")
self.lineEdit_depth_max_bathy.setMaximumWidth(80)
self.gridLayout_groupbox_display_option_bathymetry.addWidget(self.lineEdit_depth_max_bathy, 0, 5, 1, 1, Qt.AlignCenter)
self.label_depth_max_unit = QLabel()
self.label_depth_max_unit.setText("m")
self.gridLayout_groupbox_display_option_bathymetry.addWidget(self.label_depth_max_unit, 0, 6, 1, 1, Qt.AlignLeft)
self.label_next_cell = QLabel()
self.label_next_cell.setText("+/-")
self.gridLayout_groupbox_display_option_bathymetry.addWidget(self.label_next_cell, 0, 7, 1, 1, Qt.AlignCenter)
self.lineEdit_next_cell_bathy = QLineEdit()
self.lineEdit_next_cell_bathy.setText("0.00")
self.lineEdit_next_cell_bathy.setMaximumWidth(80)
self.gridLayout_groupbox_display_option_bathymetry.addWidget(self.lineEdit_next_cell_bathy, 0, 8, 1, 1, Qt.AlignCenter)
self.label_next_cell_unit = QLabel()
self.label_next_cell_unit.setText("m")
self.gridLayout_groupbox_display_option_bathymetry.addWidget(self.label_next_cell_unit, 0, 9, 1, 1, Qt.AlignLeft)
self.pushbutton_apply_bathymetry = QPushButton()
self.pushbutton_apply_bathymetry.setIcon(self.icon_apply_limits)
self.gridLayout_groupbox_display_option_bathymetry.addWidget(self.pushbutton_apply_bathymetry, 0, 10, 1, 1)
# =====================================================
# BOTTOM HORIZONTAL BOX LAYOUT
# =====================================================
# +++++++++++++++++++++++++++++++++++++************+++
# | Group Box Backscatter Acoustic Raw Data 2D field |
# ++++++++++++++++++++++++++************++++++++++++++
self.verticalLayout_groupbox_transect_2Dplot_raw_BS_data = QVBoxLayout(self.groupbox_transect_2Dplot_raw_BS_data)
self.canvas_BS = FigureCanvas()
self.toolbar_BS = NavigationToolBar(self.canvas_BS, self)
self.verticalLayout_groupbox_transect_2Dplot_raw_BS_data.addWidget(self.toolbar_BS)
self.scroll_BS = QScrollArea()
self.scroll_BS.setWidget(self.canvas_BS)
self.scroll_BS.setHorizontalScrollBarPolicy(Qt.ScrollBarAlwaysOn)
self.scroll_BS.setVerticalScrollBarPolicy(Qt.ScrollBarAlwaysOn)
self.scroll_BS.setAlignment(Qt.AlignCenter)
self.verticalLayout_groupbox_transect_2Dplot_raw_BS_data.addWidget(self.scroll_BS)
# +++++++++++++++++++++++++++++++++++++++++++
# | Group Box Plot profile from BS 2D field |
# +++++++++++++++++++++++++++++++++++++++++++
self.verticalLayout_groupbox_plot_the_vertical_profile_for_a_frequency = QVBoxLayout(self.groupbox_plot_the_vertical_profile_for_a_frequency)
self.groupbox_plot_the_vertical_profile_for_a_frequency.setTitle("Plot the vertical profile for one frequency")
self.horizontalLayout_spacerItem_combobox_frequency_profile = QHBoxLayout()
self.verticalLayout_groupbox_plot_the_vertical_profile_for_a_frequency.addLayout(
self.horizontalLayout_spacerItem_combobox_frequency_profile)
self.spacerItem_frequency_profile = QSpacerItem(50, 10, QSizePolicy.Expanding, QSizePolicy.Minimum)
self.horizontalLayout_spacerItem_combobox_frequency_profile.addSpacerItem(self.spacerItem_frequency_profile)
self.combobox_frequency_profile = QComboBox()
self.horizontalLayout_spacerItem_combobox_frequency_profile.addWidget(self.combobox_frequency_profile)
self.groupbox_plot_profile = QGroupBox()
self.verticalLayout_groupbox_plot_profile = QVBoxLayout(self.groupbox_plot_profile)
self.verticalLayout_groupbox_plot_the_vertical_profile_for_a_frequency.addWidget(self.groupbox_plot_profile)
self.canvas_plot_profile = FigureCanvas()
self.toolbar_profile = NavigationToolBar(self.canvas_plot_profile, self)
self.verticalLayout_groupbox_plot_profile.addWidget(self.toolbar_profile)
self.verticalLayout_groupbox_plot_profile.addWidget(self.canvas_plot_profile)
# --- Slider for moving the profile ---
self.horizontalLayout_slider = QHBoxLayout()
self.verticalLayout_groupbox_plot_the_vertical_profile_for_a_frequency.addLayout(self.horizontalLayout_slider)
self.pushbutton_slider_left_to_begin = QPushButton()
self.pushbutton_slider_left_to_begin.setIcon(self.icon_triangle_left_to_begin)
self.horizontalLayout_slider.addWidget(self.pushbutton_slider_left_to_begin)
self.pushbutton_slider_left = QPushButton()
self.pushbutton_slider_left.setIcon(self.icon_triangle_left)
self.horizontalLayout_slider.addWidget(self.pushbutton_slider_left)
self.lineEdit_slider = QLineEdit()
self.lineEdit_slider.setText("1")
self.lineEdit_slider.setFixedWidth(50)
self.horizontalLayout_slider.addWidget(self.lineEdit_slider)
self.pushbutton_slider_right = QPushButton()
self.pushbutton_slider_right.setIcon(self.icon_triangle_right)
self.horizontalLayout_slider.addWidget(self.pushbutton_slider_right)
self.pushbutton_slider_right_to_end = QPushButton()
self.pushbutton_slider_right_to_end.setIcon(self.icon_triangle_right_to_end)
self.horizontalLayout_slider.addWidget(self.pushbutton_slider_right_to_end)
self.slider = QSlider()
self.horizontalLayout_slider.addWidget(self.slider, 9)
self.slider.setOrientation(Qt.Horizontal)
self.slider.setCursor(Qt.OpenHandCursor)
self.slider.setMinimum(1)
self.slider.setMaximum(10)
self.slider.setTickInterval(1)
self.slider.setValue(1)
self.retranslate_acoustic_data_tab()
self.max_selected_file = 1
# --------------------------------------------------------------------------------------------------------------
# --- Connect signal of widget ---
self.combobox_ABS_system_choice.currentTextChanged.connect(self.ABS_system_choice)
self.addBtn.clicked.connect(self.open_dialog_box)
self.delBtn.clicked.connect(self.remove_file_from_ListWidget)
self.clearBtn.clicked.connect(self.clear_files_from_ListWidget)
self.fileListWidget.itemSelectionChanged.connect(self.fileListWidget_event)
# self.fileListWidget.itemSelectionChanged.connect(self.print_selected_file)
# self.fileListWidget.itemSelectionChanged.connect(self.fill_measurements_information_groupbox)
# self.fileListWidget.itemSelectionChanged.connect(self.fill_table)
# self.fileListWidget.itemSelectionChanged.connect(self.compute_tmin_tmax)
# self.fileListWidget.itemSelectionChanged.connect(self.compute_rmin_rmax)
# self.fileListWidget.itemSelectionChanged.connect(self.update_frequency_combobox)
# # self.fileListWidget.itemSelectionChanged.connect(self.plot_backscattered_acoustic_signal_recording)
# # self.fileListWidget.itemSelectionChanged.connect(self.plot_profile)
# self.fileListWidget.itemSelectionChanged.connect(self.update_plot_backscattered_acoustic_signal_recording)
# self.fileListWidget.itemSelectionChanged.connect(self.update_plot_profile)
# self.fileListWidget.itemSelectionChanged.connect(self.set_range_for_spinboxes_bathymetry)
self.combobox_ABS_name.currentIndexChanged.connect(self.fill_measurements_information_groupbox)
self.checkbox_kt.stateChanged.connect(self.activate_unactivate_spinbox_kt)
self.lineEdit_distance_from_ABS_to_free_surface.returnPressed.connect(self.distance_from_ABS_to_free_surface)
self.pushbutton_distance_from_ABS_to_free_surface.clicked.connect(self.refresh_distance_from_ABS_to_free_surface)
self.lineEdit_temperature.returnPressed.connect(self.temperature_value)
self.lineEdit_speed_of_sound.returnPressed.connect(self.water_velocity)
self.lineEdit_sound_attenuation.returnPressed.connect(self.water_attenuation)
self.groupbox_gps_value.toggled.connect(self.groupbox_gps_value_toggle)
self.groupbox_gps_value.toggled.connect(self.groupbox_gps_value_size_change)
self.groupbox_gps_file.toggled.connect(self.groupbox_gps_file_toggle)
self.groupbox_gps_file.toggled.connect(self.groupbox_gps_file_size_change)
self.pushbutton_apply_depth_limits.clicked.connect(self.compute_BS_cross_section)
self.pushbutton_apply_depth_limits.clicked.connect(self.update_plot_backscattered_acoustic_signal_recording)
self.pushbutton_apply_depth_limits.clicked.connect(self.update_plot_profile)
self.pushbutton_apply_depth_limits.clicked.connect(self.set_range_for_spinboxes_bathymetry)
self.pushbutton_apply_recording_time_limits.clicked.connect(self.compute_BS_cross_section)
self.pushbutton_apply_recording_time_limits.clicked.connect(self.detect_bottom)
self.pushbutton_apply_recording_time_limits.clicked.connect(self.update_plot_backscattered_acoustic_signal_recording)
self.pushbutton_apply_recording_time_limits.clicked.connect(self.update_plot_profile)
self.pushbutton_apply_bathymetry.clicked.connect(self.detect_bottom)
self.pushbutton_slider_left_to_begin.clicked.connect(self.slide_profile_number_to_begin)
self.pushbutton_slider_left.clicked.connect(self.slide_profile_number_to_left)
self.pushbutton_slider_right.clicked.connect(self.slide_profile_number_to_right)
self.pushbutton_slider_right_to_end.clicked.connect(self.slide_profile_number_to_end)
self.lineEdit_slider.returnPressed.connect(self.profile_number_on_lineEdit)
self.slider.valueChanged.connect(self.update_lineEdit_by_moving_slider)
self.slider.valueChanged.connect(self.update_plot_profile)
self.slider.valueChanged.connect(self.update_plot_backscattered_acoustic_signal_recording)
def _setup_icons(self):
def path_icon(icon):
return os.path.join(
"icons", icon
)
self.icon_folder = QIcon(path_icon("folder.png"))
self.icon_apply_limits = QIcon(path_icon("circle_green_arrow_right.png"))
self.icon_triangle_left_to_begin = QIcon(path_icon("triangle_left_to_begin.png"))
self.icon_triangle_left = QIcon(path_icon("triangle_left.png"))
self.icon_triangle_right = QIcon(path_icon("triangle_right.png"))
self.icon_triangle_right_to_end = QIcon(path_icon("triangle_right_to_end.png"))
self.icon_add = QIcon(path_icon("add.png"))
self.icon_delete = QIcon(path_icon("delete.png"))
self.icon_clear = QIcon(path_icon("clear.png"))
self.icon_between = QPixmap(path_icon("between.png"))
self.icon_refresh = QIcon(path_icon("update.png"))
def _setup_attrs(self):
self.fig_profile = None
self.fig_BS = None
# -------------------- Functions for Acoustic dataTab --------------------
def full_update(self):
logger.debug(f"{__name__}: Update")
self.blockSignals(True)
self.fileListWidget.blockSignals(True)
self.combobox_ABS_system_choice.blockSignals(True)
self.combobox_ABS_system_choice.setCurrentText(stg.ABS_name[0])
self.ABS_system_choice()
self.fileListWidget.addFilenames(stg.filename_BS_raw_data)
self.fill_measurements_information_groupbox()
self.fill_table()
self.plot_backscattered_acoustic_signal_recording()
self.plot_profile()
self.update_frequency_combobox()
self.update_bottom_detection_settings()
self.water_attenuation()
self.compute_tmin_tmax()
self.compute_rmin_rmax()
self.combobox_ABS_system_choice.blockSignals(False)
self.fileListWidget.blockSignals(False)
self.blockSignals(False)
def retranslate_acoustic_data_tab(self):
self.groupbox_info.setTitle(_translate("CONSTANT_STRING", cs.MEASUREMENTS_INFORMATION))
self.label_date_acoustic_file.setText(_translate("CONSTANT_STRING", cs.DATE) + ":")
self.label_hour_acoustic_file.setText(_translate("CONSTANT_STRING", cs.HOUR) + ":")
self.label_profiles.setText(_translate("CONSTANT_STRING", cs.NB_PROFILES) + ":")
self.label_profiles.setToolTip(_translate("CONSTANT_STRING", cs.NB_PROFILES_TOOLTIP))
self.label_profiles_per_sec.setText(_translate("CONSTANT_STRING", cs.NB_PROFILES_PER_SEC) + ":")
self.label_profiles_per_sec.setToolTip(_translate("CONSTANT_STRING", cs.NB_PROFILES_PER_SEC_TOOLTIP))
self.label_cells.setText(_translate("CONSTANT_STRING", cs.NB_CELLS) + ":")
self.label_cells.setToolTip(_translate("CONSTANT_STRING", cs.NB_CELLS_TOOLTIP))
self.label_cell_size.setText(_translate("CONSTANT_STRING", cs.CELL_SIZE) + ":")
self.label_cell_size.setToolTip(_translate("CONSTANT_STRING", cs.CELL_SIZE_TOOLTIP))
self.label_pulse_length.setText(_translate("CONSTANT_STRING", cs.PULSE_LENGHT) + ":")
self.label_pulse_length.setToolTip(_translate("CONSTANT_STRING", cs.PULSE_LENGHT_TOOLTIP))
self.label_pings_per_sec.setText(_translate("CONSTANT_STRING", cs.NB_PINGS_PER_SEC))
self.label_pings_per_sec.setToolTip(_translate("CONSTANT_STRING", cs.NB_PINGS_PER_SEC_TOOLTIP))
self.label_pings_per_profile.setText(_translate("CONSTANT_STRING", cs.NB_PINGS_PER_PROFILE) + ":")
self.label_pings_per_profile.setToolTip(_translate("CONSTANT_STRING", cs.NB_PINGS_PER_PROFILE_TOOLTIP))
self.label_freq.setText(_translate("CONSTANT_STRING", cs.FREQUENCY) + ":")
self.label_freq.setToolTip(_translate("CONSTANT_STRING", cs.FREQUENCY_TOOLTIP))
self.label_kt.setText(_translate("CONSTANT_STRING", cs.KT) + ":")
self.label_kt.setToolTip(_translate("CONSTANT_STRING", cs.KT_TOOLTIP))
self.label_rx.setText(_translate("CONSTANT_STRING", cs.GAIN_RX) + ":")
self.label_rx.setToolTip(_translate("CONSTANT_STRING", cs.GAIN_RX_TOOLTIP))
self.label_tx.setText(_translate("CONSTANT_STRING", cs.GAIN_TX) + ":")
self.label_tx.setToolTip(_translate("CONSTANT_STRING", cs.GAIN_TX_TOOLTIP))
self.groupbox_transect_2Dplot_raw_BS_data.setTitle(_translate("CONSTANT_STRING", cs.RAW_ACOUSTIC_DATA_2D_FIELD))
def fileListWidget_event(self):
self.fileListWidget.blockSignals(True)
self.print_selected_file()
self.fill_measurements_information_groupbox()
self.fill_table()
self.compute_tmin_tmax()
self.compute_rmin_rmax()
# self.compute_time_cross_section()
self.update_frequency_combobox()
# self.fileListWidget.itemSelectionChanged.connect(self.plot_backscattered_acoustic_signal_recording)
# self.fileListWidget.itemSelectionChanged.connect(self.plot_profile)
self.update_plot_backscattered_acoustic_signal_recording()
self.update_plot_profile()
self.update_bottom_detection_settings()
self.fileListWidget.blockSignals(False)
def print_selected_file(self):
logger.debug(
f"Selected file in list widget : {self.fileListWidget.selectedItems()}"
)
logger.debug(
"self.fileListWidget.selectedItems()[1:] : "
+ f"{self.fileListWidget.selectedItems()[1:]}"
)
if len(self.fileListWidget.selectedItems()) > self.max_selected_file:
self.fileListWidget.setSelectionMode(1)
def onClicked_radiobutton_gps(self):
radiobutton = self.sender()
if radiobutton.isChecked():
if self.radiobutton_value.isChecked():
self.groupbox_gps_value.setVisible(True)
self.groupbox_gps_file.setVisible(False)
elif self.radiobutton_file.isChecked():
self.groupbox_gps_value.setVisible(False)
self.groupbox_gps_file.setVisible(True)
def ABS_system_choice(self):
if self.combobox_ABS_system_choice.currentText() == " ":
self.groupbox_measurement_information_no_ABS()
elif self.combobox_ABS_system_choice.currentText() == "AQUAscat":
self.groupbox_measurement_information_Aquascat()
elif self.combobox_ABS_system_choice.currentText() == "UBSediFlow":
self.groupbox_measurement_information_UBSediFlow()
def groupbox_measurement_information_no_ABS(self):
self.label_ABS_name.hide()
self.combobox_ABS_name.hide()
self.label_date_acoustic_file.hide()
self.label_hour_acoustic_file.hide()
self.label_distance_from_ABS_to_free_surface.hide()
self.lineEdit_distance_from_ABS_to_free_surface.hide()
self.label_distance_from_ABS_to_free_surface_unit.hide()
self.pushbutton_distance_from_ABS_to_free_surface.hide()
self.label_temperature.hide()
self.lineEdit_temperature.hide()
self.label_temperature_unit.hide()
self.label_speed_of_sound.hide()
self.lineEdit_speed_of_sound.hide()
self.label_speed_of_sound_unit.hide()
self.label_sound_attenuation.hide()
self.lineEdit_sound_attenuation.hide()
self.label_sound_attenuation_unit.hide()
self.label_freq.hide()
self.combobox_frequency_information.hide()
self.label_profiles.hide()
self.label_profiles_per_sec.hide()
self.label_cells.hide()
self.label_cell_size.hide()
self.label_pulse_length.hide()
self.label_pings_per_sec.hide()
self.label_pings_per_profile.hide()
self.label_kt.hide()
self.lineEdit_kt.hide()
self.label_kt_unit.hide()
self.checkbox_kt.hide()
self.label_rx.hide()
self.lineEdit_rx.hide()
self.checkbox_rx.hide()
self.label_tx.hide()
self.lineEdit_tx.hide()
self.checkbox_tx.hide()
def groupbox_measurement_information_Aquascat(self):
# --- Hide UBSediFlow information and remove widget from grid layout ---
self.label_ABS_name.hide()
self.combobox_ABS_name.hide()
self.label_date_acoustic_file.hide()
self.label_hour_acoustic_file.hide()
self.label_distance_from_ABS_to_free_surface.hide()
self.lineEdit_distance_from_ABS_to_free_surface.hide()
self.label_distance_from_ABS_to_free_surface_unit.hide()
self.pushbutton_distance_from_ABS_to_free_surface.hide()
self.label_temperature.hide()
self.lineEdit_temperature.hide()
self.label_temperature_unit.hide()
self.label_speed_of_sound.hide()
self.lineEdit_speed_of_sound.hide()
self.label_speed_of_sound_unit.hide()
self.label_sound_attenuation.hide()
self.lineEdit_sound_attenuation.hide()
self.label_sound_attenuation_unit.hide()
self.label_freq.hide()
self.combobox_frequency_information.hide()
self.label_profiles.hide()
self.label_profiles_per_sec.hide()
self.label_cells.hide()
self.label_cell_size.hide()
self.label_pulse_length.hide()
self.label_pings_per_sec.hide()
self.label_pings_per_profile.hide()
self.label_kt.hide()
self.lineEdit_kt.hide()
self.label_kt_unit.hide()
self.checkbox_kt.hide()
self.label_rx.hide()
self.lineEdit_rx.hide()
self.checkbox_rx.hide()
self.label_tx.hide()
self.lineEdit_tx.hide()
self.checkbox_tx.hide()
for i in reversed(range(self.gridLayout_groupbox_info.count())):
widgetToRemove = self.gridLayout_groupbox_info.itemAt(i).widget()
# remove it from the layout list
self.gridLayout_groupbox_info.removeWidget(widgetToRemove)
# remove it from the gui
widgetToRemove.setParent(None)
# --- Show Aquascat information ---
self.label_ABS_name.show()
self.label_ABS_name.setText("Acoustic Backscatter System: AQUAscat")
self.gridLayout_groupbox_info.addWidget(self.label_ABS_name, 0, 0, 1, 2, Qt.AlignCenter)
self.combobox_ABS_name.show()
self.gridLayout_groupbox_info.addWidget(self.combobox_ABS_name, 0, 2, 1, 2, Qt.AlignCenter)
self.label_date_acoustic_file.show()
self.gridLayout_groupbox_info.addWidget(self.label_date_acoustic_file, 1, 0, 1, 1, Qt.AlignLeft)
self.label_hour_acoustic_file.show()
self.gridLayout_groupbox_info.addWidget(self.label_hour_acoustic_file, 1, 1, 1, 1, Qt.AlignLeft)
self.label_distance_from_ABS_to_free_surface.show()
self.gridLayout_groupbox_info.addWidget(self.label_distance_from_ABS_to_free_surface, 2, 0, 1, 1, Qt.AlignLeft)
self.lineEdit_distance_from_ABS_to_free_surface.show()
self.gridLayout_groupbox_info.addWidget(self.lineEdit_distance_from_ABS_to_free_surface, 2, 1, 1, 1, Qt.AlignLeft)
self.label_distance_from_ABS_to_free_surface_unit.show()
self.gridLayout_groupbox_info.addWidget(self.label_distance_from_ABS_to_free_surface_unit, 2, 2, 1, 1, Qt.AlignLeft)
self.pushbutton_distance_from_ABS_to_free_surface.show()
self.gridLayout_groupbox_info.addWidget(self.pushbutton_distance_from_ABS_to_free_surface, 2, 3, 1, 1, Qt.AlignLeft)
self.label_temperature.show()
self.gridLayout_groupbox_info.addWidget(self.label_temperature, 3, 0, 1, 1, Qt.AlignLeft)
self.lineEdit_temperature.show()
self.gridLayout_groupbox_info.addWidget(self.lineEdit_temperature, 3, 1, 1, 1, Qt.AlignLeft)
self.label_temperature_unit.show()
self.gridLayout_groupbox_info.addWidget(self.label_temperature_unit, 3, 2, 1, 1, Qt.AlignLeft)
self.setup_temperature_value()
self.label_speed_of_sound.show()
self.gridLayout_groupbox_info.addWidget(self.label_speed_of_sound, 4, 0, 1, 1, Qt.AlignLeft)
self.lineEdit_speed_of_sound.show()
self.gridLayout_groupbox_info.addWidget(self.lineEdit_speed_of_sound, 4, 1, 1, 1, Qt.AlignLeft)
self.label_speed_of_sound_unit.show()
self.gridLayout_groupbox_info.addWidget(self.label_speed_of_sound_unit, 4, 2, 1, 1, Qt.AlignLeft)
self.label_freq.show()
self.gridLayout_groupbox_info.addWidget(self.label_freq, 5, 0, 1, 1, Qt.AlignLeft)
self.combobox_frequency_information.show()
self.gridLayout_groupbox_info.addWidget(self.combobox_frequency_information, 5, 1, 1, 1, Qt.AlignLeft)
self.label_kt.show()
self.gridLayout_groupbox_info.addWidget(self.label_kt, 6, 0, 1, 1, Qt.AlignLeft)
self.lineEdit_kt.show()
self.gridLayout_groupbox_info.addWidget(self.lineEdit_kt, 6, 1, 1, 1, Qt.AlignLeft)
self.label_kt_unit.show()
self.gridLayout_groupbox_info.addWidget(self.label_kt_unit, 6, 2, 1, 1, Qt.AlignLeft)
self.checkbox_kt.show()
self.gridLayout_groupbox_info.addWidget(self.checkbox_kt, 6, 3, 1, 1, Qt.AlignLeft)
self.label_sound_attenuation.show()
self.gridLayout_groupbox_info.addWidget(self.label_sound_attenuation, 7, 0, 1, 1, Qt.AlignLeft)
self.lineEdit_sound_attenuation.show()
self.gridLayout_groupbox_info.addWidget(self.lineEdit_sound_attenuation, 7, 1, 1, 1, Qt.AlignLeft)
self.label_sound_attenuation_unit.show()
self.gridLayout_groupbox_info.addWidget(self.label_sound_attenuation_unit, 7, 2, 1, 1, Qt.AlignLeft)
self.label_profiles.show()
self.gridLayout_groupbox_info.addWidget(self.label_profiles, 8, 0, 1, 1, Qt.AlignLeft)
self.label_profiles_per_sec.show()
self.gridLayout_groupbox_info.addWidget(self.label_profiles_per_sec, 9, 0, 1, 1, Qt.AlignLeft)
self.label_cells.show()
self.gridLayout_groupbox_info.addWidget(self.label_cells, 10, 0, 1, 1, Qt.AlignLeft)
self.label_cell_size.show()
self.gridLayout_groupbox_info.addWidget(self.label_cell_size, 11, 0, 1, 1, Qt.AlignLeft)
self.label_pulse_length.show()
self.gridLayout_groupbox_info.addWidget(self.label_pulse_length, 12, 0, 1, 1, Qt.AlignLeft)
self.label_pings_per_sec.show()
self.gridLayout_groupbox_info.addWidget(self.label_pings_per_sec, 13, 0, 1, 1, Qt.AlignLeft)
self.label_pings_per_profile.show()
self.gridLayout_groupbox_info.addWidget(self.label_pings_per_profile, 14, 0, 1, 1, Qt.AlignLeft)
self.label_rx.show()
self.gridLayout_groupbox_info.addWidget(self.label_rx, 15, 0, 1, 1, Qt.AlignLeft)
self.lineEdit_rx.show()
self.gridLayout_groupbox_info.addWidget(self.lineEdit_rx, 15, 1, 1, 1, Qt.AlignLeft)
self.checkbox_rx.show()
self.gridLayout_groupbox_info.addWidget(self.checkbox_rx, 15, 3, 1, 1, Qt.AlignLeft)
self.label_tx.show()
self.gridLayout_groupbox_info.addWidget(self.label_tx, 16, 0, 1, 1, Qt.AlignLeft)
self.lineEdit_tx.show()
self.gridLayout_groupbox_info.addWidget(self.lineEdit_tx, 16, 1, 1, 1, Qt.AlignLeft)
self.checkbox_tx.show()
self.gridLayout_groupbox_info.addWidget(self.checkbox_tx, 16, 3, 1, 1, Qt.AlignLeft)
def groupbox_measurement_information_UBSediFlow(self):
# --- Hide Aquascat information ---
self.label_ABS_name.hide()
self.combobox_ABS_name.hide()
self.label_date_acoustic_file.hide()
self.label_hour_acoustic_file.hide()
self.label_distance_from_ABS_to_free_surface.hide()
self.lineEdit_distance_from_ABS_to_free_surface.hide()
self.label_distance_from_ABS_to_free_surface_unit.hide()
self.pushbutton_distance_from_ABS_to_free_surface.hide()
self.label_temperature.hide()
self.lineEdit_temperature.hide()
self.label_temperature_unit.hide()
self.label_speed_of_sound.hide()
self.lineEdit_speed_of_sound.hide()
self.label_speed_of_sound_unit.hide()
self.label_sound_attenuation.hide()
self.lineEdit_sound_attenuation.hide()
self.label_sound_attenuation_unit.hide()
self.label_freq.hide()
self.combobox_frequency_information.hide()
self.label_profiles.hide()
self.label_profiles_per_sec.hide()
self.label_cells.hide()
self.label_cell_size.hide()
self.label_pulse_length.hide()
self.label_pings_per_sec.hide()
self.label_pings_per_profile.hide()
self.label_kt.hide()
self.lineEdit_kt.hide()
self.label_kt_unit.hide()
self.checkbox_kt.hide()
self.label_rx.hide()
self.lineEdit_rx.hide()
self.checkbox_rx.hide()
self.label_tx.hide()
self.lineEdit_tx.hide()
self.checkbox_tx.hide()
for i in reversed(range(self.gridLayout_groupbox_info.count())):
widgetToRemove = self.gridLayout_groupbox_info.itemAt(i).widget()
# remove it from the layout list
self.gridLayout_groupbox_info.removeWidget(widgetToRemove)
# remove it from the gui
widgetToRemove.setParent(None)
# --- Show UBSediFlow information ---
self.label_ABS_name.show()
self.label_ABS_name.setText("Acoustic Backscatter System: UBSediFlow")
self.gridLayout_groupbox_info.addWidget(self.label_ABS_name, 0, 0, 1, 2, Qt.AlignCenter)
self.combobox_ABS_name.show()
self.gridLayout_groupbox_info.addWidget(self.combobox_ABS_name, 0, 2, 1, 2, Qt.AlignCenter)
self.label_date_acoustic_file.show()
self.gridLayout_groupbox_info.addWidget(self.label_date_acoustic_file, 1, 0, 1, 1, Qt.AlignLeft)
self.label_hour_acoustic_file.show()
self.gridLayout_groupbox_info.addWidget(self.label_hour_acoustic_file, 1, 1, 1, 1, Qt.AlignLeft)
self.label_distance_from_ABS_to_free_surface.show()
self.gridLayout_groupbox_info.addWidget(self.label_distance_from_ABS_to_free_surface, 2, 0, 1, 1, Qt.AlignLeft)
self.lineEdit_distance_from_ABS_to_free_surface.show()
self.gridLayout_groupbox_info.addWidget(self.lineEdit_distance_from_ABS_to_free_surface, 2, 1, 1, 1, Qt.AlignLeft)
self.label_distance_from_ABS_to_free_surface_unit.show()
self.gridLayout_groupbox_info.addWidget(self.label_distance_from_ABS_to_free_surface_unit, 2, 2, 1, 1, Qt.AlignLeft)
self.pushbutton_distance_from_ABS_to_free_surface.show()
self.gridLayout_groupbox_info.addWidget(self.pushbutton_distance_from_ABS_to_free_surface, 2, 3, 1, 1, Qt.AlignLeft)
self.label_temperature.show()
self.gridLayout_groupbox_info.addWidget(self.label_temperature, 3, 0, 1, 1, Qt.AlignLeft)
self.lineEdit_temperature.show()
self.gridLayout_groupbox_info.addWidget(self.lineEdit_temperature, 3, 1, 1, 1, Qt.AlignLeft)
self.label_temperature_unit.show()
self.gridLayout_groupbox_info.addWidget(self.label_temperature_unit, 3, 2, 1, 1, Qt.AlignLeft)
self.label_speed_of_sound.show()
self.gridLayout_groupbox_info.addWidget(self.label_speed_of_sound, 4, 0, 1, 1, Qt.AlignLeft)
self.lineEdit_speed_of_sound.show()
self.gridLayout_groupbox_info.addWidget(self.lineEdit_speed_of_sound, 4, 1, 1, 1, Qt.AlignLeft)
self.label_speed_of_sound_unit.show()
self.gridLayout_groupbox_info.addWidget(self.label_speed_of_sound_unit, 4, 2, 1, 1, Qt.AlignLeft)
self.label_freq.show()
self.gridLayout_groupbox_info.addWidget(self.label_freq, 5, 0, 1, 1, Qt.AlignLeft)
self.combobox_frequency_information.show()
self.gridLayout_groupbox_info.addWidget(self.combobox_frequency_information, 5, 1, 1, 1, Qt.AlignLeft)
self.label_kt.show()
self.gridLayout_groupbox_info.addWidget(self.label_kt, 6, 0, 1, 1, Qt.AlignLeft)
self.lineEdit_kt.show()
self.gridLayout_groupbox_info.addWidget(self.lineEdit_kt, 6, 1, 1, 1, Qt.AlignLeft)
self.label_kt_unit.show()
self.gridLayout_groupbox_info.addWidget(self.label_kt_unit, 6, 2, 1, 1, Qt.AlignLeft)
self.checkbox_kt.show()
self.gridLayout_groupbox_info.addWidget(self.checkbox_kt, 6, 3, 1, 1, Qt.AlignLeft)
self.label_sound_attenuation.show()
self.gridLayout_groupbox_info.addWidget(self.label_sound_attenuation, 7, 0, 1, 1, Qt.AlignLeft)
self.lineEdit_sound_attenuation.show()
self.gridLayout_groupbox_info.addWidget(self.lineEdit_sound_attenuation, 7, 1, 1, 1, Qt.AlignLeft)
self.label_sound_attenuation_unit.show()
self.gridLayout_groupbox_info.addWidget(self.label_sound_attenuation_unit, 7, 2, 1, 1, Qt.AlignLeft)
self.label_profiles.show()
self.gridLayout_groupbox_info.addWidget(self.label_profiles, 8, 0, 1, 1, Qt.AlignLeft)
self.label_profiles_per_sec.show()
self.gridLayout_groupbox_info.addWidget(self.label_profiles_per_sec, 9, 0, 1, 1, Qt.AlignLeft)
self.label_cells.show()
self.gridLayout_groupbox_info.addWidget(self.label_cells, 10, 0, 1, 1, Qt.AlignLeft)
self.label_cell_size.show()
self.gridLayout_groupbox_info.addWidget(self.label_cell_size, 11, 0, 1, 1, Qt.AlignLeft)
self.label_pulse_length.show()
self.gridLayout_groupbox_info.addWidget(self.label_pulse_length, 12, 0, 1, 1, Qt.AlignLeft)
self.label_pings_per_sec.show()
self.gridLayout_groupbox_info.addWidget(self.label_pings_per_sec, 13, 0, 1, 1, Qt.AlignLeft)
self.label_pings_per_profile.show()
self.gridLayout_groupbox_info.addWidget(self.label_pings_per_profile, 14, 0, 1, 1, Qt.AlignLeft)
self.label_rx.show()
self.gridLayout_groupbox_info.addWidget(self.label_rx, 15, 0, 1, 1, Qt.AlignLeft)
self.lineEdit_rx.show()
self.gridLayout_groupbox_info.addWidget(self.lineEdit_rx, 15, 1, 1, 1, Qt.AlignLeft)
self.checkbox_rx.show()
self.gridLayout_groupbox_info.addWidget(self.checkbox_rx, 15, 2, 1, 1, Qt.AlignLeft)
self.label_tx.show()
self.gridLayout_groupbox_info.addWidget(self.label_tx, 16, 0, 1, 1, Qt.AlignLeft)
self.lineEdit_tx.show()
self.gridLayout_groupbox_info.addWidget(self.lineEdit_tx, 16, 1, 1, 1, Qt.AlignLeft)
self.checkbox_tx.show()
self.gridLayout_groupbox_info.addWidget(self.checkbox_tx, 16, 2, 1, 1, Qt.AlignLeft)
def distance_from_ABS_to_free_surface(self):
if self.fileListWidget.count() == 0:
msgBox = QMessageBox()
msgBox.setWindowTitle("Distance ABS - Free surface Error")
msgBox.setIcon(QMessageBox.Warning)
msgBox.setText("Upload data before setting distance ABS - Free surface")
msgBox.setStandardButtons(QMessageBox.Ok)
msgBox.exec()
self.lineEdit_distance_from_ABS_to_free_surface.setText("0.00")
return
def refresh_distance_from_ABS_to_free_surface(self):
self.pushbutton_distance_from_ABS_to_free_surface.blockSignals(True)
data_id = self.fileListWidget.currentRow()
previous = stg.distance_from_ABS_to_free_surface[data_id]
new = (
float(
self.lineEdit_distance_from_ABS_to_free_surface\
.text().replace(",", ".")
)
)
self.lineEdit_distance_from_ABS_to_free_surface.setText(f"{new}")
logger.debug(f"prev: {previous}, new: {new}")
stg.depth[data_id] = stg.depth[data_id] - previous
stg.depth_reshape[data_id] = stg.depth_reshape[data_id] - previous
stg.depth[data_id] = stg.depth[data_id] + new
stg.depth_reshape[data_id] = stg.depth_reshape[data_id] + new
stg.depth_cross_section[data_id] = stg.depth[data_id]
stg.distance_from_ABS_to_free_surface[data_id] = new
self.fill_table()
self.compute_rmin_rmax()
self.compute_time_cross_section()
self.compute_depth_cross_section()
self.set_range_for_spinboxes_bathymetry()
self.compute_BS_cross_section()
self.update_plot_backscattered_acoustic_signal_recording()
self.update_plot_profile()
self.pushbutton_distance_from_ABS_to_free_surface.blockSignals(False)
def setup_temperature_value(self):
self.water_velocity()
self.water_attenuation()
def temperature_value(self):
if findall(r",", self.lineEdit_temperature.text()):
stg.temperature = float(self.lineEdit_temperature.text().replace(',', '.'))
self.lineEdit_temperature.setText(self.lineEdit_temperature.text().replace(',', '.'))
else:
stg.temperature = float(self.lineEdit_temperature.text())
self.lineEdit_temperature.setText(self.lineEdit_temperature.text())
self.water_velocity()
self.water_attenuation()
def water_velocity(self):
"""Computing sond speed from Bilaniuk and Wong 1993"""
temp = float(self.lineEdit_temperature.text())
C = (1.40238744 * 1e3 +
5.03836171 * temp -
5.81172916 * 1e-2 * temp ** 2 +
3.34638117 * 1e-4 * temp ** 3 -
1.48259672 * 1e-6 * temp ** 4 +
3.16585020 * 1e-9 * temp ** 5)
stg.water_velocity = C
self.lineEdit_speed_of_sound.setText(str(round(stg.water_velocity, 2)))
def groupbox_gps_value_toggle(self):
if self.groupbox_gps_value.isChecked() == True:
self.groupbox_gps_file.setChecked(False)
def groupbox_gps_value_size_change(self):
duration = 500
self.animation_groupbox_gps_value = QPropertyAnimation(self.groupbox_gps_value, b"size")
self.animation_groupbox_gps_value.setDuration(duration)
self.animation_groupbox_gps_value.setStartValue(QSize(self.groupbox_gps_value.width(),
self.groupbox_gps_value.height()))
if self.groupbox_gps_value.isChecked():
self.animation_groupbox_gps_value.setEndValue(
QSize(self.groupbox_gps_value.width(),
self.groupbox_gps_value.sizeHint().height()))
else:
self.animation_groupbox_gps_value.setEndValue(QSize(self.groupbox_gps_value.width(), 25))
self.animation_groupbox_gps_value.start()
def groupbox_gps_file_toggle(self):
if self.groupbox_gps_file.isChecked() == True:
self.groupbox_gps_value.setChecked(False)
def groupbox_gps_file_size_change(self):
duration = 500
self.animation_groupbox_gps_file = QPropertyAnimation(self.groupbox_gps_file, b"size")
self.animation_groupbox_gps_file.setDuration(duration)
self.animation_groupbox_gps_file.setStartValue(QSize(self.groupbox_gps_file.width(),
self.groupbox_gps_file.height()))
if self.groupbox_gps_file.isChecked():
self.animation_groupbox_gps_file.setEndValue(
QSize(self.groupbox_gps_file.width(),
self.groupbox_gps_file.sizeHint().height()))
else:
self.animation_groupbox_gps_file.setEndValue(QSize(self.groupbox_gps_file.width(), 25))
self.animation_groupbox_gps_file.start()
# -------- Computing water attenuation coefficient ----------- #
def water_attenuation(self):
"""Computing attenuation from François and Garrison 1982"""
temp = float(self.lineEdit_temperature.text())
file_id = self.fileListWidget.currentRow()
if self.fileListWidget.count() > 0:
stg.water_attenuation[file_id].clear()
for f in stg.freq[file_id]:
if temp > 20:
alpha = ((3.964 * 1e-4 -
1.146 * 1e-5 * temp +
1.45 * 1e-7 * temp ** 2 -
6.5 * 1e-10 * temp ** 3) *
1e-3 * (np.log(10) / 20) * (f * 1e-3) ** 2)
else:
alpha = ((4.937 * 1e-4 -
2.59 * 1e-5 * temp +
9.11 * 1e-7 * temp ** 2 -
1.5 * 1e-8 * temp ** 3) *
1e-3 * (np.log(10) / 20) * (f * 1e-3) ** 2)
stg.water_attenuation[file_id].append(alpha)
self.lineEdit_sound_attenuation.setText(
str("%.6f" % stg.water_attenuation[file_id][
self.combobox_frequency_information.currentIndex()]))
def open_dialog_box(self):
abs_params = [
(None, None),
("AQUAscat file", "Aquascat file (*.aqa)"),
("UBSediFlow file", "UBSediFlow file (*.udt)"),
]
system = self.combobox_ABS_system_choice.currentIndex()
if system == 0:
msgBox = QMessageBox()
msgBox.setWindowTitle("Download Error")
msgBox.setIcon(QMessageBox.Warning)
msgBox.setText("Choose ABS system before download acoustic files")
msgBox.setStandardButtons(QMessageBox.Ok)
msgBox.exec()
else:
abs_name, abs_file_type = abs_params[system]
filenames, _ = QFileDialog.getOpenFileNames(
self, abs_name,
[
stg.path_BS_raw_data[-1]
if self.fileListWidget.count() > 0
else ""
][0],
abs_file_type,
options=QFileDialog.DontUseNativeDialog
)
if len(filenames) == 0:
return
for n in filenames:
stg.path_BS_raw_data.append(os.path.dirname(n))
stg.filename_BS_raw_data.append(os.path.basename(n))
stg.data_preprocessed.append(os.path.basename(n))
self.open_acoustic_data()
def open_acoustic_data(self):
# --- Fill lineEdit with path and file names + load acoustic data ---
# --- fill date, hour and measurements information + fill frequency combobox for bottom detection ---
system = self.combobox_ABS_system_choice.currentIndex()
if system != 0:
try:
self.load_BS_acoustic_raw_data()
except ValueError as e:
msgBox = QMessageBox()
msgBox.setWindowTitle("Download Error")
msgBox.setIcon(QMessageBox.Warning)
msgBox.setText("Please select a file")
msgBox.setStandardButtons(QMessageBox.Ok)
msgBox.exec()
else:
self.fileListWidget.blockSignals(True)
if self.fileListWidget.count() == 0:
for p, f in zip(stg.path_BS_raw_data,
stg.filename_BS_raw_data):
self.fileListWidget.addFilenames([f])
self.fileListWidget.setToolTip(p)
else:
for k in range(self.fileListWidget.count(),
len(stg.filename_BS_raw_data),
1):
self.fileListWidget.addFilenames(
[stg.filename_BS_raw_data[k]]
)
self.fileListWidget.setToolTip(
stg.path_BS_raw_data[k]
)
self.fill_measurements_information_groupbox()
self.fill_table()
self.plot_backscattered_acoustic_signal_recording()
self.plot_profile()
self.update_frequency_combobox()
self.water_attenuation()
self.compute_tmin_tmax()
self.compute_rmin_rmax()
self.set_range_for_spinboxes_bathymetry()
stg.acoustic_data = list(
range(
self.fileListWidget.count()
)
)
self.fileListWidget.blockSignals(False)
def rename_file_in_ListWidget(self, event):
if event.type() == QEvent.ContextMenu:
menu = QMenu()
menu.addAction('Rename')
def remove_file_from_ListWidget(self):
if self.fileListWidget.count() <= 0:
return
self.fileListWidget.blockSignals(True)
# --- Clear files included in list Widget ---
current_row = self.fileListWidget.currentRow()
if current_row >= 0:
current_item = self.fileListWidget.takeItem(current_row)
del current_item
# --- Clear variables ---
list_to_pop1 = [
stg.acoustic_data, stg.date, stg.hour,
stg.freq, stg.freq_text,
stg.nb_profiles, stg.nb_profiles_per_sec,
stg.nb_cells, stg.cell_size,
stg.pulse_length, stg.nb_pings_per_sec,
stg.nb_pings_averaged_per_profile,
stg.kt_read, stg.kt_corrected, stg.gain_rx, stg.gain_tx,
stg.filename_BS_raw_data, stg.path_BS_raw_data,
stg.BS_raw_data, stg.time, stg.depth,
stg.BS_raw_data_reshape, stg.time_reshape, stg.depth_reshape
]
for p in list_to_pop1:
if isinstance(p, list):
p.pop(current_row)
if stg.BS_cross_section:
list_to_pop2 = [
stg.rmin, stg.rmax, stg.tmin, stg.tmax,
stg.time_cross_section, stg.depth_cross_section,
stg.BS_cross_section
]
for k in list_to_pop2:
k.pop(current_row)
if stg.BS_stream_bed:
list_to_pop3 = [
stg.BS_stream_bed, stg.depth_bottom,
stg.val_bottom, stg.ind_bottom,
stg.freq_bottom_detection
]
for s in list_to_pop3:
s.pop(current_row)
if self.fileListWidget.count() == 0:
self.clear_files_from_ListWidget_reset()
self.fileListWidget.blockSignals(False)
def clear_files_from_ListWidget(self):
self.fileListWidget.blockSignals(True)
self.clear_files_data()
self.clear_files_from_ListWidget_reset()
self.fileListWidget.blockSignals(False)
def clear_files_from_ListWidget_reset(self):
self.fileListWidget.clear()
# self.fileListWidget.takeItem(0)
if self.fileListWidget.count() == 0:
# --- Clear measurmeents information ---
self.label_date_acoustic_file.clear()
self.label_date_acoustic_file.setText("Date: ")
self.label_hour_acoustic_file.clear()
self.label_hour_acoustic_file.setText("Hour: ")
self.lineEdit_sound_attenuation.setText("0.00")
self.combobox_frequency_information.clear()
self.label_profiles_value.clear()
self.label_profiles_per_sec_value.clear()
self.label_cells_value.clear()
self.label_cell_size_value.clear()
self.label_pulse_length_value.clear()
self.label_pings_per_sec_value.clear()
self.label_pings_per_profile_value.clear()
self.lineEdit_kt.setText("0.00")
self.lineEdit_rx.setText("0.00")
self.lineEdit_tx.setText("0.00")
# --- Clear display options ---
self.label_time_min.setText("0.00")
self.lineEdit_time_min_limits.setText("0.00")
self.lineEdit_time_max_limits.setText("0.00")
self.label_time_max.setText("0.00")
self.label_depth_min.setText("0.00")
self.lineEdit_depth_min_limits.setText("0.00")
self.lineEdit_depth_max_limits.setText("0.00")
self.label_depth_max.setText("0.00")
self.label_distance_from_bank_min.setText("0.00")
self.lineEdit_distance_from_bank_min_limits.setText("0.00")
self.lineEdit_distance_from_bank_max_limits.setText("0.00")
self.label_distance_from_bank_max.setText("0.00")
self.combobox_frequency_bathymetry.clear()
self.lineEdit_depth_min_bathy.setText("0.00")
self.lineEdit_depth_max_bathy.setText("0.00")
self.lineEdit_next_cell_bathy.setText("0.00")
# --- Clear table of values ---
self.tableView.reset()
data = pd.DataFrame(np.zeros((10, 10)))
self.tableModel = TableModel(data)
self.tableView.setModel(self.tableModel)
# --- Clear figure : 2D plot of the acoustic recording ---
self.verticalLayout_groupbox_transect_2Dplot_raw_BS_data.removeWidget(self.scroll_BS)
self.verticalLayout_groupbox_transect_2Dplot_raw_BS_data.removeWidget(self.toolbar_BS)
self.canvas_BS = FigureCanvas()
self.toolbar_BS = NavigationToolBar(self.canvas_BS, self)
self.scroll_BS.setWidget(self.canvas_BS)
self.verticalLayout_groupbox_transect_2Dplot_raw_BS_data.addWidget(self.toolbar_BS)
self.verticalLayout_groupbox_transect_2Dplot_raw_BS_data.addWidget(self.scroll_BS)
# --- Clear figure : profile ---
self.combobox_frequency_profile.clear()
self.verticalLayout_groupbox_plot_profile.removeWidget(self.canvas_plot_profile)
self.verticalLayout_groupbox_plot_profile.removeWidget(self.toolbar_profile)
self.canvas_plot_profile = FigureCanvas()
self.toolbar_profile = NavigationToolBar(self.canvas_plot_profile, self)
self.verticalLayout_groupbox_plot_profile.addWidget(self.toolbar_profile)
self.verticalLayout_groupbox_plot_profile.addWidget(self.canvas_plot_profile)
self.slider.setValue(0)
self.slider.setMaximum(10)
def clear_files_data(self):
list_to_clear = [
stg.acoustic_data, stg.date, stg.hour,
stg.freq, stg.freq_text,
stg.nb_profiles, stg.nb_profiles_per_sec,
stg.nb_cells, stg.cell_size,
stg.pulse_length, stg.nb_pings_per_sec,
stg.nb_pings_averaged_per_profile,
stg.kt_read, stg.kt_corrected, stg.gain_rx, stg.gain_tx,
stg.filename_BS_raw_data, stg.path_BS_raw_data,
stg.BS_raw_data, stg.time, stg.depth,
stg.BS_raw_data_reshape, stg.time_reshape, stg.depth_reshape,
stg.rmin, stg.rmax, stg.tmin, stg.tmax,
stg.time_cross_section, stg.depth_cross_section,
stg.BS_cross_section, stg.BS_stream_bed
]
for k in list_to_clear:
if isinstance(k, list):
k.clear()
def load_BS_acoustic_raw_data(self):
if self.fileListWidget.count() == 0:
for p, f in zip(stg.path_BS_raw_data,
stg.filename_BS_raw_data):
if self.combobox_ABS_system_choice.currentIndex() == 1:
acoustic_data = AcousticDataLoader(
os.path.join(p, f)
)
elif self.combobox_ABS_system_choice.currentIndex() == 2:
acoustic_data = AcousticDataLoaderUBSediFlow(
os.path.join(p, f)
)
self.initiate_setting_parameters(
acoustic_data=acoustic_data
)
else:
for k in range(self.fileListWidget.count(),
len(stg.filename_BS_raw_data), 1):
if self.combobox_ABS_system_choice.currentIndex() == 1:
acoustic_data = AcousticDataLoader(
os.path.join(
stg.path_BS_raw_data[k],
stg.filename_BS_raw_data[k]
)
)
elif self.combobox_ABS_system_choice.currentIndex() == 2:
acoustic_data = AcousticDataLoaderUBSediFlow(
os.path.join(
stg.path_BS_raw_data[k],
stg.filename_BS_raw_data[k]
)
)
self.initiate_setting_parameters(
acoustic_data=acoustic_data
)
def initiate_setting_parameters(self, acoustic_data):
# --- The acoustic variables are field with loaded data ---
stg.ABS_name.append(self.combobox_ABS_system_choice.currentText())
stg.BS_raw_data.append(acoustic_data._BS_raw_data)
stg.BS_raw_data_reshape.append(acoustic_data.reshape_BS_raw_data())
stg.depth.append(acoustic_data._r)
stg.depth_2D.append(np.array([]))
stg.depth_reshape.append(acoustic_data.reshape_r())
stg.time.append(acoustic_data._time)
stg.time_reshape.append(acoustic_data.reshape_t())
stg.freq.append(acoustic_data._freq)
stg.freq_text.append(acoustic_data._freq_text)
stg.date.append(acoustic_data._date)
stg.hour.append(acoustic_data._hour)
stg.distance_from_ABS_to_free_surface.append(0.00)
stg.nb_profiles.append(acoustic_data._nb_profiles)
stg.nb_profiles_per_sec.append(acoustic_data._nb_profiles_per_sec)
stg.nb_cells.append(acoustic_data._nb_cells)
stg.cell_size.append(acoustic_data._cell_size)
stg.pulse_length.append(acoustic_data._cell_size)
stg.nb_pings_per_sec.append(acoustic_data._nb_pings_per_sec)
stg.nb_pings_averaged_per_profile.append(acoustic_data._nb_pings_averaged_per_profile)
if self.combobox_ABS_name.currentIndex() == 1:
stg.kt_read = acoustic_data._kt
else:
stg.kt_read = [0*i for i in range(acoustic_data._freq.shape[0])]
stg.gain_rx.append(acoustic_data._gain_rx)
stg.gain_tx.append(acoustic_data._gain_tx)
stg.water_attenuation.append([])
self.initiate_setting_parameters_new_others()
def initiate_setting_parameters_new_others(self):
stg.BS_cross_section.append(np.array([]))
stg.depth_cross_section.append(np.array([]))
stg.time_cross_section.append(np.array([]))
stg.tmin.append((0, 0))
stg.tmax.append((0, 0))
stg.rmin.append((0, 0))
stg.rmax.append((0, 0))
stg.BS_stream_bed.append(np.array([]))
stg.depth_bottom.append(np.array([]))
stg.val_bottom.append([])
stg.ind_bottom.append([])
stg.freq_bottom_detection.append((0, 0))
stg.depth_bottom_detection_min.append(0.0)
stg.depth_bottom_detection_max.append(0.0)
stg.depth_bottom_detection_interval.append(0.0)
stg.BS_mean.append(np.array([]))
stg.BS_noise_raw_data.append(np.array([]))
stg.BS_noise_averaged_data.append(np.array([]))
stg.SNR_raw_data.append(np.array([]))
stg.SNR_cross_section.append(np.array([]))
stg.SNR_stream_bed.append(np.array([]))
stg.time_noise.append(np.array([]))
stg.depth_noise.append(np.array([]))
stg.noise_method.append(0)
stg.noise_value.append(0)
stg.SNR_filter_value.append(0)
stg.Nb_cells_to_average_BS_signal.append(0)
stg.filename_BS_noise_data.append("")
stg.path_BS_noise_data.append("")
stg.BS_raw_data_pre_process_SNR.append(np.array([]))
stg.BS_raw_data_pre_process_average.append(np.array([]))
stg.BS_cross_section_pre_process_SNR.append(np.array([]))
stg.BS_cross_section_pre_process_average.append(np.array([]))
stg.BS_stream_bed_pre_process_SNR.append(np.array([]))
stg.BS_stream_bed_pre_process_average.append(np.array([]))
stg.FCB = np.array([])
stg.depth_real = np.array([])
stg.lin_reg = []
stg.kt2D.append(np.array([]))
stg.kt3D.append(np.array([]))
stg.J_cross_section.append([np.array([]), np.array([])])
stg.VBI_cross_section.append(np.array([]))
stg.SSC_fine.append(np.array([]))
stg.SSC_sand.append(np.array([]))
def fill_measurements_information_groupbox(self):
if self.fileListWidget.currentRow() == -1:
return
self.fill_measurements_information_groupbox_datetime()
self.fill_measurements_information_groupbox_frequency()
self.fill_measurements_information_groupbox_cells()
self.fill_measurements_information_groupbox_kt()
self.water_velocity()
self.water_attenuation()
def fill_measurements_information_groupbox_datetime(self):
file_id = self.fileListWidget.currentRow()
logger.debug(f"file_id: {file_id}")
logger.debug(f"stg.date: {stg.date}")
self.label_date_acoustic_file.clear()
self.label_date_acoustic_file.setText(
"Date: " + str(stg.date[file_id])
)
self.gridLayout_groupbox_info.addWidget(
self.label_date_acoustic_file,
1, 0, 1, 1,
Qt.AlignLeft
)
self.label_hour_acoustic_file.clear()
self.label_hour_acoustic_file.setText(
"Hour: " + str(stg.hour[file_id])
)
self.gridLayout_groupbox_info.addWidget(
self.label_hour_acoustic_file,
1, 1, 1, 1,
Qt.AlignLeft
)
def fill_measurements_information_groupbox_frequency(self):
file_id = self.fileListWidget.currentRow()
freq_id = self.combobox_frequency_information.currentIndex()
self.combobox_frequency_information.clear()
self.combobox_frequency_information.addItems(
stg.freq_text[file_id]
)
self.combobox_frequency_information\
.currentIndexChanged\
.connect(self.combobox_frequency_information_update)
self.lineEdit_distance_from_ABS_to_free_surface.setText(
str(stg.distance_from_ABS_to_free_surface[file_id])
)
logger.debug(f"Set temperature = {stg.temperature}")
self.lineEdit_temperature.setText(str(stg.temperature))
self.label_profiles_value.setText(
str(stg.nb_profiles[file_id][freq_id])
)
self.gridLayout_groupbox_info.addWidget(
self.label_profiles_value,
8, 1, 1, 1,
Qt.AlignLeft
)
self.label_profiles_per_sec_value.setText(
str(stg.nb_profiles_per_sec[file_id][freq_id]) + " Hz"
)
self.gridLayout_groupbox_info.addWidget(
self.label_profiles_per_sec_value,
9, 1, 1, 1,
Qt.AlignLeft
)
def fill_measurements_information_groupbox_cells(self):
file_id = self.fileListWidget.currentRow()
freq_id = self.combobox_frequency_information.currentIndex()
self.label_cells_value.setText(
str(stg.nb_cells[file_id][freq_id])
)
self.gridLayout_groupbox_info.addWidget(
self.label_cells_value,
10, 1, 1, 1,
Qt.AlignLeft
)
self.label_cell_size_value.setText(
str(100*round(stg.cell_size[file_id][freq_id], 3)) + " cm"
)
self.gridLayout_groupbox_info.addWidget(
self.label_cell_size_value,
11, 1, 1, 1,
Qt.AlignLeft
)
self.label_pulse_length_value.setText(
str(round(stg.pulse_length[file_id][freq_id], 6)) + " sec"
)
self.gridLayout_groupbox_info.addWidget(
self.label_pulse_length_value,
12, 1, 1, 1,
Qt.AlignLeft
)
self.label_pings_per_sec_value.setText(
str(stg.nb_pings_per_sec[file_id][freq_id]) + " Hz"
)
self.gridLayout_groupbox_info.addWidget(
self.label_pings_per_sec_value,
13, 1, 1, 1,
Qt.AlignLeft
)
self.label_pings_per_profile_value.setText(
str(stg.nb_pings_averaged_per_profile[file_id][freq_id])
)
self.gridLayout_groupbox_info.addWidget(
self.label_pings_per_profile_value,
14, 1, 1, 1,
Qt.AlignLeft
)
def fill_measurements_information_groupbox_kt(self):
file_id = self.fileListWidget.currentRow()
freq_id = self.combobox_frequency_information.currentIndex()
abs_id = self.combobox_ABS_name.currentText()
data_ABS = self.calib_kt.data_ABS[abs_id]["Frequency"].values
stg.kt_corrected.clear()
for f in range(stg.freq[file_id].shape[0]):
freq_array = np.array(
[
stg.freq[file_id][f] - freq
for freq in data_ABS
]
)
stg.kt_corrected.append(
self.calib_kt.data_ABS[abs_id].iloc[
np.where(
np.abs(
freq_array
) == np.min(
np.abs(
freq_array
)
)
)[0][0]
][1]
)
self.lineEdit_kt.setText(
str("%.4f" % stg.kt_corrected[freq_id])
)
self.lineEdit_kt.setEnabled(True)
self.lineEdit_kt.returnPressed.connect(self.kt_value)
self.lineEdit_rx.setText(
str("%.2f" % stg.gain_rx[file_id][freq_id])
)
self.lineEdit_rx.setEnabled(False)
self.checkbox_rx.stateChanged.connect(
self.activate_unactivate_spinbox_rx
)
self.lineEdit_rx.returnPressed.connect(self.gain_rx_value)
self.lineEdit_tx.setText(str("%.2f" % stg.gain_tx[file_id][freq_id]))
self.lineEdit_tx.setEnabled(False)
self.checkbox_tx.stateChanged.connect(
self.activate_unactivate_spinbox_tx
)
self.lineEdit_tx.returnPressed.connect(self.gain_tx_value)
def combobox_frequency_information_update(self):
if self.fileListWidget.count() <= 0:
return
file_id = self.fileListWidget.currentRow()
freq_id = self.combobox_frequency_information.currentIndex()
if stg.water_attenuation[file_id]:
self.lineEdit_sound_attenuation.setText(
str(
"%.6f"
% stg.water_attenuation[file_id][freq_id]
)
)
self.label_profiles_value.clear()
self.gridLayout_groupbox_info.removeWidget(
self.label_profiles_value
)
self.label_profiles_value.setText(
str(
stg.nb_profiles[file_id][freq_id]
)
)
self.gridLayout_groupbox_info.addWidget(
self.label_profiles_value,
8, 1, 1, 1, Qt.AlignLeft
)
self.label_profiles_per_sec_value.clear()
self.label_profiles_per_sec_value.setText(
str(
stg.nb_profiles_per_sec[file_id][freq_id]
) + " Hz"
)
self.gridLayout_groupbox_info.addWidget(
self.label_profiles_per_sec_value,
9, 1, 1, 1, Qt.AlignLeft
)
self.label_cells_value.clear()
self.label_cells_value.setText(
str(
stg.nb_cells[file_id][freq_id]
)
)
self.gridLayout_groupbox_info.addWidget(
self.label_cells_value,
10, 1, 1, 1, Qt.AlignLeft
)
self.label_cell_size_value.clear()
self.gridLayout_groupbox_info.removeWidget(self.label_cell_size_value)
self.label_cell_size_value.setText(
str(
100 * round(stg.cell_size[file_id][freq_id], 3)
) + " cm"
)
self.gridLayout_groupbox_info.addWidget(
self.label_cell_size_value,
11, 1, 1, 1, Qt.AlignLeft
)
self.label_pulse_length_value.clear()
self.label_pulse_length_value.setText(
str(
round(stg.pulse_length[file_id][freq_id], 6)
) + " sec"
)
self.gridLayout_groupbox_info.addWidget(
self.label_pulse_length_value,
12, 1, 1, 1, Qt.AlignLeft
)
self.label_pings_per_sec_value.clear()
self.label_pings_per_sec_value.setText(
str(
stg.nb_pings_per_sec[file_id][freq_id]
) + " Hz"
)
self.gridLayout_groupbox_info.addWidget(
self.label_pings_per_sec_value,
13, 1, 1, 1, Qt.AlignLeft
)
self.label_pings_per_profile_value.clear()
self.label_pings_per_profile_value.setText(
str(stg.nb_pings_averaged_per_profile[file_id][freq_id])
)
self.gridLayout_groupbox_info.addWidget(
self.label_pings_per_profile_value,
14, 1, 1, 1, Qt.AlignLeft
)
if self.checkbox_kt.isChecked() and len(stg.kt_corrected) > freq_id:
if self.combobox_frequency_information.count() > 0:
self.lineEdit_kt.setText(
str("%.4f" % stg.kt_corrected[freq_id])
)
else:
self.lineEdit_kt.setText(str("%.4f" % stg.kt_read[freq_id]))
self.lineEdit_rx.setText(
str(stg.gain_rx[file_id][freq_id])
)
self.lineEdit_tx.setText(str(stg.gain_tx[file_id][freq_id]))
def activate_unactivate_spinbox_kt(self):
freq_id = self.combobox_frequency_information.currentIndex()
if self.checkbox_kt.isChecked():
self.lineEdit_kt.setEnabled(True)
if stg.kt_corrected:
self.lineEdit_kt.setText(str("%.4f" % stg.kt_corrected[freq_id]))
else:
self.lineEdit_kt.setDisabled(True)
if stg.kt_read:
self.lineEdit_kt.setText(str("%.4f" % stg.kt_read[freq_id]))
def activate_unactivate_spinbox_rx(self):
if self.checkbox_rx.isChecked():
self.lineEdit_rx.setEnabled(True)
else:
self.lineEdit_rx.setDisabled(True)
def activate_unactivate_spinbox_tx(self):
if self.checkbox_tx.isChecked():
self.lineEdit_tx.setEnabled(True)
else:
self.lineEdit_tx.setDisabled(True)
def kt_value(self):
if self.fileListWidget.count() <= 0:
return
if not self.checkbox_kt.isChecked():
return
freq_id = self.combobox_frequency_information.currentIndex()
if findall(r",", self.lineEdit_kt.text()):
stg.kt_corrected[freq_id] = (
float(self.lineEdit_kt.text().replace(',', '.'))
)
self.lineEdit_kt.setText(
"%.4f" % float(
self.lineEdit_kt.text().replace(',', '.')
)
)
else:
stg.kt_corrected[freq_id] = (
float(self.lineEdit_kt.text())
)
self.lineEdit_kt.setText("%.4f" % float(self.lineEdit_kt.text()))
def gain_rx_value(self):
freq_id = self.combobox_frequency_information.currentIndex()
if self.fileListWidget.count() > 0:
stg.gain_rx[self.fileListWidget.currentRow()][freq_id] = (
float(self.lineEdit_rx.text())
)
def gain_tx_value(self):
freq_id = self.combobox_frequency_information.currentIndex()
if self.fileListWidget.count() > 0:
stg.gain_tx[self.fileListWidget.currentRow()][freq_id] = (
float(self.lineEdit_tx.text())
)
def fill_table(self):
# if self.fileListWidget.currentRow() != -1:
if self.fileListWidget.selectedItems() != []:
file_id = self.fileListWidget.currentRow()
header_list = []
header_list.clear()
table_data = np.array([[]])
for freq_ind, freq_value in enumerate(stg.freq_text[0]):
header_list.append("Time - " + freq_value)
header_list.append("Depth - " + freq_value)
header_list.append("BS - " + freq_value)
if freq_ind == 0:
table_data = np.vstack(
(
np.vstack(
(
stg.time_reshape[file_id][:, freq_ind],
stg.depth_reshape[file_id][:, freq_ind]
)
),
stg.BS_raw_data_reshape[file_id][:, freq_ind]
)
)
else:
table_data = np.vstack((
table_data,
np.vstack(
(
np.vstack(
(
stg.time_reshape[file_id][:, freq_ind],
stg.depth_reshape[file_id][:, freq_ind]
)
),
stg.BS_raw_data_reshape[file_id][:, freq_ind]
)
)
))
stg.DataFrame_acoustic = pd.DataFrame(None)
stg.DataFrame_acoustic = pd.DataFrame(
data=table_data.transpose(), columns=header_list
)
self.tableModel = TableModel(stg.DataFrame_acoustic)
self.tableView.setModel(self.tableModel)
def transect_xaxis_choice(self):
if self.groupbox_xaxis_time.isChecked() == True:
self.groupbox_xaxis_space.setChecked(False)
elif self.groupbox_xaxis_space.isChecked() == True:
self.groupbox_xaxis_time.setChecked(False)
def compute_tmin_tmax(self):
''' tmin and tmax are filled with min and max of time when data are uploaded and
double slider of time are updated with these values '''
if self.fileListWidget.currentRow() == -1:
return
data_id = self.fileListWidget.currentRow()
tmin_indice = np.where(
np.abs(
stg.time[data_id][0, :] - np.nanmin(stg.time[data_id][0, :])
) == np.nanmin(
np.abs(
stg.time[data_id][0, :]
- np.nanmin(stg.time[data_id][0, :])
)
)
)[0][0]
tmin_value = np.round(
np.nanmin(stg.time[data_id][0, :]), 2
)
stg.tmin[data_id] = (tmin_indice, tmin_value)
tmax_indice = np.where(
np.abs(
stg.time[data_id][0, :] - np.nanmax(stg.time[data_id][0, :])
) == np.nanmin(
np.abs(
stg.time[data_id][0, :]
- np.nanmax(stg.time[data_id][0, :])
)
)
)[0][0]
tmax_value = np.round(np.nanmax(stg.time[data_id][0, :]), 2)
stg.tmax[data_id] = (tmax_indice + 1, tmax_value)
self.set_range_for_time_boundaries_option()
def set_range_for_time_boundaries_option(self):
data_id = self.fileListWidget.currentRow()
self.label_time_min.clear()
self.label_time_min.setText(
f"{stg.time[data_id][0, 0]:.1f}"
)
self.label_time_max.clear()
self.label_time_max.setText(
f"{stg.time[data_id][0, -1]:.1f}"
)
if stg.time_cross_section[data_id].shape != (0,):
self.lineEdit_time_min_limits.setText(
f"{stg.time_cross_section[data_id][0, 0]:.1f}"
)
self.lineEdit_time_max_limits.setText(
f"{stg.time_cross_section[data_id][0, -1]:.1f}"
)
else:
self.lineEdit_time_min_limits.setText(
f"{stg.time[data_id][0, 0]:.1f}"
)
self.lineEdit_time_max_limits.setText(
f"{stg.time[data_id][0, -1]:.1f}"
)
def compute_time_cross_section(self):
''' tmin and tmax are updated with double slider of time '''
data_id = max(0, self.fileListWidget.currentRow())
time_min = float(self.lineEdit_time_min_limits.text().replace(",", "."))
time_max = float(self.lineEdit_time_max_limits.text().replace(",", "."))
stg.tmin[data_id] = ((
np.where(
np.abs(
np.round(
stg.time[data_id][0, :], 2
) - time_min
) == np.nanmin(
np.abs(
np.round(
stg.time[data_id][0, :], 2
) - time_min
)
)
)[0][0],
time_min
))
stg.tmax[data_id] = ((
np.where(
np.abs(
np.round(
stg.time[data_id][0, :], 2)
- time_max
) == np.nanmin(
np.abs(
np.round(
stg.time[data_id][0, :],2)
- time_max
)
)
)[0][0] + 1,
time_max
))
stg.time_cross_section[data_id] = (
stg.time[data_id][
:, stg.tmin[data_id][0]: stg.tmax[data_id][0]
]
)
def compute_rmin_rmax(self):
''' rmin and rmax are filled with min and max of depth when data are uploaded and
double slider of depth are updated with these values '''
if self.fileListWidget.currentRow() == -1:
return
data_id = self.fileListWidget.currentRow()
# --- rmim / rmax ---
rmin_indice = np.where(
np.abs(
stg.depth[data_id][0, :] - np.nanmin(stg.depth[data_id][0, :])
) == np.nanmin(
np.abs(
stg.depth[data_id][0, :]
- np.nanmin(stg.depth[data_id][0, :])
)
)
)[0][0]
rmin_value = np.round(np.nanmin(stg.depth[data_id][0, :]), 2)
stg.rmin[data_id] = (rmin_indice, rmin_value)
rmax_indice = np.where(
np.abs(
stg.depth[data_id][0, :] - np.nanmax(stg.depth[data_id][0, :])
) == np.nanmin(
np.abs(
stg.depth[data_id][0, :]
- np.nanmax(stg.depth[data_id][0, :])
)
)
)[0][0]
rmax_value = np.round(np.nanmax(stg.depth[data_id][0, :]), 2)
stg.rmax[data_id] = (rmax_indice + 1, rmax_value)
self.set_range_for_depth_boundaries_option()
def set_range_for_depth_boundaries_option(self):
data_id = self.fileListWidget.currentRow()
self.label_depth_min.clear()
self.label_depth_min.setText("-" + str("%.5s" % stg.depth[data_id][0, -1]))
self.label_depth_max.clear()
self.label_depth_max.setText("-" + str("%.5s" % stg.depth[data_id][0, 0]))
if stg.depth_cross_section[data_id].shape != (0,):
self.lineEdit_depth_min_limits.setText(
"-" + str("%.5s" % stg.depth_cross_section[data_id][0, -1])
)
self.lineEdit_depth_max_limits.setText(
"-" + str("%.5s" % stg.depth_cross_section[data_id][0, 0])
)
else:
self.lineEdit_depth_min_limits.setText(
"-" + str("%.5s" % stg.depth[data_id][0, -1])
)
self.lineEdit_depth_max_limits.setText(
"-" + str("%.5s" % stg.depth[data_id][0, 0])
)
def compute_depth_cross_section(self):
''' rmin and rmax are updated with double slider of depth '''
data_id = self.fileListWidget.currentRow()
round_depth = np.round(stg.depth[data_id][0, :], 2)
depth_max = float(
"".join(
findall(
"[.0-9]",
self.lineEdit_depth_max_limits.text()
)
)
)
depth_min = float(
"".join(
findall(
"[.0-9]",
self.lineEdit_depth_min_limits.text()
)
)
)
diff_max = np.abs(round_depth - depth_max)
diff_min = np.abs(round_depth - depth_min)
stg.rmin[data_id] = ((
np.where(diff_max == np.nanmin(diff_max))[0][0]+1,
depth_max
))
stg.rmax[data_id] = ((
np.where(diff_min == np.nanmin(diff_min))[0][0],
depth_min
))
stg.depth_cross_section[data_id] = (
stg.depth[data_id][
:, stg.rmin[data_id][0]:stg.rmax[data_id][0]
]
)
def compute_BS_cross_section(self):
if self.fileListWidget.currentRow() == -1:
return
data_id = self.fileListWidget.currentRow()
self.compute_depth_cross_section()
self.compute_time_cross_section()
stg.BS_cross_section[data_id] = (
stg.BS_raw_data[data_id][
:,
stg.rmin[data_id][0]:stg.rmax[data_id][0],
stg.tmin[data_id][0]:stg.tmax[data_id][0]
]
)
def update_frequency_combobox(self):
data_id = self.fileListWidget.currentRow()
if data_id == -1:
return
self.combobox_frequency_bathymetry.clear()
self.combobox_frequency_bathymetry.addItems(
[f for f in stg.freq_text[data_id]]
)
self.combobox_frequency_profile.clear()
self.combobox_frequency_profile.addItems(
[f for f in stg.freq_text[data_id]]
)
def set_range_for_doubleRangeSlider_intg_area(self):
if self.fileListWidget.currentRow() == -1:
return
data_id = self.fileListWidget.currentRow()
if stg.depth_cross_section[data_id].shape == (0,):
self.doubleRangeSlider_intg_area.setRange(
min=-stg.depth[data_id][0, -1],
max=-stg.depth[data_id][0, 0]
)
self.doubleRangeSlider_intg_area.setValue(
value=(
-stg.depth[data_id][0, -1],
-stg.depth[data_id][0, 0]
)
)
else:
self.doubleRangeSlider_intg_area.setRange(
min=-stg.depth_cross_section[data_id][0, -1],
max=-stg.depth_cross_section[data_id][0, 0]
)
self.doubleRangeSlider_intg_area.setValue(
value=(
-stg.depth_cross_section[data_id][0, -1],
-stg.depth_cross_section[data_id][0, 0]
)
)
def set_range_for_spinboxes_bathymetry(self):
if self.fileListWidget.currentRow() == -1:
return
data_id = self.fileListWidget.currentRow()
if stg.depth_cross_section[data_id].shape != (0,):
self.lineEdit_depth_min_bathy.setText(
"-" + str("%.5s" % stg.depth_cross_section[data_id][0, -1])
)
self.lineEdit_depth_max_bathy.setText(
"-" + str("%.5s" % stg.depth_cross_section[data_id][0, 0])
)
else:
self.lineEdit_depth_min_bathy.setText(
"-" + str("%.5s" % stg.depth[data_id][0, -1])
)
self.lineEdit_depth_max_bathy.setText(
"-" + str("%.5s" % stg.depth[data_id][0, 0])
)
def plot_backscattered_acoustic_signal_recording(self):
if self.fileListWidget.count() <= 0:
return
layout = self.verticalLayout_groupbox_transect_2Dplot_raw_BS_data
file_id = self.fileListWidget.currentRow()
freq_id = self.combobox_frequency_profile.currentIndex()
layout.removeWidget(self.toolbar_BS)
layout.removeWidget(self.scroll_BS)
if self.fig_BS is not None:
self.fig_BS.clear()
self.fig_BS, self.axis_BS = plt.subplots(
nrows=stg.freq[file_id].shape[0],
ncols=1, sharex=False, sharey=False,
layout="constrained"
)
self.canvas_BS = FigureCanvas(self.fig_BS)
self.toolbar_BS = NavigationToolBar(self.canvas_BS, self)
self.scroll_BS.setWidget(self.canvas_BS)
layout.addWidget(self.toolbar_BS)
layout.addWidget(self.scroll_BS)
for f, _ in enumerate(stg.freq[file_id]):
val_min = np.nanmin(stg.BS_raw_data[file_id][f, :, :])
val_max = np.nanmax(stg.BS_raw_data[file_id][f, :, :])
if val_min == 0:
val_min = 1e-5
if self.combobox_ABS_system_choice.currentIndex() == 1:
pcm = self.axis_BS[f].pcolormesh(
stg.time[file_id][f, :],
-stg.depth[file_id][f, :],
stg.BS_raw_data[file_id][f, :, :],
cmap='viridis',
norm=LogNorm(vmin=val_min, vmax=val_max)
)
elif self.combobox_ABS_system_choice.currentIndex() == 2:
pcm = self.axis_BS[f].pcolormesh(
stg.time[file_id][f, :],
-stg.depth[file_id][f, :],
np.log(stg.BS_raw_data[file_id][f, :, :]),
cmap='Blues'
)
self.axis_BS[f].text(
1, .70, stg.freq_text[file_id][f],
fontsize=14, fontweight='bold', fontname="DejaVu Sans",
c="black", alpha=0.5,
horizontalalignment='right', verticalalignment='bottom',
transform=self.axis_BS[f].transAxes
)
# --- Plot red solid line on transect to visualize position of
# --- plotted profile ---
self.axis_BS[freq_id].plot(
stg.time[file_id][
freq_id, self.slider.value() - 1
]
* np.ones(stg.depth[file_id].shape[1]),
-stg.depth[file_id][freq_id, :],
color='red', linestyle="solid", linewidth=2
)
self.fig_BS.supxlabel('Time (sec)', fontsize=10)
self.fig_BS.supylabel('Depth (m)', fontsize=10)
cbar = self.fig_BS.colorbar(
pcm, ax=self.axis_BS[:],
shrink=1, location='right'
)
cbar.set_label(
label='Acoustic backscatter signal (V)',
rotation=270, labelpad=10
)
self.fig_BS.canvas.draw_idle()
def update_plot_backscattered_acoustic_signal_recording(self):
# --- Condition if table is filled but transect is not plotted
# --- => Error message if spin box values of tmin or tmax is change
if self.canvas_BS == None:
msgBox = QMessageBox()
msgBox.setWindowTitle("Plot transect Error")
msgBox.setIcon(QMessageBox.Warning)
msgBox.setText("Plot transect before change x-axis value")
msgBox.setStandardButtons(QMessageBox.Ok)
msgBox.exec()
return
data_id = max(0, self.fileListWidget.currentRow())
if data_id == -1:
return
if len(self.axis_BS.tolist()) != stg.freq[data_id].shape[0]:
if self.fig_BS is not None:
self.fig_BS.clear()
self.fig_BS, self.axis_BS = plt.subplots(
nrows=stg.freq[data_id].shape[0],
ncols=1,
sharex=False, sharey=False,
layout="constrained"
)
for f, _ in enumerate(stg.freq[data_id]):
self.axis_BS[f].cla()
if stg.BS_cross_section[data_id].shape != (0,):
BS_data = stg.BS_cross_section
time_data = stg.time_cross_section
depth_data = stg.depth_cross_section
else:
BS_data = stg.BS_raw_data
time_data = stg.time
depth_data = stg.depth
val_min = np.nanmin(BS_data[data_id][f, :, :])
val_max = np.nanmax(BS_data[data_id][f, :, :])
if val_min == 0:
val_min = 1e-5
if self.combobox_ABS_system_choice.currentIndex() == 1:
pcm = self.axis_BS[f].pcolormesh(
time_data[data_id][f, :],
-depth_data[data_id][f, :],
BS_data[data_id][f, :, :],
cmap='viridis',
norm=LogNorm(vmin=val_min, vmax=val_max)
)
elif self.combobox_ABS_system_choice.currentIndex() == 2:
pcm = self.axis_BS[f].pcolormesh(
time_data[data_id][f, :],
-depth_data[data_id][f, :],
np.log(BS_data[data_id][f, :, :]),
cmap='Blues'
)
# --- Plot red solid line on transect to visualize position of plotted profile ---
slider_value = [
self.slider.value() - 1
if self.slider.value() - 1 <= time_data[data_id].shape[1] - 1
else np.max(time_data[data_id].shape[1] - 1)
][0]
freq_id = self.combobox_frequency_profile.currentIndex()
self.axis_BS[freq_id].plot(
time_data[data_id][0, slider_value] * np.ones(
depth_data[data_id].shape[1]
),
-depth_data[data_id][freq_id, :],
color='red', linestyle="solid", linewidth=2
)
# --- Plot river bottom line ---
if stg.depth_bottom[data_id].shape != (0,):
self.axis_BS[f].plot(
time_data[data_id][
self.combobox_frequency_bathymetry.currentIndex(), :
],
-stg.depth_bottom[data_id],
color='black', linewidth=1, linestyle="solid"
)
self.fig_BS.supxlabel('Time (sec)', fontsize=10)
self.fig_BS.supylabel('Depth (m)', fontsize=10)
self.fig_BS.canvas.draw_idle()
def plot_profile(self):
if self.fileListWidget.currentRow() != -1:
self.combobox_frequency_profile.setCurrentIndex(0)
self.combobox_frequency_profile.currentIndexChanged.connect(self.update_plot_profile)
self.combobox_frequency_profile.currentIndexChanged.connect(
self.update_plot_backscattered_acoustic_signal_recording
)
self.slider.setMaximum(stg.time[self.fileListWidget.currentRow()].shape[1])
self.verticalLayout_groupbox_plot_profile.removeWidget(self.toolbar_profile)
self.verticalLayout_groupbox_plot_profile.removeWidget(self.canvas_plot_profile)
# --- Figure to plot profiles ---
if self.fig_profile is not None:
self.fig_profile.clear()
self.fig_profile, self.axis_profile = plt.subplots(nrows=1, ncols=1, layout="constrained")
self.canvas_plot_profile = FigureCanvas(self.fig_profile)
self.toolbar_profile = NavigationToolBar(self.canvas_plot_profile, self)
self.verticalLayout_groupbox_plot_profile.addWidget(self.toolbar_profile)
self.verticalLayout_groupbox_plot_profile.addWidget(self.canvas_plot_profile)
slider_value = [
self.slider.value() - 1 if self.slider.value() - 1 <= stg.time[self.fileListWidget.currentRow()].shape[
1] - 1 else np.max(stg.time[self.fileListWidget.currentRow()].shape[1] - 1)][0]
# --- Profile plot ---
self.axis_profile.plot(stg.BS_raw_data[self.fileListWidget.currentRow()][
self.combobox_frequency_profile.currentIndex(), :, self.slider.value() - 1],
-stg.depth[self.fileListWidget.currentRow()][self.combobox_frequency_profile.currentIndex(), :],
linestyle='solid', color='k', linewidth=1)
self.axis_profile.text(.95, .05, stg.freq_text[self.fileListWidget.currentRow()][self.combobox_frequency_profile.currentIndex()],
fontsize=10, fontweight='bold', fontname="DejaVu Sans",
fontstyle="normal", c="black", alpha=0.2,
horizontalalignment='right', verticalalignment='bottom',
transform=self.axis_profile.transAxes)
# --- Plot bottom line ---
if len(stg.depth_bottom[self.fileListWidget.currentRow()]) != 0:
self.axis_profile.plot([0,
np.nanmax(stg.BS_raw_data[self.fileListWidget.currentRow()][
self.combobox_frequency_profile.currentIndex(),
:, slider_value])],
-stg.depth[self.fileListWidget.currentRow()][
self.combobox_frequency_profile.currentIndex(),
int(stg.ind_bottom[self.fileListWidget.currentRow()][slider_value])] * np.ones(2),
linestyle='solid', color='r', linewidth=1)
position_x = (stg.depth[self.fileListWidget.currentRow()][self.combobox_frequency_profile.currentIndex(),
int(stg.ind_bottom[self.fileListWidget.currentRow()][slider_value])] /
np.nanmax(
stg.depth[self.fileListWidget.currentRow()][self.combobox_frequency_profile.currentIndex(),
:]))
self.axis_profile.text(.95, 1 - position_x + 0.05, "River bed",
fontsize=10, fontweight='normal', fontname="Times New Roman",
fontstyle="italic", c="red", alpha=0.2,
horizontalalignment='right', verticalalignment='bottom',
transform=self.axis_profile.transAxes)
self.fig_profile.supxlabel("Acoustic Backscatter Signal (V)")
self.fig_profile.supylabel("Depth (m)")
self.fig_profile.canvas.draw_idle()
def update_plot_profile(self):
if self.fileListWidget.currentRow() != -1:
if stg.BS_cross_section[self.fileListWidget.currentRow()].shape != (0,):
self.axis_profile.cla()
# --- Set slider value ---
self.slider.setMaximum(stg.time_cross_section[self.fileListWidget.currentRow()].shape[1])
slider_value = [self.slider.value() - 1 if self.slider.value() - 1 <= stg.time_cross_section[
self.fileListWidget.currentRow()].shape[1] - 1
else np.max(stg.time_cross_section[self.fileListWidget.currentRow()].shape[1] - 1)][0]
# --- Profile plot ---
self.axis_profile.plot(stg.BS_cross_section[self.fileListWidget.currentRow()][
self.combobox_frequency_profile.currentIndex(), :, slider_value],
-stg.depth_cross_section[self.fileListWidget.currentRow()][
self.combobox_frequency_profile.currentIndex(), :],
linestyle='solid', color='k', linewidth=1)
# --- Write frequency on graph ---
self.axis_profile.text(.95, .90, stg.freq_text[self.fileListWidget.currentRow()][
self.combobox_frequency_profile.currentIndex()],
fontsize=14, fontweight='bold', fontname="DejaVu Sans",
fontstyle="normal", c="black", alpha=0.2,
horizontalalignment='right', verticalalignment='bottom',
transform=self.axis_profile.transAxes)
# --- Plot bottom line ---
if stg.depth_bottom[self.fileListWidget.currentRow()].shape != (0,):
self.axis_profile.plot([0,
np.nanmax(stg.BS_cross_section[self.fileListWidget.currentRow()][
self.combobox_frequency_profile.currentIndex(),
:, slider_value])],
-stg.depth[self.fileListWidget.currentRow()][
self.combobox_frequency_profile.currentIndex(),
int(stg.ind_bottom[self.fileListWidget.currentRow()][
slider_value])] * np.ones(2),
linestyle='solid', color='r', linewidth=1)
position_x = (stg.depth[self.fileListWidget.currentRow()][
self.combobox_frequency_profile.currentIndex(),
int(stg.ind_bottom[self.fileListWidget.currentRow()][slider_value])] /
np.nanmax(stg.depth[self.fileListWidget.currentRow()][
self.combobox_frequency_profile.currentIndex(), :]))
self.axis_profile.text(.95, 1 - position_x + 0.05, "River bed",
fontsize=10, fontweight='normal', fontname="DejaVu Sans",
fontstyle="italic", c="red", alpha=0.2,
horizontalalignment='right', verticalalignment='bottom',
transform=self.axis_profile.transAxes)
else:
self.axis_profile.cla()
# --- Set slider value ---
self.slider.setMaximum(stg.time[self.fileListWidget.currentRow()].shape[1])
slider_value = [self.slider.value() - 1 if self.slider.value() - 1 <= stg.time[
self.fileListWidget.currentRow()].shape[1] - 1
else np.max(stg.time[self.fileListWidget.currentRow()].shape[1] - 1)][0]
# --- Profile plot ---
self.axis_profile.plot(stg.BS_raw_data[self.fileListWidget.currentRow()][
self.combobox_frequency_profile.currentIndex(), :, self.slider.value() - 1],
-stg.depth[self.fileListWidget.currentRow()][
self.combobox_frequency_profile.currentIndex(), :],
linestyle='solid', color='k', linewidth=1)
# --- Write frequency on graph ---
self.axis_profile.text(.95, .05, stg.freq_text[self.fileListWidget.currentRow()][
self.combobox_frequency_profile.currentIndex()],
fontsize=10, fontweight='bold', fontname="DejaVu Sans",
fontstyle="normal", c="black", alpha=0.2,
horizontalalignment='right', verticalalignment='bottom',
transform=self.axis_profile.transAxes)
# --- Plot bottom line ---
if stg.depth_bottom[self.fileListWidget.currentRow()].shape != (0,):
self.axis_profile.plot([0,
np.nanmax(stg.BS_raw_data[self.fileListWidget.currentRow()][
self.combobox_frequency_profile.currentIndex(),
:, slider_value])],
-stg.depth[self.fileListWidget.currentRow()][
self.combobox_frequency_profile.currentIndex(),
int(stg.ind_bottom[self.fileListWidget.currentRow()][
slider_value])] * np.ones(2),
linestyle='solid', color='r', linewidth=1)
position_x = (stg.depth[self.fileListWidget.currentRow()][
self.combobox_frequency_profile.currentIndex(),
int(stg.ind_bottom[self.fileListWidget.currentRow()][slider_value])] /
np.nanmax(stg.depth[self.fileListWidget.currentRow()][
self.combobox_frequency_profile.currentIndex(), :]))
self.axis_profile.text(.95, 1 - position_x + 0.05, "River bed",
fontsize=10, fontweight='normal', fontname="DejaVu Sans",
fontstyle="italic", c="red", alpha=0.2,
horizontalalignment='right', verticalalignment='bottom',
transform=self.axis_profile.transAxes)
self.fig_profile.supxlabel("Acoustic Backscatter Signal (V)")
self.fig_profile.supylabel("Depth (m)")
self.fig_profile.canvas.draw_idle()
def slide_profile_number_to_begin(self):
self.slider.setValue(int(self.slider.minimum()))
self.update_lineEdit_by_moving_slider()
def slide_profile_number_to_right(self):
self.slider.setValue(int(self.slider.value()) + 1)
self.update_lineEdit_by_moving_slider()
def slide_profile_number_to_left(self):
self.slider.setValue(int(self.slider.value()) - 1)
self.update_lineEdit_by_moving_slider()
def slide_profile_number_to_end(self):
self.slider.setValue(int(self.slider.maximum()))
self.update_lineEdit_by_moving_slider()
def profile_number_on_lineEdit(self):
if stg.time_cross_section[self.fileListWidget.currentRow()].shape != (0,):
self.slider.setValue(
int(np.where(np.abs(stg.time_cross_section[self.fileListWidget.currentRow()][self.combobox_frequency_profile.currentIndex()] -
float(self.lineEdit_slider.text().replace(",", "."))) ==
np.nanmin(np.abs(stg.time_cross_section[self.fileListWidget.currentRow()][self.combobox_frequency_profile.currentIndex()] -
float(self.lineEdit_slider.text().replace(",", ".")))))[0][0]))
else:
self.slider.setValue(
int(np.where(np.abs(stg.time[self.fileListWidget.currentRow()][self.combobox_frequency_profile.currentIndex()] -
float(self.lineEdit_slider.text().replace(",", "."))) ==
np.nanmin(np.abs(stg.time[self.fileListWidget.currentRow()][self.combobox_frequency_profile.currentIndex()] -
float(self.lineEdit_slider.text().replace(",", ".")))))[0][0]))
def update_lineEdit_by_moving_slider(self):
if stg.time_cross_section[self.fileListWidget.currentRow()].shape != (0,):
self.lineEdit_slider.setText(
str(stg.time_cross_section[self.fileListWidget.currentRow()][self.combobox_frequency_profile.currentIndex(), self.slider.value()-1]))
else:
self.lineEdit_slider.setText(
str(stg.time[self.fileListWidget.currentRow()][self.combobox_frequency_profile.currentIndex(), self.slider.value()-1]))
def update_bottom_detection_settings(self):
data_id = max(0, self.fileListWidget.currentRow())
if stg.depth_bottom_detection_interval[data_id] == 0.0:
self.set_range_for_spinboxes_bathymetry()
return
self.combobox_frequency_bathymetry.setCurrentIndex(
int(stg.freq_bottom_detection[data_id][0])
)
self.lineEdit_depth_min_bathy.setText(
str(stg.depth_bottom_detection_min[data_id])
)
self.lineEdit_depth_max_bathy.setText(
str(stg.depth_bottom_detection_max[data_id])
)
self.lineEdit_next_cell_bathy.setText(
str(stg.depth_bottom_detection_interval[data_id])
)
def save_bottom_detection_settings(self):
data_id = max(0, self.fileListWidget.currentRow())
stg.freq_bottom_detection[data_id] = (
int(self.combobox_frequency_bathymetry.currentIndex()),
str(self.combobox_frequency_bathymetry.currentText()),
)
stg.depth_bottom_detection_min[data_id] = float(
self.lineEdit_depth_min_bathy.text()
)
stg.depth_bottom_detection_max[data_id] = float(
self.lineEdit_depth_max_bathy.text()
)
stg.depth_bottom_detection_interval[data_id] = float(
self.lineEdit_next_cell_bathy.text()
)
def detect_bottom(self):
self.save_bottom_detection_settings()
if self.fileListWidget.count() == 0:
msgBox = QMessageBox()
msgBox.setWindowTitle("Detect bottom Error")
msgBox.setIcon(QMessageBox.Warning)
msgBox.setText("Load data before compute bathymety algorithm")
msgBox.setStandardButtons(QMessageBox.Ok)
msgBox.exec()
return
elif self.canvas_BS == None:
msgBox = QMessageBox()
msgBox.setWindowTitle("Detect bottom Error")
msgBox.setIcon(QMessageBox.Warning)
msgBox.setText("Plot transect before compute bathymety algorithm")
msgBox.setStandardButtons(QMessageBox.Ok)
msgBox.exec()
return
elif self.lineEdit_next_cell_bathy.text() == "0.00":
return
self.detect_bottom_compute()
def detect_bottom_compute(self):
data_id = max(0, self.fileListWidget.currentRow())
freq_id = self.combobox_frequency_bathymetry.currentIndex()
freq_text = self.combobox_frequency_bathymetry.currentText()
if stg.BS_cross_section[data_id].shape != (0,):
BS_data = stg.BS_cross_section
time_data = stg.time_cross_section
depth_data = stg.depth_cross_section
elif stg.BS_raw_data[data_id].shape != (0,):
BS_data = stg.BS_raw_data
time_data = stg.time
depth_data = stg.depth
stg.freq_bottom_detection[data_id] = (freq_id, freq_text)
rmin = float(
"".join(findall(
"[.0-9]",
self.lineEdit_depth_max_bathy.text()
))
)
rmax = float(
"".join(findall(
"[.0-9]", self.lineEdit_depth_min_bathy.text()
))
)
r_bottom = np.zeros(time_data[data_id].shape[1])
val_bottom = np.zeros(time_data[data_id].shape[1])
r_bottom_ind = []
BS_smooth = deepcopy(BS_data[data_id][freq_id, :, :])
for k in range(time_data[data_id].shape[1]):
BS_smooth[:, k] = savgol_filter(BS_smooth[:, k], 10, 2)
# ----------- Detecting the bottom -------------
for d in range(time_data[data_id].shape[1]):
ind_min = np.where(
depth_data[data_id][freq_id, :]
>= rmin
)[0][0]
ind_max = np.where(
depth_data[data_id][freq_id, :]
<= rmax
)[0][-1]
# Getting the peak
try:
val_bottom[d] = np.nanmax(BS_smooth[ind_min:ind_max, d])
except ValueError as e:
msgBox = QMessageBox()
msgBox.setWindowTitle("Detect bottom Error")
msgBox.setIcon(QMessageBox.Warning)
msgBox.setText(
f"1/ {e} : maximum value of section bottom is not found. \n "
f"Please change parameter of algorithm"
)
msgBox.setStandardButtons(QMessageBox.Ok)
msgBox_return = msgBox.exec()
if msgBox_return == msgBox.Ok:
break
else:
ind_bottom = np.where(
(BS_smooth[ind_min:ind_max, d]) == val_bottom[d]
)[0][0]
# np.append(stg.ind_bottom, ind_bottom)
r_bottom[d] = depth_data[data_id][
freq_id, ind_bottom + ind_min
]
r_bottom_ind.append(ind_bottom + ind_min)
# Updating the range where we will look for the peak (in the next cell)
rmin = r_bottom[d] - float(
"".join(findall(
"[.0-9]", self.lineEdit_next_cell_bathy.text()
))
)
rmax = r_bottom[d] + float(
"".join(findall(
"[.0-9]", self.lineEdit_next_cell_bathy.text()
))
)
BS_section_bottom = np.zeros((
depth_data[data_id].shape[1],
time_data[data_id].shape[1]
))
for i in range(BS_section_bottom.shape[0]):
try:
BS_section_bottom[r_bottom_ind[i]][i] = 1
except IndexError as e:
msgBox = QMessageBox()
msgBox.setWindowTitle("Detect bottom Error")
msgBox.setIcon(QMessageBox.Warning)
msgBox.setText(
f"2/ {e} : maximum value of section bottom is not found. \n "
f"Please change parameter of algorithm"
)
msgBox.setStandardButtons(QMessageBox.Ok)
msgBox_return = msgBox.exec()
if msgBox_return == msgBox.Ok:
break
if BS_section_bottom.sum() > 2:
stg.depth_bottom[data_id] = r_bottom
stg.val_bottom[data_id] = val_bottom
stg.ind_bottom[data_id] = r_bottom_ind
BS_stream_bed_copy = deepcopy(BS_data[data_id])
for f, _ in enumerate(stg.freq[data_id]):
for k, _ in enumerate(stg.depth_bottom[data_id]):
BS_stream_bed_copy[
f, np.where(
depth_data[data_id][freq_id, :]
>= stg.depth_bottom[data_id][k]
)[0], k
] = np.nan
stg.BS_stream_bed[data_id] = BS_stream_bed_copy
self.detect_bottom_compute_plot_BS_with_bathymetry(
BS_data, time_data, depth_data
)
# --- Update plot profile ---
self.update_plot_profile()
self.fig_BS.canvas.draw_idle()
def detect_bottom_compute_plot_BS_with_bathymetry(
self, BS_data, time_data, depth_data
):
data_id = max(0, self.fileListWidget.currentRow())
freq_id = self.combobox_frequency_bathymetry.currentIndex()
for f, _ in enumerate(stg.freq[data_id]):
self.axis_BS[f].cla()
val_min = np.min(stg.BS_raw_data[data_id][f, :, :])
val_max = np.max(stg.BS_raw_data[data_id][f, :, :])
if val_min == 0:
val_min = 1e-5
if self.combobox_ABS_system_choice.currentIndex() == 1:
pcm = self.axis_BS[f].pcolormesh(
time_data[data_id][f, :],
-depth_data[data_id][f, :],
BS_data[data_id][f, :, :],
cmap='viridis',
norm=LogNorm(vmin=val_min, vmax=val_max)
)
elif self.combobox_ABS_system_choice.currentIndex() == 2:
pcm = self.axis_BS[f].pcolormesh(
time_data[data_id][f, :],
-depth_data[data_id][f, :],
np.log(BS_data[data_id][f, :, :]),
cmap='Blues'
)
self.axis_BS[f].plot(
time_data[data_id][freq_id, :],
-stg.depth_bottom[data_id],
color='black', linewidth=1, linestyle="solid"
)
self.axis_BS[f].text(
1, .70, stg.freq_text[data_id][f],
fontsize=14, fontweight='bold',
fontname="DejaVu Sans", c="black", alpha=0.5,
horizontalalignment='right',
verticalalignment='bottom',
transform=self.axis_BS[f].transAxes
)