Implementation of acoustic inversion method for suspended sediments high concentrations

dev-brahim
brahim 2023-09-05 12:09:21 +02:00
parent 1b8945025c
commit 5bd6f9d08f
7 changed files with 888 additions and 231 deletions

View File

@ -80,6 +80,10 @@ class AcousticDataLoader():
order="F")
return r
def compute_r_2D(self):
r2D = np.repeat(self._r, self._time.size, axis=1)
return r2D
def reshape_t(self):
t = np.reshape(np.repeat(self._time, self._r.shape[0]), (self._time.shape[0]*self._r.shape[0], 1))
return t

View File

@ -0,0 +1,150 @@
import numpy as np
import settings as stg
class AcousticInversionMethodHighConcentration():
""" Thi class compute acoustic inversion method adapted for high suspended sediments concentration
For instance, the case of dam flush downstream Rhone-Isere confluence (07/01/2018) evaluated at ~ 10g/L """
def __init__(self):
pass
# ==========================================
# Functions
# ==========================================
# ---------- Computing sound speed ------------- #
def water_velocity(self, T):
"""Computing sond speed from Bilaniuk and Wong 1993"""
C = 1.40238744 * 1e3 + 5.03836171 * T - 5.81172916 * 1e-2 * T ** 2 + 3.34638117 * 1e-4 * T ** 3 - \
1.48259672 * 1e-6 * T ** 4 + 3.16585020 * 1e-9 * T ** 5
return C
# -------- Computing water attenuation coefficient ----------- #
def water_attenuation(self, freq1, freq2, T):
"""Computing attenuation from François and Garrison 1982"""
if T > 20:
alpha = (3.964 * 1e-4 - 1.146 * 1e-5 * T + 1.45 * 1e-7 * T ** 2 - 6.5 * 1e-10 * T ** 3) * 1e-3 * \
(np.log(10) / 20) * (np.array([freq1, freq2]) * 1e-3) ** 2
else:
alpha = (4.937 * 1e-4 - 2.59 * 1e-5 * T + 9.11 * 1e-7 * T ** 2 - 1.5 * 1e-8 * T ** 3) * 1e-3 * \
(np.log(10) / 20) * (np.array([freq1, freq2]) * 1e-3) ** 2
return alpha
# ---------- Conmpute FBC ----------
# def compute_FCB(self):
# # print(self.BS_averaged_cross_section_corr.V.shape)
# # print(self.r_2D.shape)
# FCB = np.zeros((256, 4, 1912))
# for f in range(4):
# # print(self.alpha_w_function(self.Freq[f], self.temperature))
# FCB[:, f, :] = np.log(self.BS_averaged_cross_section_corr.V[:, f, :]) + np.log(self.r_3D[:, f, :]) + \
# np.log(2 * self.alpha_w_function(self.Freq[f], self.temperature) * self.r_3D[:, f, :])
# return FCB
# ------------- Computing ks ------------- #
def ks(self, ind):
ks0 = np.array([0.0446681, 0.11490388, 0.35937832, 2.5025668])
ks = ks0[ind]
return ks
# ------------- Computing sv ------------- #
def sv(self):
pass
# ------------- Computing X ------------- #
def X_exponent(self, ind):
X0 = [3.688664080521131, 3.451418735488537, 0, 3.276577078823426, 0, 0]
X = X0[ind]
return X
# -------------- Computing Kt -------------- #
def kt_corrected(self, r, water_velocity, RxGain, TxGain, kt_ref):
"""Computing the instrument constant Kt that depends on gain and temperature"""
# Cell size
delta_r = r[1] - r[0]
# Pulse length
tau = 2 * delta_r / 1500
# Sound speed
cel = water_velocity
# Reference pulse length
tau_ref = 13.33333e-6
# Reference sound speed
c_ref = 1475
# Gain
gain = 10 ** ((RxGain + TxGain) / 20)
# Computing Kt
kt0 = kt_ref * gain * np.sqrt(tau * cel / (tau_ref * c_ref)) # 1D numpy array
kt = np.reshape(kt0, (1, 2)) # convert to 2d numpy array to compute J_cross_section
return kt
# ------------- Computing J_cross_section ------------- #
def j_cross_section(self, BS, r2D, kt):
J_cross_section = np.zeros((2, BS.shape[0], BS.shape[2])) # 2 because it's a pair of frequencies
for k in range(2):
J_cross_section[k, :, :] = (3 / (16 * np.pi)) * ((BS[:, k, :]**2 * r2D**2) / kt[k, :, :]**2)
# J_cross_section[J_cross_section == 0] = np.nan
print("compute j_cross_section finished")
return J_cross_section
# ------------- Computing alpha_s ------------- #
def alpha_s(self):
pass
# ------------- Computing interpolation of fine SSC data obtained from water sampling -------------
# ------------- collected at various depth in the vertical sample -------------
def M_profile_SCC_fine_interpolated(self):
pass
# ------------- Computing zeta ------------- #
def zeta(self, ind1, ind2):
# zeta = alpha_s / ((1/r) * (M_profile_SSC_fine))
zeta0 = np.array([0.04341525, 0.04832906, 0.0847188, np.nan])
zeta = zeta0[[ind1, ind2]]
return zeta
# ------------- Computing VBI ------------- #
def VBI_cross_section(self, freq1, freq2,
zeta_freq1, zeta_freq2,
j_cross_section_freq1, j_cross_section_freq2,
r2D,
water_attenuation_freq1, water_attenuation_freq2,
X):
# print('self.zeta_exp[ind_j].shape', self.zeta_exp[ind_j])
# print('np.log(self.j_cross_section[:, ind_i, :]).shape', np.log(self.j_cross_section[:, ind_i, :]).shape)
# print('self.r_3D[:, ind_i, :]', self.r_3D[:, ind_i, :].shape)
# print('self.water_attenuation[ind_i]', self.water_attenuation[ind_i])
# print('self.x_exp[0.3-1 MHz]', self.x_exp['0.3-1 MHz'].values[0])
# print("start computing VBI")
logVBI = ((zeta_freq2 *
np.log(j_cross_section_freq1 * np.exp(4 * r2D * water_attenuation_freq1) /
(freq1 ** X)) -
zeta_freq1 *
np.log(j_cross_section_freq2 * np.exp(4 * r2D * water_attenuation_freq2) /
(freq2 ** X))) /
(zeta_freq2 - zeta_freq1))
print("compute VBI finished")
return np.exp(logVBI)
# ------------- Computing SSC fine ------------- #
def SSC_fine(self, zeta, r2D, VBI, freq, X, j_cross_section):
SSC_fine = (1/zeta) * ( 1/(4 * r2D) * np.log((VBI * freq**X) / j_cross_section) )
print("compute SSC fine finished")
return SSC_fine
# ------------- Computing SSC sand ------------- #
def SSC_sand(self, VBI, freq, X, ks):
SSC_sand = (16 * np.pi * VBI * freq ** X) / (3 * ks**2)
print("compute SSC sand finished")
return SSC_sand

View File

@ -327,9 +327,9 @@ class AcousticDataTab(QWidget):
self.verticalLayout_display_option.addWidget(self.groupbox_xaxis_time)
self.gridLayout_groupbox_xaxis_time = QGridLayout(self.groupbox_xaxis_time)
self.label_from = QLabel()
self.label_from.setText("From")
self.gridLayout_groupbox_xaxis_time.addWidget(self.label_from, 0, 0, 1, 1)
self.label_from_time = QLabel()
self.label_from_time.setText("From")
self.gridLayout_groupbox_xaxis_time.addWidget(self.label_from_time, 0, 0, 1, 1)
self.label_tmin = QLabel()
self.label_tmin.setText("t<span style= vertical-align:sub>min</span> = ")
@ -345,9 +345,9 @@ class AcousticDataTab(QWidget):
self.label_tmin_unit.setText("sec")
self.gridLayout_groupbox_xaxis_time.addWidget(self.label_tmin_unit, 0, 3, 1, 1)
self.label_to = QLabel()
self.label_to.setText("to")
self.gridLayout_groupbox_xaxis_time.addWidget(self.label_to, 0, 4, 1, 1)
self.label_to_time = QLabel()
self.label_to_time.setText("to")
self.gridLayout_groupbox_xaxis_time.addWidget(self.label_to_time, 0, 4, 1, 1)
self.label_tmax = QLabel()
self.label_tmax.setText("t<span style= vertical-align:sub>max</span> = ")
@ -356,13 +356,19 @@ class AcousticDataTab(QWidget):
self.spinbox_tmax = QDoubleSpinBox()
self.spinbox_tmax.setRange(0, 9999)
self.gridLayout_groupbox_xaxis_time.addWidget(self.spinbox_tmax, 0, 6, 1, 1)
self.spinbox_tmax.valueChanged.connect(self.update_xaxis_transect_with_BS_raw_data)
self.spinbox_tmax.valueChanged.connect(self.update_xaxis_transect_with_SNR_data)
# self.spinbox_tmax.valueChanged.connect(self.update_xaxis_transect_with_BS_raw_data)
# self.spinbox_tmax.valueChanged.connect(self.update_xaxis_transect_with_SNR_data)
self.label_tmax_unit = QLabel()
self.label_tmax_unit.setText("sec")
self.gridLayout_groupbox_xaxis_time.addWidget(self.label_tmax_unit, 0, 7, 1, 1)
self.pushbutton_apply_transect_boundaries_in_time = QPushButton()
self.pushbutton_apply_transect_boundaries_in_time.setText("Apply")
self.gridLayout_groupbox_xaxis_time.addWidget(self.pushbutton_apply_transect_boundaries_in_time, 0, 7, 1, 1)
self.pushbutton_apply_transect_boundaries_in_time.clicked.connect(self.update_xaxis_transect_with_BS_raw_data)
self.pushbutton_apply_transect_boundaries_in_time.clicked.connect(self.update_xaxis_transect_with_SNR_data)
# --- Group Box Plot x-axis in space ---
self.groupbox_xaxis_space = QGroupBox()
@ -372,31 +378,44 @@ class AcousticDataTab(QWidget):
self.verticalLayout_display_option.addWidget(self.groupbox_xaxis_space)
self.gridLayout_groupbox_xaxis_space = QGridLayout(self.groupbox_xaxis_space)
self.label_from = QLabel()
self.label_from.setText("From")
self.gridLayout_groupbox_xaxis_space.addWidget(self.label_from, 0, 0, 1, 1)
self.label_from_space = QLabel()
self.label_from_space.setText("From ")
self.gridLayout_groupbox_xaxis_space.addWidget(self.label_from_space, 0, 0, 1, 1)
self.label_xmin = QLabel()
self.label_xmin.setText("x<span style= vertical-align:sub>min</span> = ")
self.gridLayout_groupbox_xaxis_space.addWidget(self.label_xmin, 0, 1, 1, 1)
self.spinbox_xmin = QSpinBox()
self.spinbox_xmin.setRange(0, 9999)
self.gridLayout_groupbox_xaxis_space.addWidget(self.spinbox_xmin, 0, 2, 1, 1)
self.label_xmin_m = QLabel()
self.label_xmin_m.setText("m")
self.gridLayout_groupbox_xaxis_space.addWidget(self.label_xmin_m, 0, 3, 1, 1)
self.label_to = QLabel()
self.label_to.setText("to")
self.gridLayout_groupbox_xaxis_space.addWidget(self.label_to, 0, 4, 1, 1)
self.label_to_space = QLabel()
self.label_to_space.setText("to")
self.gridLayout_groupbox_xaxis_space.addWidget(self.label_to_space, 0, 4, 1, 1)
self.label_xmax = QLabel()
self.label_xmax.setText("x<span style= vertical-align:sub>max</span> = ")
self.gridLayout_groupbox_xaxis_space.addWidget(self.label_xmax, 0, 5, 1, 1)
self.spinbox_xmax = QSpinBox()
self.spinbox_xmax.setRange(0, 9999)
self.gridLayout_groupbox_xaxis_space.addWidget(self.spinbox_xmax, 0, 6, 1, 1)
self.label_xmax_m = QLabel()
self.label_xmax_m.setText("m")
self.gridLayout_groupbox_xaxis_space.addWidget(self.label_xmax_m, 0, 7, 1, 1)
self.pushbutton_apply_transect_boundaries_in_space = QPushButton()
self.pushbutton_apply_transect_boundaries_in_space.setText("Apply")
self.gridLayout_groupbox_xaxis_space.addWidget(self.pushbutton_apply_transect_boundaries_in_space, 0, 8, 1, 1)
self.pushbutton_apply_transect_boundaries_in_space.clicked.connect(self.update_xaxis_transect_with_BS_raw_data)
self.pushbutton_apply_transect_boundaries_in_space.clicked.connect(self.update_xaxis_transect_with_SNR_data)
# --- Group Box bathymetry computation algorithm to detect and plot bottom of transect---
self.groupbox_compute_bathymetry = QGroupBox()
@ -410,30 +429,44 @@ class AcousticDataTab(QWidget):
self.combobox_freq_choice = QComboBox()
# self.combobox_freq_choice.addItems(['', '0.3 MHz', '0.5 Mhz', '1 MHz', '5 MHz'])
self.gridlayout_compute_bathymetry.addWidget(self.combobox_freq_choice, 0, 0, 2, 1)
self.gridlayout_compute_bathymetry.addWidget(self.label_from, 0, 1, 1, 1)
self.label_from_bathy = QLabel()
self.label_from_bathy.setText("From ")
self.gridlayout_compute_bathymetry.addWidget(self.label_from_bathy, 0, 1, 1, 1)
self.spinbox_depth_min = QSpinBox()
self.spinbox_depth_min.setRange(0, 9999)
self.gridlayout_compute_bathymetry.addWidget(self.spinbox_depth_min, 0, 2, 1, 1)
self.label_depth_min_unit = QLabel()
self.label_depth_min_unit.setText("m")
self.gridlayout_compute_bathymetry.addWidget(self.label_depth_min_unit, 0, 3, 1, 1)
self.gridlayout_compute_bathymetry.addWidget(self.label_to, 0, 4, 1, 1)
self.label_to_bathy = QLabel()
self.label_to_bathy.setText("to ")
self.gridlayout_compute_bathymetry.addWidget(self.label_to_bathy, 0, 4, 1, 1)
self.spinbox_depth_max = QSpinBox()
self.spinbox_depth_max.setRange(0, 99999)
self.gridlayout_compute_bathymetry.addWidget(self.spinbox_depth_max, 0, 5, 1, 1)
self.label_depth_max_unit = QLabel()
self.label_depth_max_unit.setText("m")
self.gridlayout_compute_bathymetry.addWidget(self.label_depth_max_unit, 0, 6, 1, 1)
self.label_next_cell = QLabel()
self.label_next_cell.setText("Next cell : +/-")
self.gridlayout_compute_bathymetry.addWidget(self.label_next_cell, 1, 1, 1, 1)
self.doublespinbox_next_cell = QDoubleSpinBox()
self.doublespinbox_next_cell.setRange(0, 99999)
self.doublespinbox_next_cell.setDecimals(2)
self.gridlayout_compute_bathymetry.addWidget(self.doublespinbox_next_cell, 1, 2, 1, 1)
self.label_next_cell_unit = QLabel()
self.label_next_cell_unit.setText("m")
self.gridlayout_compute_bathymetry.addWidget(self.label_next_cell_unit, 1, 3, 1, 1)
self.pushbutton_compute_bathymetry_algorithm = QPushButton()
self.pushbutton_compute_bathymetry_algorithm.setText("Compute \n&& \nPlot")
self.gridlayout_compute_bathymetry.addWidget(self.pushbutton_compute_bathymetry_algorithm, 0, 7, 2, 1)
@ -684,6 +717,7 @@ class AcousticDataTab(QWidget):
stg.BS_raw_data = acoustic_data._BS_raw_data
stg.BS_raw_data_reshape = acoustic_data.reshape_BS_raw_cross_section()
stg.r = acoustic_data._r
stg.r_2D = acoustic_data.compute_r_2D()
stg.r_reshape = acoustic_data.reshape_r()
stg.time = acoustic_data._time
stg.time_reshape = acoustic_data.reshape_t()
@ -861,6 +895,8 @@ class AcousticDataTab(QWidget):
np.where(np.round(stg.time, 2) == self.spinbox_tmax.value())[0][0]]
stg.t = stg.time[np.where(np.round(stg.time, 2) == self.spinbox_tmin.value())[0][0]:
np.where(np.round(stg.time, 2) == self.spinbox_tmax.value())[0][0]]
stg.r_2D = stg.r_2D[:, np.where(np.round(stg.time, 2) == self.spinbox_tmin.value())[0][0]:
np.where(np.round(stg.time, 2) == self.spinbox_tmax.value())[0][0]]
for f in range(stg.freq.shape[0]):
self.axis_BS[f].cla()

View File

@ -1,18 +1,28 @@
import sys
from PyQt5.QtWidgets import QWidget, QMainWindow, QApplication, QVBoxLayout, QHBoxLayout, QGroupBox
from PyQt5.QtCore import QCoreApplication
from PyQt5.QtWidgets import QWidget, QMainWindow, QApplication, QVBoxLayout, QHBoxLayout, QGroupBox, QComboBox, \
QGridLayout, QLabel, QPushButton, QSpinBox
from PyQt5.QtCore import QCoreApplication, Qt
from PyQt5.QtGui import QStandardItemModel
import numpy as np
from itertools import combinations
import matplotlib.pyplot as plt
from matplotlib.colors import LogNorm, BoundaryNorm, CSS4_COLORS
from matplotlib.backends.backend_qt5agg import FigureCanvasQTAgg as FigureCanvas
from matplotlib.backends.backend_qt5agg import NavigationToolbar2QT as NavigationToolBar
import Translation.constant_string as cs
from checkable_combobox import CheckableComboBox
import settings as stg
from Model.acoustic_inversion_method_high_concentration import AcousticInversionMethodHighConcentration
_translate = QCoreApplication.translate
@ -23,22 +33,141 @@ class AcousticInversionTab(QWidget):
def __init__(self, widget_tab):
super().__init__()
#
# self.verticalLayout_acoustic_inversion_tab = QVBoxLayout(widget_tab)
#
# self.horizontalLayout_Top_acousticInversionTab = QHBoxLayout()
#
# self.groupbox_AcousticInversionOption = QGroupBox()
# # self.groupbox_AcousticInversionOption.setTitle("Acoustic inversion option")
#
# self.horizontalLayout_Top_acousticInversionTab.addWidget(self.groupbox_AcousticInversionOption)
#
# self.verticalLayout_acoustic_inversion_tab.addLayout(self.horizontalLayout_Top_acousticInversionTab, 4)
#
# self.horizontalLayout_Bottom_acousticInversionTab = QHBoxLayout()
#
# self.groupbox_sediment_concentration_2Dplot = QGroupBox()
# # self.groupbox_sediment_concentration_2Dplot.setTitle("Fine and sand sediment concentration")
self.inv_hc = AcousticInversionMethodHighConcentration()
### --- General layout of widgets ---
self.verticalLayoutMain = QVBoxLayout(widget_tab)
self.horizontalLayoutTop = QHBoxLayout()
self.verticalLayoutMain.addLayout(self.horizontalLayoutTop, 4) # 1O units is 100% , 1 units is 10%
self.horizontalLayoutBottom = QHBoxLayout()
self.verticalLayoutMain.addLayout(self.horizontalLayoutBottom, 6)
### --- Layout of groupbox in the Top horizontal layout box
# Acoustic inversion Options | Acoustic inversion method Settings parameter
self.groupbox_acoustic_inversion_options = QGroupBox()
self.horizontalLayoutTop.addWidget(self.groupbox_acoustic_inversion_options, 3)
self.groupbox_acoustic_inversion_settings_parameter = QGroupBox()
self.horizontalLayoutTop.addWidget(self.groupbox_acoustic_inversion_settings_parameter, 7)
### --- Layout of groupbox in the Bottom horizontal layout box
# Plot SSC 2D field | Plot SSC graph sample vs inversion
self.groupbox_SSC_2D_field = QGroupBox()
self.horizontalLayoutBottom.addWidget(self.groupbox_SSC_2D_field, 6)
self.groupbox_SSC_sample_vs_inversion = QGroupBox()
self.horizontalLayoutBottom.addWidget(self.groupbox_SSC_sample_vs_inversion, 4)
# =====================================================
# TOP HORIZONTAL BOX LAYOUT
# =====================================================
# +++++++++++++++++++++++++++++++++++++++++++++++
# | Group box Acoustic inversion options |
# +++++++++++++++++++++++++++++++++++++++++++++++
self.gridLayout_groupbox_acoustic_inversion_options = QGridLayout(self.groupbox_acoustic_inversion_options)
self.groupbox_acoustic_inversion_options.setTitle("Acoustic inversion option")
self.label_acoustic_inversion_method_choice = QLabel()
self.gridLayout_groupbox_acoustic_inversion_options.addWidget(
self.label_acoustic_inversion_method_choice, 0, 0, 1, 1)
self.label_acoustic_inversion_method_choice.setText("Acoustic inversion method : ")
self.combobox_acoustic_inversion_method_choice = QComboBox()
self.gridLayout_groupbox_acoustic_inversion_options.addWidget(
self.combobox_acoustic_inversion_method_choice, 0, 1, 1, 1)
self.combobox_acoustic_inversion_method_choice.addItems([" ", "Acoustic inversion method 1"])
self.combobox_acoustic_inversion_method_choice.currentIndexChanged.connect(
self.acoustic_inversion_method_choice)
self.label_sample_choice = QLabel()
self.gridLayout_groupbox_acoustic_inversion_options.addWidget(self.label_sample_choice, 1, 0, 1, 1)
self.label_sample_choice.setText("Calibration samples : ")
self.combobox_calibration_samples = CheckableComboBox()
self.gridLayout_groupbox_acoustic_inversion_options.addWidget(self.combobox_calibration_samples, 1, 1, 1, 1)
self.combobox_calibration_samples.currentIndexChanged.connect(self.sample_choice)
# +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
# | Group box Acoustic inversion method settings parameter |
# +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
self.gridLayout_groupbox_acoustic_inversion_settings_parameter \
= QGridLayout(self.groupbox_acoustic_inversion_settings_parameter)
self.groupbox_acoustic_inversion_settings_parameter.setTitle("Acoustic inversion method settings parameter")
self.label_temperature = QLabel()
self.label_temperature.setText("Temperature : ")
self.gridLayout_groupbox_acoustic_inversion_settings_parameter.addWidget(self.label_temperature, 0, 0, 1, 1)
self.spinbox_temperature = QSpinBox()
self.gridLayout_groupbox_acoustic_inversion_settings_parameter.addWidget(self.spinbox_temperature, 0, 1, 1, 1)
self.spinbox_temperature.valueChanged.connect(self.temperature_value)
self.label_frequencies_pairs_to_compute_VBI = QLabel()
self.label_frequencies_pairs_to_compute_VBI.setText("frequencies for VBI : ")
self.gridLayout_groupbox_acoustic_inversion_settings_parameter.addWidget(
self.label_frequencies_pairs_to_compute_VBI, 1, 0, 1, 1)
self.combobox_frequencies_VBI = CheckableComboBox()
self.gridLayout_groupbox_acoustic_inversion_settings_parameter.addWidget(
self.combobox_frequencies_VBI, 1, 1, 1, 1)
self.combobox_frequencies_VBI.currentIndexChanged.connect(self.frequencies_pair_choice_to_compute_VBI)
self.label_frequency_to_compute_SSC = QLabel()
self.label_frequency_to_compute_SSC.setText("frequencies for SSC : ")
self.gridLayout_groupbox_acoustic_inversion_settings_parameter.addWidget(
self.label_frequency_to_compute_SSC, 2, 0, 1, 1)
self.combobox_frequency_SSC = CheckableComboBox()
self.gridLayout_groupbox_acoustic_inversion_settings_parameter.addWidget(
self.combobox_frequency_SSC, 2, 1, 1, 1)
self.combobox_frequency_SSC.currentIndexChanged.connect(self.frequency_choice_to_compute_SSC)
self.pushbutton_run = QPushButton()
self.pushbutton_run.setText("RUN")
self.gridLayout_groupbox_acoustic_inversion_settings_parameter.addWidget(self.pushbutton_run, 3, 0, 1, 1)
self.pushbutton_run.clicked.connect(self.compute_acoustic_inversion_method_high_concentration)
self.pushbutton_plot = QPushButton()
self.pushbutton_plot.setText("PLOT")
self.gridLayout_groupbox_acoustic_inversion_settings_parameter.addWidget(self.pushbutton_plot, 3, 1, 1, 1)
self.pushbutton_plot.clicked.connect(self.plot_SSC_2D_fields)
self.pushbutton_plot.clicked.connect(self.plot_SSC_inverse_VS_measured)
# =====================================================
# BOTTOM HORIZONTAL BOX LAYOUT
# =====================================================
# +++++++++++++++++++++++++++++++++++++++++++++++
# | Group box SSC 2D field |
# +++++++++++++++++++++++++++++++++++++++++++++++
self.verticalLayout_groupbox_SSC_2D_field = QVBoxLayout(self.groupbox_SSC_2D_field)
self.groupbox_SSC_2D_field.setTitle("Suspended Sediment Concentration 2D plot")
self.canvas_SSC_2D_field = None
# +++++++++++++++++++++++++++++++++++++++++++++++
# | Group box plot samples vs inversion |
# +++++++++++++++++++++++++++++++++++++++++++++++
self.verticalLayout_groupbox_SSC_sample_vs_inversion = QVBoxLayout(self.groupbox_SSC_sample_vs_inversion)
self.groupbox_SSC_sample_vs_inversion.setTitle("Suspended Sediment Concentration : sample vs inversion")
self.canvas_SSC_sample_vs_inversion = None
#
# self.verticalLayout_groupbox_sediment_concentration_2Dplot = QVBoxLayout(self.groupbox_sediment_concentration_2Dplot)
#
@ -53,7 +182,7 @@ class AcousticInversionTab(QWidget):
# # self.horizontalLayout_Bottom_acousticInversionTab.addWidget(self.canvas_sediments2DPlot)
# self.horizontalLayout_Bottom_acousticInversionTab.addWidget(self.groupbox_sediment_concentration_2Dplot, 7)
#
# self.groupbox_sediment_concentration_sample_vs_measurement = QGroupBox()
#
# # self.groupbox_sediment_concentration_sample_vs_measurement.setTitle(
# # "Suspended sediment concentration plot : acoustic inversion theory VS measurements")
#
@ -75,68 +204,252 @@ class AcousticInversionTab(QWidget):
# self.verticalLayout_acoustic_inversion_tab.addLayout(self.horizontalLayout_Bottom_acousticInversionTab, 6)
#
# self.retranslate_acoustic_inversion_tab()
#
# # ---------------------------------------------------------------------------------------------
# # -------------------- Functions --------------------
# # ---------------------------------------------------------------------------------------------
#
# ----------------------------------------------------------------------------------------------------------------
# -------------------- Functions --------------------
# def retranslate_acoustic_inversion_tab(self):
#
# self.groupbox_AcousticInversionOption.setTitle(_translate("CONSTANT_STRING", cs.ACOUSTIC_INVERSION_OPTIONS))
# self.groupbox_sediment_concentration_2Dplot.setTitle(_translate("CONSTANT_STRING", cs.FINE_AND_SAND_SEDIMENTS_CONCENTRATION_2D_FIELD))
# self.groupbox_sediment_concentration_sample_vs_measurement.setTitle(_translate("CONSTANT_STRING", cs.SUSPENDED_SEDIMENT_CONCENTRATION_PLOT))
#
# def plot_SSC_fine(self):
# frequency = 0
# val_min = 1e-2 #np.nanmin(self.model.SSC_fine[:, :]) #
# val_max = 15 #np.nanmax(self.model.SSC_fine[:, :]) #
# # print('val_min=', val_min)
# # print('val_max=', val_max)
# # if val_min == 0:
# # val_min = 0.5
# # print('val_min update =', val_min)
# pcm_SSC_fine = self.axis_SSC_2Dplot[0].pcolormesh(self.model.dist_BS_section, np.flipud(self.model.BS_averaged_cross_section.r),
# self.model.SSC_fine[:, :],
# cmap='rainbow', norm=LogNorm(vmin=val_min, vmax=val_max), shading='gouraud')
# self.axis_SSC_2Dplot[0].plot(self.model.dist_BS_section,
# np.max(self.model.r_bottom_cross_section) - self.model.r_bottom_cross_section
# + np.min(self.model.r_bottom_cross_section),
# color='k', linewidth=2)
# self.figure_SSC_2Dplot.supxlabel("Distance from left bank (m)", fontsize=10)
# self.figure_SSC_2Dplot.supylabel("Depth (m)", fontsize=10)
# self.figure_SSC_2Dplot.tight_layout()
#
# cbar_SSC_fine = self.figure_SSC_2Dplot.colorbar(pcm_SSC_fine, ax=self.axis_SSC_2Dplot[0], shrink=1, location='right')
# cbar_SSC_fine.set_label(label='Fine SSC (g/L', rotation=270, labelpad=15)
#
# def plot_SSC_sand(self):
# frequency = 0
# val_min = 1e-2 #np.nanmin(self.model.SSC_fine[:, :]) #
# val_max = 2 #np.nanmax(self.model.SSC_fine[:, :]) #
# # print('val_min=', val_min)
# # print('val_max=', val_max)
# # if val_min == 0:
# # val_min = 0.5
# # print('val_min update =', val_min)
# pcm_SSC_sand = self.axis_SSC_2Dplot[1].pcolormesh(self.model.dist_BS_section, np.flipud(self.model.BS_averaged_cross_section.r),
# self.model.SSC_sand[:, :],
# cmap='rainbow', norm=LogNorm(vmin=val_min, vmax=val_max), shading='gouraud')
# self.axis_SSC_2Dplot[1].plot(self.model.dist_BS_section,
# np.max(self.model.r_bottom_cross_section) - self.model.r_bottom_cross_section
# + np.min(self.model.r_bottom_cross_section),
# color='k', linewidth=2)
# self.figure_SSC_2Dplot.supxlabel("Distance from left bank (m)", fontsize=10)
# self.figure_SSC_2Dplot.supylabel("Depth (m)", fontsize=10)
# self.figure_SSC_2Dplot.tight_layout()
#
# cbar_SSC_sand = self.figure_SSC_2Dplot.colorbar(pcm_SSC_sand, ax=self.axis_SSC_2Dplot[1], shrink=1, location='right')
# cbar_SSC_sand.set_label(label='Sand SSC (g/L', rotation=270, labelpad=15)
#
# # if __name__ == "__main__":
# # app = QApplication(sys.argv)
# # print("class acoustic inversion tab :", AcousticInversionTab())
# # sys.exit(app.exec_())
#
#
def acoustic_inversion_method_choice(self):
if self.combobox_acoustic_inversion_method_choice.currentIndex() == 1:
# --- add items in combobox of samples to calibrate acoustic inversion method ---
samples_vertical_line = np.split(stg.samples, np.where(np.diff(stg.sample_time) != 0)[0]+1)
for s in samples_vertical_line:
self.combobox_calibration_samples.addItem(" - ".join([i for i in s]))
for i in range(len(samples_vertical_line)):
self.combobox_calibration_samples.setItemChecked(i, False)
# --- add items in combobox of frequencies for VBI computation ---
for k in combinations(stg.freq_text, 2):
self.combobox_frequencies_VBI.addItem(k[0] + " - " + k[1])
# print(k)
for i in range(len(list(combinations(stg.freq_text, 2)))):
self.combobox_frequencies_VBI.setItemChecked(i, False)
def sample_choice(self):
sample_position = []
for i in range(self.combobox_calibration_samples.count()):
if self.combobox_calibration_samples.itemChecked(i):
sample_position.append(i)
elif (i in sample_position) and (not self.combobox_calibration_samples.itemChecked(i)):
sample_position.remove(i)
def frequencies_pair_choice_to_compute_VBI(self):
freq_combination = list(combinations(stg.freq, 2))
frequencies_position = []
for i in range(self.combobox_frequencies_VBI.count()):
if self.combobox_frequencies_VBI.itemChecked(i):
frequencies_position.append(i)
elif (i in frequencies_position) and (not self.combobox_frequencies_VBI.itemChecked(i)):
frequencies_position.remove(i)
if len(frequencies_position) != 0:
# print(frequencies_position)
# print(freq_combination[frequencies_position[0]][0], freq_combination[frequencies_position[0]][1])
stg.frequencies_pair = (
np.array([[int(np.where(stg.freq == freq_combination[frequencies_position[0]][0])[0][0]),
freq_combination[frequencies_position[0]][0]],
[int(np.where(stg.freq == freq_combination[frequencies_position[0]][1])[0][0]),
freq_combination[frequencies_position[0]][1]]]))
# print(type(stg.frequencies_pair))
# print(stg.frequencies_pair)
# print(stg.frequencies_pair[1, 0])
# print(type(stg.frequencies_pair[0]), stg.frequencies_pair[0],
# np.where(stg.freq == stg.frequencies_pair[0])[0][0])
# print(type(stg.frequencies_pair[1]), stg.frequencies_pair[1],
# np.where(stg.freq == stg.frequencies_pair[1])[0][0])
# --- add items in combobox of frequency for SSC computation ---
for k in range(stg.frequencies_pair.shape[0]):
self.combobox_frequency_SSC.addItem(str(1e-6*stg.frequencies_pair[k, 1]) + " MHz")
for i in range(stg.frequencies_pair.shape[0]):
self.combobox_frequency_SSC.setItemChecked(i, False)
def frequency_choice_to_compute_SSC(self, index):
# print(self.combobox_frequency_SSC.currentText())
# print(self.combobox_frequency_SSC.currentIndex())
# print(self.combobox_frequency_SSC.itemChecked(index))
if self.combobox_frequency_SSC.itemChecked(index):
# # itemChecked(index)): # currentIndex() == 0) or (self.combobox_frequency_SSC.currentIndex() == 1):
# print(self.combobox_frequency_SSC.currentText())
# print(stg.freq_text)
# print(np.where(np.array(stg.freq_text) == self.combobox_frequency_SSC.currentText()))
stg.frequency_to_compute_SSC \
= np.array([int(np.where(np.array(stg.freq_text) == self.combobox_frequency_SSC.currentText())[0][0]),
stg.freq[int(np.where(np.array(stg.freq_text) == self.combobox_frequency_SSC.currentText())[0][0])]])
# print("stg.frequency_to_compute_SSC ", stg.frequency_to_compute_SSC)
def temperature_value(self):
stg.temperature = self.spinbox_temperature.value()
# print(stg.temperature)
def compute_acoustic_inversion_method_high_concentration(self):
stg.water_attenuation = self.inv_hc.water_attenuation(stg.frequencies_pair[0, 1], stg.frequencies_pair[1, 1], stg.temperature)
# print("water attenuation ", stg.water_attenuation)
stg.water_velocity = self.inv_hc.water_velocity(stg.temperature)
# print("water velocity ", stg.water_velocity)
stg.kt_corrected = self.inv_hc.kt_corrected(stg.r, stg.water_velocity,
stg.gain_rx[[int(stg.frequencies_pair[0, 0]), int(stg.frequencies_pair[1, 0])]],
stg.gain_tx[[int(stg.frequencies_pair[0, 0]), int(stg.frequencies_pair[1, 0])]],
stg.kt[[int(stg.frequencies_pair[0, 0]), int(stg.frequencies_pair[1, 0])]])
# print("kt ", stg.kt_corrected)
# print("kt shape ", stg.kt_corrected.shape)
stg.kt_corrected_2D = np.repeat(stg.kt_corrected, stg.r.shape[0], axis=0)
# print("kt 2D ", stg.kt_corrected_2D)
# print("kt 2D shape ", stg.kt_corrected_2D.shape)
stg.kt_corrected_3D = np.zeros((stg.kt_corrected_2D.shape[1], stg.kt_corrected_2D.shape[0], stg.t.shape[0]))
# print("stg.t.shape ", stg.t.shape)
# print("kt corrected 3D zeros shape ", stg.kt_corrected_3D.shape)
for k in range(stg.kt_corrected_2D.shape[1]):
stg.kt_corrected_3D[k, :, :] = np.repeat(stg.kt_corrected_2D, stg.t.shape[0], axis=1)[:, k*stg.t.shape[0]:(k+1)*stg.t.shape[0]]
print("kt 3D ", stg.kt_corrected_3D)
print("kt 3D shape ", stg.kt_corrected_3D.shape)
# print("kt 2D", np.repeat(stg.kt_corrected[:, :, np.newaxis], stg.t.shape[0], axis=2))
stg.J_cross_section = self.inv_hc.j_cross_section(stg.BS_data[:, [int(stg.frequencies_pair[0, 0]), int(stg.frequencies_pair[0, 0])], :],
stg.r_2D,
stg.kt_corrected_3D)
print("J ", stg.J_cross_section)
print("J sahpe ", stg.J_cross_section.shape)
stg.X_exponent = self.inv_hc.X_exponent(self.combobox_frequencies_VBI.currentIndex())
print("X ", stg.X_exponent)
stg.zeta = self.inv_hc.zeta(int(stg.frequencies_pair[0, 0]), int(stg.frequencies_pair[1, 0]))
print("zeta ", stg.zeta)
# print("stg.frequencies_pair ", stg.frequencies_pair)
# print("stg.frequencies_pair[0, 0]", int(stg.frequencies_pair[0, 0]))
# print("int(stg.frequencies_pair[1, 0]", int(stg.frequencies_pair[1, 0]))
stg.ks = self.inv_hc.ks(int(stg.frequency_to_compute_SSC[0]))
print("ks ", stg.ks)
stg.VBI_cross_section = self.inv_hc.VBI_cross_section(stg.frequencies_pair[0, 1], stg.frequencies_pair[1, 1],
stg.zeta[0], # zeta is already limited to the frequencies pairs so that we just need to select indices 0 and 1
stg.zeta[1],
stg.J_cross_section[0, :, :],
stg.J_cross_section[1, :, :],
stg.r_2D,
stg.water_attenuation[0],
stg.water_attenuation[1],
stg.X_exponent)
# print("VBI shape ", stg.VBI_cross_section.shape)
# print(int(self.combobox_frequency_SSC.currentIndex()))
# print(stg.zeta[int(self.combobox_frequency_SSC.currentIndex())])
stg.SSC_fine = self.inv_hc.SSC_fine(stg.zeta[int(self.combobox_frequency_SSC.currentIndex())],
stg.r_2D,
stg.VBI_cross_section,
stg.frequency_to_compute_SSC[1],
stg.X_exponent,
stg.J_cross_section[self.combobox_frequency_SSC.currentIndex(), :, :])
# print("SSC fine shape ", stg.SSC_fine.shape)
stg.SSC_sand = self.inv_hc.SSC_sand(stg.VBI_cross_section,
stg.frequency_to_compute_SSC[1],
stg.X_exponent,
stg.ks)
# print("SSC sand shape ", stg.SSC_sand.shape)
def plot_SSC_2D_fields(self):
if self.canvas_SSC_2D_field == None:
self.figure_SSC_2D_field, self.axis_SSC_2D_field = plt.subplots(nrows=2, ncols=1, layout="constrained")
self.canvas_SSC_2D_field = FigureCanvas(self.figure_SSC_2D_field)
self.verticalLayout_groupbox_SSC_2D_field.addWidget(self.canvas_SSC_2D_field)
self.plot_SSC_fine()
self.plot_SSC_sand()
def plot_SSC_fine(self):
val_min = 1e-2 #np.nanmin(self.model.SSC_fine[:, :]) #
val_max = 15 #np.nanmax(self.model.SSC_fine[:, :]) #
# print('val_min=', val_min)
# print('val_max=', val_max)
# if val_min == 0:
# val_min = 0.5
# print('val_min update =', val_min)
pcm_SSC_fine = self.axis_SSC_2D_field[0].pcolormesh(stg.t, -stg.r, stg.J_cross_section[0, :, :],
cmap='rainbow',
# norm=LogNorm(vmin=val_min, vmax=val_max),
shading='gouraud')
self.axis_SSC_2D_field[0].plot(stg.t, -stg.r_bottom, color='black', linewidth=1, linestyle="solid")
self.figure_SSC_2D_field.supxlabel("Time (sec)", fontsize=10)
self.figure_SSC_2D_field.supylabel("Depth (m)", fontsize=10)
cbar_SSC_fine = self.figure_SSC_2D_field.colorbar(pcm_SSC_fine, ax=self.axis_SSC_2D_field[0], shrink=1, location='right')
cbar_SSC_fine.set_label(label='Fine SSC (g/L', rotation=270, labelpad=15)
self.figure_SSC_2D_field.canvas.draw_idle()
def plot_SSC_sand(self):
val_min = np.nanmin(stg.VBI_cross_section) #1e-2 #np.nanmin(self.model.SSC_fine[:, :]) #
val_max = np.nanmax(stg.VBI_cross_section) #15 #np.nanmax(self.model.SSC_fine[:, :]) #
# print('val_min=', val_min)
# print('val_max=', val_max)
# if val_min == 0:
# val_min = 0.5
# print('val_min update =', val_min)
pcm_SSC_sand = self.axis_SSC_2D_field[1].pcolormesh(stg.t, -stg.r, stg.J_cross_section[1, :, :],
cmap='rainbow',
# vmin=val_min, vmax=val_max,
# norm=LogNorm(vmin=val_min, vmax=val_max),
shading='gouraud')
self.axis_SSC_2D_field[1].plot(stg.t, -stg.r_bottom, color='black', linewidth=1, linestyle="solid")
self.figure_SSC_2D_field.supxlabel("Time (sec)", fontsize=10)
self.figure_SSC_2D_field.supylabel("Depth (m)", fontsize=10)
cbar_SSC_sand = self.figure_SSC_2D_field.colorbar(pcm_SSC_sand, ax=self.axis_SSC_2D_field[1], shrink=1, location='right')
cbar_SSC_sand.set_label(label='Sand SSC (g/L', rotation=270, labelpad=15)
self.figure_SSC_2D_field.canvas.draw_idle()
def plot_SSC_inverse_VS_measured(self):
sample_depth_position = []
for i in range(stg.sample_depth.shape[0]):
sample_depth_position.append(
np.where(np.abs(stg.r + stg.sample_depth[i]) == np.min(np.abs(stg.r + stg.sample_depth[i])))[0][0])
sample_time_position = []
for j in range(stg.sample_time.shape[0]):
sample_time_position.append(
np.where(np.abs(stg.t - stg.sample_time[j]) == np.min(np.abs(stg.t - stg.sample_time[j])))[0][0])
if self.canvas_SSC_sample_vs_inversion == None:
self.figure_SSC_sample_vs_inversion, self.axis_SSC_sample_vs_inversion = plt.subplots(nrows=1, ncols=1, layout="constrained")
self.canvas_SSC_sample_vs_inversion = FigureCanvas(self.figure_SSC_sample_vs_inversion)
self.verticalLayout_groupbox_SSC_sample_vs_inversion.addWidget(self.canvas_SSC_sample_vs_inversion)
self.axis_SSC_sample_vs_inversion.plot(stg.Ctot_fine, stg.SSC_fine[sample_depth_position, sample_time_position], ls=" ", marker='v', color='black', label='Fine SSC')
self.axis_SSC_sample_vs_inversion.plot(stg.Ctot_sand, stg.SSC_sand[sample_depth_position, sample_time_position], ls=" ", marker='x', color='black', label='Sand SSC')
self.axis_SSC_sample_vs_inversion.set_xscale('log')
self.axis_SSC_sample_vs_inversion.set_yscale('log')
self.axis_SSC_sample_vs_inversion.plot([0.5e-2, 20], [0.5e-2, 20], color='black', lw=1)
self.axis_SSC_sample_vs_inversion.set_xlabel('Measured SSC (g/l)', weight='bold')
self.axis_SSC_sample_vs_inversion.set_ylabel('Inverse SSC (g/l)', weight='bold')
self.axis_SSC_sample_vs_inversion.legend()

View File

@ -0,0 +1,33 @@
from PyQt5.QtWidgets import QComboBox
from PyQt5.QtCore import Qt
class CheckableComboBox(QComboBox):
def __init__(self):
super().__init__()
self._changed = False
self.view().pressed.connect(self.handleItemPressed)
def setItemChecked(self, index, checked=False):
item = self.model().item(index, self.modelColumn()) # QStandardItem object
if checked:
item.setCheckState(Qt.Checked)
else:
item.setCheckState(Qt.Unchecked)
def handleItemPressed(self, index):
item = self.model().itemFromIndex(index)
if item.checkState() == Qt.Checked:
item.setCheckState(Qt.Unchecked)
else:
item.setCheckState(Qt.Checked)
self._changed = True
def hidePopup(self):
if not self._changed:
super().hidePopup()
self._changed = False
def itemChecked(self, index):
item = self.model().item(index, self.modelColumn())
return item.checkState() == Qt.Checked

View File

@ -415,8 +415,9 @@ class SampleDataTab(QWidget):
# horizontal_header = list(map(str, ["Color", "Sample"] + stg.fine_sediment_columns +
# stg.sand_sediment_columns[2:]))
horizontal_header = list(itertools.chain(["Color", "Sample"],
list(map(str, stg.fine_sediment_columns.values)),
list(map(str, stg.sand_sediment_columns[2:]))))
list(map(str, stg.fine_sediment_columns[:2])),
list(map(str, stg.fine_sediment_columns[3:])),
list(map(str, stg.sand_sediment_columns[3:]))))
for horizontal_header_text in horizontal_header:
# print(horizontal_header_text)
@ -447,7 +448,8 @@ class SampleDataTab(QWidget):
self.item_checkbox = QTableWidgetItem()
self.item_checkbox.setCheckState(Qt.Unchecked)
self.tableWidget_sample.setItem(i, 1, self.item_checkbox)
self.item_checkbox.setText("S " + str(i + 1))
self.item_checkbox.setText("S" + str(i + 1))
stg.samples.append("S" + str(i + 1))
# print(f"S{i+1} ", self.tableWidget_sample.item(i, 1).checkState())
# --- Fill table with data ---

View File

@ -1,7 +1,7 @@
import sys
from PyQt5.QtWidgets import QWidget, QHBoxLayout, QVBoxLayout, QPushButton, QGroupBox, QLabel, QCheckBox, \
QSpinBox, QDoubleSpinBox, QComboBox, QLineEdit, QSlider, QGridLayout
QSpinBox, QDoubleSpinBox, QComboBox, QLineEdit, QSlider, QGridLayout, QMessageBox
from PyQt5.QtGui import QFont, QIcon, QPixmap
from PyQt5.QtCore import Qt, QCoreApplication
@ -83,7 +83,7 @@ class SignalProcessingTab(QWidget):
self.pushbutton_load_data = QPushButton()
self.horizontalLayout_pushbutton_load_data_plot_bottom_line.addWidget(self.pushbutton_load_data)
self.pushbutton_load_data.clicked.connect(self.plot_profile_position_on_transect)
self.pushbutton_load_data.clicked.connect(self.plot_profiles)
self.pushbutton_load_data.clicked.connect(self.plot_profile)
self.combobox_frequency = QComboBox()
self.horizontalLayout_pushbutton_load_data_plot_bottom_line.addWidget(self.combobox_frequency)
@ -162,26 +162,27 @@ class SignalProcessingTab(QWidget):
self.gridLayout_groupbox_acoustic_profile = QGridLayout(self.groupbox_acoustic_profile)
self.checkbox_SNR_criterion = QCheckBox()
self.gridLayout_groupbox_acoustic_profile.addWidget(self.checkbox_SNR_criterion, 0, 0, 1, 1)
# self.checkbox_SNR_criterion = QCheckBox()
self.label_SNR_criterion = QLabel()
self.gridLayout_groupbox_acoustic_profile.addWidget(self.label_SNR_criterion, 0, 0, 1, 1)
self.spinbox_SNR_criterion = QSpinBox()
self.spinbox_SNR_criterion.setRange(0, 9999)
self.spinbox_SNR_criterion.setValue(0)
self.spinbox_SNR_criterion.setDisabled(True)
# self.spinbox_SNR_criterion.setDisabled(True)
self.gridLayout_groupbox_acoustic_profile.addWidget(self.spinbox_SNR_criterion, 0, 1, 1, 1)
self.checkbox_SNR_criterion.clicked.connect(self.enable_disable_spinbox_snr_value)
# self.checkbox_SNR_criterion.clicked.connect(self.enable_disable_spinbox_snr_value)
self.spinbox_SNR_criterion.valueChanged.connect(self.remove_point_with_snr_filter)
self.pushbutton_snr_filter = QPushButton()
self.pushbutton_snr_filter.setText("Apply SNR")
self.pushbutton_snr_filter.setDisabled(True)
# self.pushbutton_snr_filter.setDisabled(True)
self.gridLayout_groupbox_acoustic_profile.addWidget(self.pushbutton_snr_filter, 0, 2, 1, 1)
self.spinbox_SNR_criterion.valueChanged.connect(self.remove_point_with_snr_filter)
# self.spinbox_SNR_criterion.valueChanged.connect(self.update_plot_profiles)
# self.spinbox_SNR_criterion.valueChanged.connect(self.update_plot_profile_position_on_transect)
self.pushbutton_snr_filter.clicked.connect(self.update_plot_profiles)
self.pushbutton_snr_filter.clicked.connect(self.update_plot_profile)
# self.pushbutton_snr_filter.clicked.connect(self.remove_point_with_snr_filter)
# self.pushbutton_snr_filter.clicked.connect(self.update_plot_profile_position_on_transect)
@ -190,7 +191,7 @@ class SignalProcessingTab(QWidget):
self.horizontalLayout_groupbox_window_size = QHBoxLayout(self.groupbox_window_size)
self.label_signal_averaging_over = QLabel()
self.label_signal_averaging_over.setText("Signal averaging over ")
self.label_signal_averaging_over.setText("Signal averaging over +/- ")
self.horizontalLayout_groupbox_window_size.addWidget(self.label_signal_averaging_over)
self.spinbox_average = QSpinBox()
self.spinbox_average.setRange(0, 9999)
@ -199,6 +200,15 @@ class SignalProcessingTab(QWidget):
self.label_cells = QLabel()
self.horizontalLayout_groupbox_window_size.addWidget(self.label_cells)
self.spinbox_average.valueChanged.connect(self.compute_averaged_profile)
self.pushbutton_average = QPushButton()
self.pushbutton_average.setText("Apply averaging")
# self.pushbutton_snr_filter.setDisabled(True)
self.horizontalLayout_groupbox_window_size.addWidget(self.pushbutton_average)
self.pushbutton_average.clicked.connect(self.plot_averaged_profile)
# --- Groupbox Rayleigh criterion ---
# # self.groupbox_rayleigh_criterion.setTitle("Rayleigh criterion")
@ -566,7 +576,8 @@ class SignalProcessingTab(QWidget):
self.slider.valueChanged.connect(self.update_lineEdit_by_moving_slider)
self.slider.valueChanged.connect(self.update_plot_profile_position_on_transect)
self.slider.valueChanged.connect(self.update_plot_profiles)
self.slider.valueChanged.connect(self.update_plot_profile)
self.slider.valueChanged.connect(self.update_plot_averaged_profile)
self.retranslate_signal_processing_tab()
@ -583,7 +594,7 @@ class SignalProcessingTab(QWidget):
self.groupbox_acoustic_profile.setTitle(_translate("CONSTANT_STRING", cs.ACOUSTIC_PROFILE))
# self.checkbox_substract_noise.setText(_translate("CONSTANT_STRING", cs.SUBTRACT_THE_NOISE))
self.checkbox_SNR_criterion.setText(_translate("CONSTANT_STRING", cs.SNR_CRITERION))
self.label_SNR_criterion.setText(_translate("CONSTANT_STRING", cs.SNR_CRITERION))
#
self.groupbox_window_size.setTitle(_translate("CONSTANT_STRING", cs.WINDOW_SIZE))
# self.label_averageH.setText(_translate("CONSTANT_STRING", cs.HORIZONTAL) + ": +/-")
@ -621,13 +632,13 @@ class SignalProcessingTab(QWidget):
def update_lineEdit_by_moving_slider(self):
self.lineEdit_slider.setText(str(self.slider.value()))
def enable_disable_spinbox_snr_value(self):
if self.checkbox_SNR_criterion.isChecked():
self.spinbox_SNR_criterion.setEnabled(True)
self.pushbutton_snr_filter.setEnabled(True)
else:
self.spinbox_SNR_criterion.setDisabled(True)
self.pushbutton_snr_filter.setDisabled(True)
# def enable_disable_spinbox_snr_value(self):
# if self.checkbox_SNR_criterion.isChecked():
# self.spinbox_SNR_criterion.setEnabled(True)
# self.pushbutton_snr_filter.setEnabled(True)
# else:
# self.spinbox_SNR_criterion.setDisabled(True)
# self.pushbutton_snr_filter.setDisabled(True)
def remove_point_with_snr_filter(self):
@ -654,56 +665,56 @@ class SignalProcessingTab(QWidget):
self.canvas_plot_profile_position_on_transect = FigureCanvas(self.figure_plot_profile_position_on_transect)
self.verticalLayout_groupbox_display_profile_position.addWidget(self.canvas_plot_profile_position_on_transect)
if stg.r_bottom.size == 0:
# if stg.r_bottom.size == 0:
val_min = np.min(stg.BS_data[:, stg.freq_bottom_detection, :])
val_max = np.max(stg.BS_data[:, stg.freq_bottom_detection, :])
if val_min == 0:
val_min = 1e-5
val_min = np.min(stg.BS_data[:, stg.freq_bottom_detection, :])
val_max = np.max(stg.BS_data[:, stg.freq_bottom_detection, :])
if val_min == 0:
val_min = 1e-5
pcm = self.axis_plot_profile_position_on_transect.pcolormesh(
stg.t, -stg.r, stg.BS_data[:, stg.freq_bottom_detection, :],
cmap='viridis', norm=LogNorm(vmin=val_min, vmax=val_max))
if stg.r_bottom.size != 0:
self.axis_plot_profile_position_on_transect.plot(
stg.t, -stg.r_bottom, color='black', linewidth=1, linestyle="solid")
pcm = self.axis_plot_profile_position_on_transect.pcolormesh(
stg.t, -stg.r, stg.BS_data[:, stg.freq_bottom_detection, :],
cmap='viridis', norm=LogNorm(vmin=val_min, vmax=val_max))
if stg.r_bottom.size != 0:
self.axis_plot_profile_position_on_transect.plot(
stg.t[self.slider.value() - 1] * np.ones(stg.r.shape[0]), -stg.r,
color='red', linestyle="solid", linewidth=2)
stg.t, -stg.r_bottom, color='black', linewidth=1, linestyle="solid")
self.figure_plot_profile_position_on_transect.canvas.draw_idle()
self.axis_plot_profile_position_on_transect.plot(
stg.t[self.slider.value() - 1] * np.ones(stg.r.shape[0]), -stg.r,
color='red', linestyle="solid", linewidth=2)
else:
self.figure_plot_profile_position_on_transect.canvas.draw_idle()
stg.BS_data_section = deepcopy(stg.BS_data)
# else:
for f in range(stg.freq.shape[0]):
for k in range(stg.r_bottom.shape[0]):
# print(k, np.where(stg.r >= stg.r_bottom[k])[0])
stg.BS_data_section[np.where(stg.r >= stg.r_bottom[k])[0], f, k] \
= np.nan
# print("----------------------------------------------------------")
# stg.BS_data_section = deepcopy(stg.BS_data)
val_min = np.min(stg.BS_data_section[:, stg.freq_bottom_detection, :])
val_max = np.max(stg.BS_data_section[:, stg.freq_bottom_detection, :])
if val_min == 0:
val_min = 1e-5
# for f in range(stg.freq.shape[0]):
# for k in range(stg.r_bottom.shape[0]):
# # print(k, np.where(stg.r >= stg.r_bottom[k])[0])
# stg.BS_data_section[np.where(stg.r >= stg.r_bottom[k])[0], f, k] \
# = np.nan
# # print("----------------------------------------------------------")
pcm = self.axis_plot_profile_position_on_transect.pcolormesh(
stg.t, -stg.r, stg.BS_data_section[:, stg.freq_bottom_detection, :],
cmap='viridis', norm=LogNorm(vmin=val_min, vmax=val_max))
if stg.r_bottom.size != 0:
self.axis_plot_profile_position_on_transect.plot(
stg.t, -stg.r_bottom, color='black', linewidth=1, linestyle="solid")
self.axis_plot_profile_position_on_transect.plot(
stg.t[self.slider.value() - 1] * np.ones(stg.r.shape[0]), -stg.r,
color='red', linestyle="solid", linewidth=2)
self.figure_plot_profile_position_on_transect.canvas.draw_idle()
# val_min = np.min(stg.BS_data_section[:, stg.freq_bottom_detection, :])
# val_max = np.max(stg.BS_data_section[:, stg.freq_bottom_detection, :])
# if val_min == 0:
# val_min = 1e-5
#
# pcm = self.axis_plot_profile_position_on_transect.pcolormesh(
# stg.t, -stg.r, stg.BS_data_section[:, stg.freq_bottom_detection, :],
# cmap='viridis', norm=LogNorm(vmin=val_min, vmax=val_max))
#
# if stg.r_bottom.size != 0:
# self.axis_plot_profile_position_on_transect.plot(
# stg.t, -stg.r_bottom, color='black', linewidth=1, linestyle="solid")
#
# self.axis_plot_profile_position_on_transect.plot(
# stg.t[self.slider.value() - 1] * np.ones(stg.r.shape[0]), -stg.r,
# color='red', linestyle="solid", linewidth=2)
#
# self.figure_plot_profile_position_on_transect.canvas.draw_idle()
def update_plot_profile_position_on_transect(self):
@ -714,55 +725,55 @@ class SignalProcessingTab(QWidget):
# --- Update transect plot ---
if self.canvas_plot_profile_position_on_transect != None:
# if stg.r_bottom.size != 0:
self.axis_plot_profile_position_on_transect.cla()
val_min = np.min(stg.BS_data[:, self.combobox_frequency.currentIndex(), :])
val_max = np.max(stg.BS_data[:, self.combobox_frequency.currentIndex(), :])
if val_min == 0:
val_min = 1e-5
self.axis_plot_profile_position_on_transect.pcolormesh(
stg.t, -stg.r, stg.BS_data[:, self.combobox_frequency.currentIndex(), :],
cmap='viridis', norm=LogNorm(vmin=val_min, vmax=val_max))
if stg.r_bottom.size != 0:
self.axis_plot_profile_position_on_transect.cla()
val_min = np.min(stg.BS_data_section[:, self.combobox_frequency.currentIndex(), :])
val_max = np.max(stg.BS_data_section[:, self.combobox_frequency.currentIndex(), :])
if val_min == 0:
val_min = 1e-5
pcm = self.axis_plot_profile_position_on_transect.pcolormesh(
stg.t, -stg.r, stg.BS_data_section[:, self.combobox_frequency.currentIndex(), :],
cmap='viridis', norm=LogNorm(vmin=val_min, vmax=val_max))
if stg.r_bottom.size != 0:
self.axis_plot_profile_position_on_transect.plot(
stg.t, -stg.r_bottom,
color='black', linewidth=1, linestyle="solid")
self.axis_plot_profile_position_on_transect.plot(
stg.t[self.slider.value() - 1] * np.ones(stg.r.shape[0]), -stg.r,
color='red', linestyle="solid", linewidth=2)
stg.t, -stg.r_bottom,
color='black', linewidth=1, linestyle="solid")
self.figure_plot_profile_position_on_transect.canvas.draw_idle()
self.axis_plot_profile_position_on_transect.plot(
stg.t[self.slider.value() - 1] * np.ones(stg.r.shape[0]), -stg.r,
color='red', linestyle="solid", linewidth=2)
else:
self.figure_plot_profile_position_on_transect.canvas.draw_idle()
self.axis_plot_profile_position_on_transect.cla()
# else:
#
# self.axis_plot_profile_position_on_transect.cla()
#
# val_min = np.min(stg.BS_data[:, self.combobox_frequency.currentIndex(), :])
# val_max = np.max(stg.BS_data[:, self.combobox_frequency.currentIndex(), :])
# if val_min == 0:
# val_min = 1e-5
#
# pcm = self.axis_plot_profile_position_on_transect.pcolormesh(
# stg.t, -stg.r, stg.BS_data[:, self.combobox_frequency.currentIndex(), :],
# cmap='viridis', norm=LogNorm(vmin=val_min, vmax=val_max))
#
# if stg.r_bottom.size != 0:
# self.axis_plot_profile_position_on_transect.plot(
# stg.t, -stg.r_bottom,
# color='black', linewidth=1, linestyle="solid")
#
# self.axis_plot_profile_position_on_transect.plot(
# stg.t[self.slider.value()-1] * np.ones(stg.r.shape[0]), -stg.r,
# color='red', linestyle="solid", linewidth=2)
#
# self.figure_plot_profile_position_on_transect.canvas.draw_idle()
val_min = np.min(stg.BS_data[:, self.combobox_frequency.currentIndex(), :])
val_max = np.max(stg.BS_data[:, self.combobox_frequency.currentIndex(), :])
if val_min == 0:
val_min = 1e-5
pcm = self.axis_plot_profile_position_on_transect.pcolormesh(
stg.t, -stg.r, stg.BS_data[:, self.combobox_frequency.currentIndex(), :],
cmap='viridis', norm=LogNorm(vmin=val_min, vmax=val_max))
if stg.r_bottom.size != 0:
self.axis_plot_profile_position_on_transect.plot(
stg.t, -stg.r_bottom,
color='black', linewidth=1, linestyle="solid")
self.axis_plot_profile_position_on_transect.plot(
stg.t[self.slider.value()-1] * np.ones(stg.r.shape[0]), -stg.r,
color='red', linestyle="solid", linewidth=2)
self.figure_plot_profile_position_on_transect.canvas.draw_idle()
def plot_profiles(self):
def plot_profile(self):
# --- Raw profile ---
@ -786,51 +797,46 @@ class SignalProcessingTab(QWidget):
self.figure_profile.canvas.draw_idle()
# --- Raw averaged profile ---
# # --- Raw averaged profile ---
#
# self.figure_averaged_profile, self.axis_averaged_profile \
# = plt.subplots(nrows=1, ncols=stg.freq.shape[0], layout='constrained')
# self.canvas_averaged_profile = FigureCanvas(self.figure_averaged_profile)
# self.verticalLayout_groupbox_plot_averaged_profile.addWidget(self.canvas_averaged_profile)
#
# for f in range(stg.freq.shape[0]):
# self.axis_averaged_profile[f].cla()
# self.axis_averaged_profile[f].plot(stg.BS_data[:, f, self.slider.value() - 1], -stg.r,
# linestyle='solid', color='k', linewidth=1)
# self.axis_averaged_profile[f].set_ylim(-np.max(stg.r), np.min(stg.r))
self.figure_averaged_profile, self.axis_averaged_profile \
= plt.subplots(nrows=1, ncols=stg.freq.shape[0], layout='constrained')
self.canvas_averaged_profile = FigureCanvas(self.figure_averaged_profile)
self.verticalLayout_groupbox_plot_averaged_profile.addWidget(self.canvas_averaged_profile)
# # --- Raw FCB profile ---
#
# self.figure_FCB_profile, self.axis_FCB_profile \
# = plt.subplots(nrows=1, ncols=stg.freq.shape[0], layout='constrained')
# self.canvas_FCB_profile = FigureCanvas(self.figure_FCB_profile)
# self.verticalLayout_groupbox_plot_FCB_profile.addWidget(self.canvas_FCB_profile)
for f in range(stg.freq.shape[0]):
self.axis_averaged_profile[f].cla()
self.axis_averaged_profile[f].plot(stg.BS_data[:, f, self.slider.value() - 1], -stg.r,
linestyle='solid', color='k', linewidth=1)
self.axis_averaged_profile[f].set_ylim(-np.max(stg.r), np.min(stg.r))
def update_plot_profile(self):
# --- Raw FCB profile ---
# if self.checkbox_SNR_criterion.isChecked():
self.figure_FCB_profile, self.axis_FCB_profile \
= plt.subplots(nrows=1, ncols=stg.freq.shape[0], layout='constrained')
self.canvas_FCB_profile = FigureCanvas(self.figure_FCB_profile)
self.verticalLayout_groupbox_plot_FCB_profile.addWidget(self.canvas_FCB_profile)
# self.remove_point_with_snr_filter()
def update_plot_profiles(self):
if self.checkbox_SNR_criterion.isChecked():
# self.remove_point_with_snr_filter()
if stg.BS_data_filter_snr.size == 0:
for f in range(stg.freq.shape[0]):
self.axis_profile[f].cla()
self.axis_profile[f].plot(stg.BS_data_filter_snr[:, f, self.slider.value()-1], -stg.r,
linestyle='solid', color='k', linewidth=1)
# if stg.r_bottom.size != 0:
# self.axis_profile[f].plot(
# np.array([0, np.nanmax(stg.BS_data[:, stg.freq_bottom_detection, self.slider.value() - 1])]),
# -stg.r_bottom[self.slider.value() - 1] * np.ones(2),
# linestyle='dashed', color='red', linewidth=1)
self.axis_profile[f].plot(stg.BS_data[:, f, self.slider.value()-1], -stg.r,
linestyle='solid', color='k', linewidth=1)
self.axis_profile[f].set_ylim(-np.max(stg.r), np.min(stg.r))
else:
for f in range(stg.freq.shape[0]):
self.axis_profile[f].cla()
self.axis_profile[f].plot(stg.BS_data[:, f, self.slider.value()-1], -stg.r,
linestyle='solid', color='k', linewidth=1)
self.axis_profile[f].plot(stg.BS_data_filter_snr[:, f, self.slider.value()-1], -stg.r,
linestyle='solid', color='k', linewidth=1)
# if stg.r_bottom.size != 0:
# self.axis_profile[f].plot(
@ -840,10 +846,123 @@ class SignalProcessingTab(QWidget):
self.axis_profile[f].set_ylim(-np.max(stg.r), np.min(stg.r))
# else:
#
# for f in range(stg.freq.shape[0]):
# self.axis_profile[f].cla()
# self.axis_profile[f].plot(stg.BS_data[:, f, self.slider.value()-1], -stg.r,
# linestyle='solid', color='k', linewidth=1)
# if stg.r_bottom.size != 0:
# self.axis_profile[f].plot(
# np.array([0, np.nanmax(stg.BS_data[:, stg.freq_bottom_detection, self.slider.value() - 1])]),
# -stg.r_bottom[self.slider.value() - 1] * np.ones(2),
# linestyle='dashed', color='red', linewidth=1)
# self.axis_profile[f].set_ylim(-np.max(stg.r), np.min(stg.r))
self.figure_profile.canvas.draw_idle()
def compute_averaged_profile(self):
pass
filter_convolve = np.ones(self.spinbox_average.value())
if stg.BS_data_filter_snr.size == 0:
stg.BS_data_averaged = np.zeros((stg.r.shape[0], stg.freq.shape[0], stg.t.shape[0]-self.spinbox_average.value()+1))
for f in range(stg.freq.shape[0]):
for i in range(stg.r.shape[0]):
stg.BS_data_averaged[i, f, :] = np.convolve(stg.BS_data[i, f, :], filter_convolve, mode='valid')
# stg.BS_data_averaged = np.concatenate((stg.BS_data[:, :, :np.int(self.spinbox_average.value()/2)],
# stg.BS_data_averaged,
# stg.BS_data[:, :, -np.int(self.spinbox_average.value()/2):]),
# axis=2)
# print(stg.BS_data_averaged.shape)
else:
stg.BS_data_averaged = np.zeros((stg.r.shape[0], stg.freq.shape[0], stg.t.shape[0]-self.spinbox_average.value()+1))
for f in range(stg.freq.shape[0]):
for i in range(stg.r.shape[0]):
stg.BS_data_averaged[i, f, :] = np.convolve(stg.BS_data_filter_snr[i, f, :], filter_convolve,
mode='valid')
self.label_cells.clear()
self.label_cells.setText("cells = +/- " + str((self.spinbox_average.value() // 2)*(1/stg.nb_profiles_per_sec)) + " sec")
def plot_averaged_profile(self):
# fig, ax = plt.subplots(nrows=1, ncols=1)
# ax.pcolormesh(stg.t[8:2232], -stg.r, stg.BS_data_averaged[:, 0, :],
# cmap='viridis',
# norm=LogNorm(vmin=1e-5, vmax=np.max(stg.BS_data_averaged[:, 0, :])))
# plt.show()
if self.canvas_averaged_profile != None:
for f in range(stg.freq.shape[0]):
self.axis_averaged_profile[f].cla()
self.figure_averaged_profile, self.axis_averaged_profile \
= plt.subplots(nrows=1, ncols=stg.freq.shape[0], layout='constrained')
self.canvas_averaged_profile = FigureCanvas(self.figure_averaged_profile)
self.verticalLayout_groupbox_plot_averaged_profile.addWidget(self.canvas_averaged_profile)
if stg.BS_data_filter_snr.size == 0:
BS_concatenate = stg.BS_data_averaged = np.concatenate((stg.BS_data[:, :, :np.int(self.spinbox_average.value()/2)],
stg.BS_data_averaged,
stg.BS_data[:, :, -np.int(self.spinbox_average.value()/2):]),
axis=2)
for f in range(stg.freq.shape[0]):
self.axis_averaged_profile[f].cla()
self.axis_averaged_profile[f].plot(BS_concatenate[:, f, self.slider.value()-1], -stg.r,
linestyle='solid', color='k', linewidth=1)
self.axis_averaged_profile[f].set_ylim(-np.max(stg.r), np.min(stg.r))
else:
BS_concatenate = stg.BS_data_averaged = np.concatenate((stg.BS_data_filter_snr[:, :, :np.int(self.spinbox_average.value() / 2)],
stg.BS_data_averaged,
stg.BS_data_filter_snr[:, :, -np.int(self.spinbox_average.value() / 2):]),
axis=2)
for f in range(stg.freq.shape[0]):
self.axis_averaged_profile[f].cla()
self.axis_averaged_profile[f].plot(BS_concatenate[:, f, self.slider.value() - 1], -stg.r,
linestyle='solid', color='k', linewidth=1)
self.axis_averaged_profile[f].set_ylim(-np.max(stg.r), np.min(stg.r))
self.figure_averaged_profile.canvas.draw_idle()
def update_plot_averaged_profile(self):
if self.canvas_averaged_profile == None:
msgBox = QMessageBox()
msgBox.setWindowTitle("Plot averaged profile Error")
msgBox.setIcon(QMessageBox.Warning)
msgBox.setText("Compute acoustic backscatter averaged data")
msgBox.setStandardButtons(QMessageBox.Ok)
msgBox.exec()
else:
if stg.BS_data_filter_snr.size == 0:
BS_concatenate = stg.BS_data_averaged = np.concatenate(
(stg.BS_data[:, :, :np.int(self.spinbox_average.value() / 2)],
stg.BS_data_averaged,
stg.BS_data[:, :, -np.int(self.spinbox_average.value() / 2):]),
axis=2)
for f in range(stg.freq.shape[0]):
self.axis_averaged_profile[f].cla()
self.axis_averaged_profile[f].plot(BS_concatenate[:, f, self.slider.value() - 1], -stg.r,
linestyle='solid', color='k', linewidth=1)
self.axis_averaged_profile[f].set_ylim(-np.max(stg.r), np.min(stg.r))
else:
BS_concatenate = stg.BS_data_averaged = np.concatenate(
(stg.BS_data_filter_snr[:, :, :np.int(self.spinbox_average.value() / 2)],
stg.BS_data_averaged,
stg.BS_data_filter_snr[:, :, -np.int(self.spinbox_average.value() / 2):]),
axis=2)
for f in range(stg.freq.shape[0]):
self.axis_averaged_profile[f].cla()
self.axis_averaged_profile[f].plot(BS_concatenate[:, f, self.slider.value() - 1], -stg.r,
linestyle='solid', color='k', linewidth=1)
self.axis_averaged_profile[f].set_ylim(-np.max(stg.r), np.min(stg.r))
self.figure_averaged_profile.canvas.draw_idle()
# def plot_transect_bottom_with_profile_position(self, profile_position):
# frequency = self.model.Freq[0]