Compare commits
4 Commits
3c2db523ac
...
24f270a2a4
| Author | SHA1 | Date |
|---|---|---|
|
|
24f270a2a4 | |
|
|
7bf93bb6d8 | |
|
|
69eb051270 | |
|
|
96144d88ee |
|
|
@ -106,7 +106,11 @@ class CreateTableForSaveAs:
|
||||||
rmax_index FLOAT, rmax_value FLOAT,
|
rmax_index FLOAT, rmax_value FLOAT,
|
||||||
freq_bottom_detection_index FLOAT,
|
freq_bottom_detection_index FLOAT,
|
||||||
freq_bottom_detection_value STRING,
|
freq_bottom_detection_value STRING,
|
||||||
SNR_filter_value FLOAT, Nb_cells_to_average_BS_signal FLOAT
|
depth_bottom_detection_min FLOAT,
|
||||||
|
depth_bottom_detection_max FLOAT,
|
||||||
|
depth_bottom_detection_inverval FLOAT,
|
||||||
|
SNR_filter_value FLOAT,
|
||||||
|
Nb_cells_to_average_BS_signal FLOAT
|
||||||
)
|
)
|
||||||
"""
|
"""
|
||||||
|
|
||||||
|
|
@ -195,6 +199,13 @@ class CreateTableForSaveAs:
|
||||||
)
|
)
|
||||||
"""
|
"""
|
||||||
|
|
||||||
|
self.create_Notes = """
|
||||||
|
CREATE TABLE Notes(
|
||||||
|
ID INTEGER PRIMARY KEY AUTOINCREMENT,
|
||||||
|
notes TEXT
|
||||||
|
)
|
||||||
|
"""
|
||||||
|
|
||||||
def save_as(self):
|
def save_as(self):
|
||||||
self.open_file_dialog()
|
self.open_file_dialog()
|
||||||
self.save()
|
self.save()
|
||||||
|
|
@ -247,6 +258,7 @@ class CreateTableForSaveAs:
|
||||||
self.create_table_calibration_parameters(cnx, cur)
|
self.create_table_calibration_parameters(cnx, cur)
|
||||||
self.create_table_calibration(cnx, cur)
|
self.create_table_calibration(cnx, cur)
|
||||||
self.create_table_inversion(cnx, cur)
|
self.create_table_inversion(cnx, cur)
|
||||||
|
self.create_table_notes(cnx, cur)
|
||||||
|
|
||||||
cnx.commit()
|
cnx.commit()
|
||||||
|
|
||||||
|
|
@ -427,9 +439,12 @@ class CreateTableForSaveAs:
|
||||||
tmin_index, tmin_value, tmax_index, tmax_value,
|
tmin_index, tmin_value, tmax_index, tmax_value,
|
||||||
rmin_index, rmin_value, rmax_index, rmax_value,
|
rmin_index, rmin_value, rmax_index, rmax_value,
|
||||||
freq_bottom_detection_index, freq_bottom_detection_value,
|
freq_bottom_detection_index, freq_bottom_detection_value,
|
||||||
|
depth_bottom_detection_min,
|
||||||
|
depth_bottom_detection_max,
|
||||||
|
depth_bottom_detection_inverval,
|
||||||
SNR_filter_value, Nb_cells_to_average_BS_signal
|
SNR_filter_value, Nb_cells_to_average_BS_signal
|
||||||
)
|
)
|
||||||
VALUES(?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)
|
VALUES(?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)
|
||||||
""",
|
""",
|
||||||
(
|
(
|
||||||
stg.acoustic_data[i], stg.temperature,
|
stg.acoustic_data[i], stg.temperature,
|
||||||
|
|
@ -440,6 +455,9 @@ class CreateTableForSaveAs:
|
||||||
stg.rmax[i][0], stg.rmax[i][1],
|
stg.rmax[i][0], stg.rmax[i][1],
|
||||||
stg.freq_bottom_detection[i][0],
|
stg.freq_bottom_detection[i][0],
|
||||||
stg.freq_bottom_detection[i][1],
|
stg.freq_bottom_detection[i][1],
|
||||||
|
stg.depth_bottom_detection_min,
|
||||||
|
stg.depth_bottom_detection_max,
|
||||||
|
stg.depth_bottom_detection_interval,
|
||||||
stg.SNR_filter_value[i],
|
stg.SNR_filter_value[i],
|
||||||
stg.Nb_cells_to_average_BS_signal[i]
|
stg.Nb_cells_to_average_BS_signal[i]
|
||||||
)
|
)
|
||||||
|
|
@ -625,3 +643,25 @@ class CreateTableForSaveAs:
|
||||||
cnx.commit()
|
cnx.commit()
|
||||||
|
|
||||||
logger.info(f"table Inversion : {time.time() - start_table_Inversion} sec")
|
logger.info(f"table Inversion : {time.time() - start_table_Inversion} sec")
|
||||||
|
|
||||||
|
def create_table_notes(self, cnx, cur):
|
||||||
|
start_table = time.time()
|
||||||
|
|
||||||
|
cur.execute("DROP TABLE if exists Notes")
|
||||||
|
|
||||||
|
cur.execute(self.create_Notes)
|
||||||
|
|
||||||
|
for i in range(len(stg.SSC_fine)):
|
||||||
|
cur.execute(
|
||||||
|
"""
|
||||||
|
INSERT into Notes(
|
||||||
|
notes
|
||||||
|
)
|
||||||
|
VALUES(?)
|
||||||
|
""",
|
||||||
|
(stg.notes,)
|
||||||
|
)
|
||||||
|
|
||||||
|
cnx.commit()
|
||||||
|
|
||||||
|
logger.info(f"table Notes : {time.time() - start_table} sec")
|
||||||
|
|
|
||||||
|
|
@ -85,6 +85,7 @@ class ReadTableForOpen:
|
||||||
self.read_table_table_sediment_data()
|
self.read_table_table_sediment_data()
|
||||||
self.read_table_table_calibration_parameters()
|
self.read_table_table_calibration_parameters()
|
||||||
self.read_table_table_calibration()
|
self.read_table_table_calibration()
|
||||||
|
self.read_table_table_notes()
|
||||||
|
|
||||||
logger.debug(f"Reading '{stg.filename_open}' done")
|
logger.debug(f"Reading '{stg.filename_open}' done")
|
||||||
|
|
||||||
|
|
@ -496,23 +497,30 @@ class ReadTableForOpen:
|
||||||
tmin_index, tmin_value, tmax_index, tmax_value,
|
tmin_index, tmin_value, tmax_index, tmax_value,
|
||||||
rmin_index, rmin_value, rmax_index, rmax_value,
|
rmin_index, rmin_value, rmax_index, rmax_value,
|
||||||
freq_bottom_detection_index, freq_bottom_detection_value,
|
freq_bottom_detection_index, freq_bottom_detection_value,
|
||||||
|
depth_bottom_detection_min,
|
||||||
|
depth_bottom_detection_max,
|
||||||
|
depth_bottom_detection_inverval,
|
||||||
SNR_filter_value, Nb_cells_to_average_BS_signal
|
SNR_filter_value, Nb_cells_to_average_BS_signal
|
||||||
FROM Settings
|
FROM Settings
|
||||||
WHERE (acoustic_data = {s})
|
WHERE (acoustic_data = {s})
|
||||||
'''
|
'''
|
||||||
|
|
||||||
data = self.execute(query3)
|
data = self.execute(query3)
|
||||||
x = data[0]
|
it = iter(data[0])
|
||||||
|
|
||||||
stg.temperature = [x[1]][0]
|
acoustic_data = next(it)
|
||||||
stg.distance_from_ABS_to_free_surface.append(x[2])
|
stg.temperature = [next(it)][0]
|
||||||
stg.tmin.append((x[3], x[4]))
|
stg.distance_from_ABS_to_free_surface.append(next(it))
|
||||||
stg.tmax.append((x[5], x[6]))
|
stg.tmin.append((next(it), next(it)))
|
||||||
stg.rmin.append((x[7], x[8]))
|
stg.tmax.append((next(it), next(it)))
|
||||||
stg.rmax.append((x[9], x[10]))
|
stg.rmin.append((next(it), next(it)))
|
||||||
stg.freq_bottom_detection.append((x[11], x[12]))
|
stg.rmax.append((next(it), next(it)))
|
||||||
stg.SNR_filter_value.append(x[13])
|
stg.freq_bottom_detection.append((next(it), next(it)))
|
||||||
stg.Nb_cells_to_average_BS_signal.append(x[14])
|
stg.depth_bottom_detection_min = next(it)
|
||||||
|
stg.depth_bottom_detection_max = next(it)
|
||||||
|
stg.depth_bottom_detection_interval = next(it)
|
||||||
|
stg.SNR_filter_value.append(next(it))
|
||||||
|
stg.Nb_cells_to_average_BS_signal.append(next(it))
|
||||||
|
|
||||||
logger.debug(f"stg.temperature: {stg.temperature}")
|
logger.debug(f"stg.temperature: {stg.temperature}")
|
||||||
logger.debug(f"stg.tmin: {stg.tmin}")
|
logger.debug(f"stg.tmin: {stg.tmin}")
|
||||||
|
|
@ -705,3 +713,16 @@ class ReadTableForOpen:
|
||||||
stg.FCB = np_f64_parse(next(it)).tolist()
|
stg.FCB = np_f64_parse(next(it)).tolist()
|
||||||
stg.depth_real = np_f64_parse(next(it)).tolist()
|
stg.depth_real = np_f64_parse(next(it)).tolist()
|
||||||
stg.lin_reg = np_f64_parse(next(it)).tolist()
|
stg.lin_reg = np_f64_parse(next(it)).tolist()
|
||||||
|
|
||||||
|
@trace
|
||||||
|
def read_table_table_notes(self):
|
||||||
|
np_f64_parse = lambda d: np.frombuffer(d, dtype=np.float64)
|
||||||
|
|
||||||
|
query = f'''
|
||||||
|
SELECT notes
|
||||||
|
FROM Notes
|
||||||
|
'''
|
||||||
|
|
||||||
|
data = self.execute(query)
|
||||||
|
if len(data) != 0:
|
||||||
|
stg.notes = data[0][0]
|
||||||
|
|
|
||||||
|
|
@ -750,7 +750,10 @@ class AcousticDataTab(QWidget):
|
||||||
self.fill_table()
|
self.fill_table()
|
||||||
self.plot_backscattered_acoustic_signal_recording()
|
self.plot_backscattered_acoustic_signal_recording()
|
||||||
self.plot_profile()
|
self.plot_profile()
|
||||||
|
|
||||||
self.update_frequency_combobox()
|
self.update_frequency_combobox()
|
||||||
|
self.update_bottom_detection_settings()
|
||||||
|
|
||||||
self.water_attenuation()
|
self.water_attenuation()
|
||||||
self.compute_tmin_tmax()
|
self.compute_tmin_tmax()
|
||||||
self.compute_rmin_rmax()
|
self.compute_rmin_rmax()
|
||||||
|
|
@ -2445,7 +2448,6 @@ class AcousticDataTab(QWidget):
|
||||||
self.fig_BS.canvas.draw_idle()
|
self.fig_BS.canvas.draw_idle()
|
||||||
|
|
||||||
def update_plot_backscattered_acoustic_signal_recording(self):
|
def update_plot_backscattered_acoustic_signal_recording(self):
|
||||||
|
|
||||||
# --- Condition if table is filled but transect is not plotted
|
# --- Condition if table is filled but transect is not plotted
|
||||||
# --- => Error message if spin box values of tmin or tmax is change
|
# --- => Error message if spin box values of tmin or tmax is change
|
||||||
if self.canvas_BS == None:
|
if self.canvas_BS == None:
|
||||||
|
|
@ -2455,112 +2457,81 @@ class AcousticDataTab(QWidget):
|
||||||
msgBox.setText("Plot transect before change x-axis value")
|
msgBox.setText("Plot transect before change x-axis value")
|
||||||
msgBox.setStandardButtons(QMessageBox.Ok)
|
msgBox.setStandardButtons(QMessageBox.Ok)
|
||||||
msgBox.exec()
|
msgBox.exec()
|
||||||
|
return
|
||||||
|
|
||||||
else:
|
data_id = self.fileListWidget.currentRow()
|
||||||
|
|
||||||
if self.fileListWidget.currentRow() != -1:
|
if data_id == -1:
|
||||||
if len(self.axis_BS.tolist()) != stg.freq[self.fileListWidget.currentRow()].shape[0]:
|
return
|
||||||
self.fig_BS, self.axis_BS = plt.subplots(nrows=stg.freq[self.fileListWidget.currentRow()].shape[0],
|
|
||||||
|
if len(self.axis_BS.tolist()) != stg.freq[data_id].shape[0]:
|
||||||
|
self.fig_BS, self.axis_BS = plt.subplots(
|
||||||
|
nrows=stg.freq[data_id].shape[0],
|
||||||
ncols=1,
|
ncols=1,
|
||||||
sharex=False, sharey=False, layout="constrained")
|
sharex=False, sharey=False,
|
||||||
|
layout="constrained"
|
||||||
|
)
|
||||||
|
|
||||||
for f, _ in enumerate(stg.freq[self.fileListWidget.currentRow()]):
|
for f, _ in enumerate(stg.freq[data_id]):
|
||||||
self.axis_BS[f].cla()
|
self.axis_BS[f].cla()
|
||||||
|
|
||||||
if stg.BS_cross_section[self.fileListWidget.currentRow()].shape != (0,):
|
if stg.BS_cross_section[data_id].shape != (0,):
|
||||||
|
BS_data = stg.BS_cross_section
|
||||||
val_min = np.nanmin(stg.BS_cross_section[self.fileListWidget.currentRow()][f, :, :])
|
time_data = stg.time_cross_section
|
||||||
val_max = np.nanmax(stg.BS_cross_section[self.fileListWidget.currentRow()][f, :, :])
|
depth_data = stg.depth_cross_section
|
||||||
if val_min == 0:
|
|
||||||
val_min = 1e-5
|
|
||||||
|
|
||||||
if self.combobox_ABS_system_choice.currentIndex() == 1:
|
|
||||||
pcm = self.axis_BS[f].pcolormesh(
|
|
||||||
stg.time_cross_section[self.fileListWidget.currentRow()][f, :],
|
|
||||||
-stg.depth_cross_section[self.fileListWidget.currentRow()][f, :],
|
|
||||||
stg.BS_cross_section[self.fileListWidget.currentRow()][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_cross_section[self.fileListWidget.currentRow()][f, :],
|
|
||||||
-stg.depth_cross_section[self.fileListWidget.currentRow()][f, :],
|
|
||||||
np.log(stg.BS_cross_section[self.fileListWidget.currentRow()][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 <=
|
|
||||||
stg.time_cross_section[self.fileListWidget.currentRow()].shape[
|
|
||||||
1] - 1
|
|
||||||
else np.max(stg.time_cross_section[self.fileListWidget.currentRow()].shape[1] - 1)][0]
|
|
||||||
|
|
||||||
self.axis_BS[self.combobox_frequency_profile.currentIndex()].plot(
|
|
||||||
stg.time_cross_section[self.fileListWidget.currentRow()][
|
|
||||||
0, # self.combobox_frequency_profile.currentIndex(),
|
|
||||||
slider_value] * np.ones(
|
|
||||||
stg.depth_cross_section[self.fileListWidget.currentRow()].shape[1]),
|
|
||||||
-stg.depth_cross_section[self.fileListWidget.currentRow()][
|
|
||||||
self.combobox_frequency_profile.currentIndex(), :],
|
|
||||||
color='red', linestyle="solid", linewidth=2)
|
|
||||||
|
|
||||||
# --- Plot river bottom line ---
|
|
||||||
if stg.depth_bottom[self.fileListWidget.currentRow()].shape != (0,):
|
|
||||||
|
|
||||||
self.axis_BS[f].plot(stg.time_cross_section[self.fileListWidget.currentRow()][
|
|
||||||
self.combobox_frequency_bathymetry.currentIndex(), :],
|
|
||||||
-stg.depth_bottom[self.fileListWidget.currentRow()],
|
|
||||||
color='black', linewidth=1, linestyle="solid")
|
|
||||||
|
|
||||||
else:
|
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, :, :])
|
||||||
|
|
||||||
val_min = np.nanmin(stg.BS_raw_data[self.fileListWidget.currentRow()][f, :, :])
|
|
||||||
val_max = np.nanmax(stg.BS_raw_data[self.fileListWidget.currentRow()][f, :, :])
|
|
||||||
if val_min == 0:
|
if val_min == 0:
|
||||||
val_min = 1e-5
|
val_min = 1e-5
|
||||||
|
|
||||||
if self.combobox_ABS_system_choice.currentIndex() == 1:
|
if self.combobox_ABS_system_choice.currentIndex() == 1:
|
||||||
pcm = self.axis_BS[f].pcolormesh(stg.time[self.fileListWidget.currentRow()][f, :],
|
pcm = self.axis_BS[f].pcolormesh(
|
||||||
-stg.depth[self.fileListWidget.currentRow()][f,
|
time_data[data_id][f, :],
|
||||||
:],
|
-depth_data[data_id][f, :],
|
||||||
stg.BS_raw_data[self.fileListWidget.currentRow()][f, :,
|
BS_data[data_id][f, :, :],
|
||||||
:],
|
cmap='viridis',
|
||||||
cmap='viridis', norm=LogNorm(vmin=val_min, vmax=val_max))
|
norm=LogNorm(vmin=val_min, vmax=val_max)
|
||||||
|
)
|
||||||
elif self.combobox_ABS_system_choice.currentIndex() == 2:
|
elif self.combobox_ABS_system_choice.currentIndex() == 2:
|
||||||
pcm = self.axis_BS[f].pcolormesh(stg.time[self.fileListWidget.currentRow()][f, :],
|
pcm = self.axis_BS[f].pcolormesh(
|
||||||
-stg.depth[self.fileListWidget.currentRow()][f,
|
time_data[data_id][f, :],
|
||||||
:],
|
-depth_data[data_id][f, :],
|
||||||
np.log(
|
np.log(BS_data[data_id][f, :, :]),
|
||||||
stg.BS_raw_data[self.fileListWidget.currentRow()][f,
|
cmap='Blues'
|
||||||
:, :]),
|
)
|
||||||
cmap='Blues')
|
|
||||||
|
|
||||||
# --- Plot red solid line on transect to visualize position of plotted profile ---
|
# --- Plot red solid line on transect to visualize position of plotted profile ---
|
||||||
slider_value = \
|
slider_value = [
|
||||||
[self.slider.value() - 1 if self.slider.value() - 1 <=
|
self.slider.value() - 1
|
||||||
stg.time[self.fileListWidget.currentRow()].shape[
|
if self.slider.value() - 1 <= time_data[data_id].shape[1] - 1
|
||||||
1] - 1
|
else np.max(time_data[data_id].shape[1] - 1)
|
||||||
else np.max(stg.time[self.fileListWidget.currentRow()].shape[1] - 1)][0]
|
][0]
|
||||||
|
|
||||||
self.axis_BS[self.combobox_frequency_profile.currentIndex()].plot(
|
freq_id = self.combobox_frequency_profile.currentIndex()
|
||||||
stg.time[self.fileListWidget.currentRow()][0, slider_value] *
|
|
||||||
np.ones(stg.depth[self.fileListWidget.currentRow()].shape[1]),
|
self.axis_BS[freq_id].plot(
|
||||||
-stg.depth[self.fileListWidget.currentRow()][
|
time_data[data_id][0, slider_value] * np.ones(
|
||||||
self.combobox_frequency_profile.currentIndex(), :],
|
depth_data[data_id].shape[1]
|
||||||
color='red', linestyle="solid", linewidth=2)
|
),
|
||||||
|
-depth_data[data_id][freq_id, :],
|
||||||
|
color='red', linestyle="solid", linewidth=2
|
||||||
|
)
|
||||||
|
|
||||||
# --- Plot river bottom line ---
|
# --- Plot river bottom line ---
|
||||||
if stg.depth_bottom[self.fileListWidget.currentRow()].shape != (0,):
|
if stg.depth_bottom[data_id].shape != (0,):
|
||||||
self.axis_BS[f].plot(stg.time[self.fileListWidget.currentRow()][
|
self.axis_BS[f].plot(
|
||||||
self.combobox_frequency_bathymetry.currentIndex(), :],
|
time_data[data_id][
|
||||||
-stg.depth_bottom[self.fileListWidget.currentRow()],
|
self.combobox_frequency_bathymetry.currentIndex(), :
|
||||||
color='black', linewidth=1, linestyle="solid")
|
],
|
||||||
|
-stg.depth_bottom[data_id],
|
||||||
self.axis_BS[f].text(1, .70, stg.freq_text[self.fileListWidget.currentRow()][f],
|
color='black', linewidth=1, linestyle="solid"
|
||||||
fontsize=14, fontweight='bold', fontname="DejaVu Sans", c="black", alpha=0.5,
|
)
|
||||||
horizontalalignment='right', verticalalignment='bottom',
|
|
||||||
transform=self.axis_BS[f].transAxes)
|
|
||||||
|
|
||||||
self.fig_BS.supxlabel('Time (sec)', fontsize=10)
|
self.fig_BS.supxlabel('Time (sec)', fontsize=10)
|
||||||
self.fig_BS.supylabel('Depth (m)', fontsize=10)
|
self.fig_BS.supylabel('Depth (m)', fontsize=10)
|
||||||
|
|
@ -2782,7 +2753,33 @@ class AcousticDataTab(QWidget):
|
||||||
str(stg.time[self.fileListWidget.currentRow()][self.combobox_frequency_profile.currentIndex(), self.slider.value()-1]))
|
str(stg.time[self.fileListWidget.currentRow()][self.combobox_frequency_profile.currentIndex(), self.slider.value()-1]))
|
||||||
|
|
||||||
|
|
||||||
|
def update_bottom_detection_settings(self):
|
||||||
|
self.lineEdit_depth_min_bathy.setText(
|
||||||
|
str(stg.depth_bottom_detection_min)
|
||||||
|
)
|
||||||
|
|
||||||
|
self.lineEdit_depth_max_bathy.setText(
|
||||||
|
str(stg.depth_bottom_detection_max)
|
||||||
|
)
|
||||||
|
|
||||||
|
self.lineEdit_next_cell_bathy.setText(
|
||||||
|
str(stg.depth_bottom_detection_interval)
|
||||||
|
)
|
||||||
|
|
||||||
|
def save_bottom_detection_settings(self):
|
||||||
|
stg.depth_bottom_detection_min = float(
|
||||||
|
self.lineEdit_depth_min_bathy.text()
|
||||||
|
)
|
||||||
|
stg.depth_bottom_detection_max = float(
|
||||||
|
self.lineEdit_depth_max_bathy.text()
|
||||||
|
)
|
||||||
|
stg.depth_bottom_detection_interval = float(
|
||||||
|
self.lineEdit_next_cell_bathy.text()
|
||||||
|
)
|
||||||
|
|
||||||
def detect_bottom(self):
|
def detect_bottom(self):
|
||||||
|
self.save_bottom_detection_settings()
|
||||||
|
|
||||||
if self.fileListWidget.count() == 0:
|
if self.fileListWidget.count() == 0:
|
||||||
msgBox = QMessageBox()
|
msgBox = QMessageBox()
|
||||||
msgBox.setWindowTitle("Detect bottom Error")
|
msgBox.setWindowTitle("Detect bottom Error")
|
||||||
|
|
@ -2790,7 +2787,7 @@ class AcousticDataTab(QWidget):
|
||||||
msgBox.setText("Load data before compute bathymety algorithm")
|
msgBox.setText("Load data before compute bathymety algorithm")
|
||||||
msgBox.setStandardButtons(QMessageBox.Ok)
|
msgBox.setStandardButtons(QMessageBox.Ok)
|
||||||
msgBox.exec()
|
msgBox.exec()
|
||||||
|
return
|
||||||
elif self.canvas_BS == None:
|
elif self.canvas_BS == None:
|
||||||
msgBox = QMessageBox()
|
msgBox = QMessageBox()
|
||||||
msgBox.setWindowTitle("Detect bottom Error")
|
msgBox.setWindowTitle("Detect bottom Error")
|
||||||
|
|
@ -2798,65 +2795,104 @@ class AcousticDataTab(QWidget):
|
||||||
msgBox.setText("Plot transect before compute bathymety algorithm")
|
msgBox.setText("Plot transect before compute bathymety algorithm")
|
||||||
msgBox.setStandardButtons(QMessageBox.Ok)
|
msgBox.setStandardButtons(QMessageBox.Ok)
|
||||||
msgBox.exec()
|
msgBox.exec()
|
||||||
|
return
|
||||||
elif self.lineEdit_next_cell_bathy.text() == "0.00":
|
elif self.lineEdit_next_cell_bathy.text() == "0.00":
|
||||||
|
return
|
||||||
|
|
||||||
pass
|
self.detect_bottom_compute()
|
||||||
|
|
||||||
else:
|
def detect_bottom_compute(self):
|
||||||
|
data_id = self.fileListWidget.currentRow()
|
||||||
|
freq_id = self.combobox_frequency_bathymetry.currentIndex()
|
||||||
|
freq_text = self.combobox_frequency_bathymetry.currentText()
|
||||||
|
|
||||||
if stg.BS_cross_section[self.fileListWidget.currentRow()].shape != (0,):
|
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[self.fileListWidget.currentRow()] = \
|
stg.freq_bottom_detection[data_id] = (freq_id, freq_text)
|
||||||
(self.combobox_frequency_bathymetry.currentIndex(), self.combobox_frequency_bathymetry.currentText())
|
|
||||||
|
|
||||||
rmin = float("".join(findall("[.0-9]", self.lineEdit_depth_max_bathy.text())))
|
rmin = float(
|
||||||
rmax = float("".join(findall("[.0-9]", self.lineEdit_depth_min_bathy.text())))
|
"".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(stg.time_cross_section[self.fileListWidget.currentRow()].shape[1])
|
r_bottom = np.zeros(time_data[data_id].shape[1])
|
||||||
val_bottom = np.zeros(stg.time_cross_section[self.fileListWidget.currentRow()].shape[1])
|
val_bottom = np.zeros(time_data[data_id].shape[1])
|
||||||
|
|
||||||
r_bottom_ind = []
|
r_bottom_ind = []
|
||||||
|
|
||||||
BS_smooth = deepcopy(stg.BS_cross_section[self.fileListWidget.currentRow()][self.combobox_frequency_bathymetry.currentIndex(), :, :])
|
BS_smooth = deepcopy(BS_data[data_id][freq_id, :, :])
|
||||||
|
|
||||||
for k in range(stg.time_cross_section[self.fileListWidget.currentRow()].shape[1]):
|
for k in range(time_data[data_id].shape[1]):
|
||||||
BS_smooth[:, k] = savgol_filter(BS_smooth[:, k], 10, 2)
|
BS_smooth[:, k] = savgol_filter(BS_smooth[:, k], 10, 2)
|
||||||
|
|
||||||
# ----------- Detecting the bottom -------------
|
# ----------- Detecting the bottom -------------
|
||||||
for d in range(stg.time_cross_section[self.fileListWidget.currentRow()].shape[1]):
|
for d in range(time_data[data_id].shape[1]):
|
||||||
|
ind_min = np.where(
|
||||||
ind_min = np.where(stg.depth_cross_section[self.fileListWidget.currentRow()][int(self.combobox_frequency_bathymetry.currentIndex()), :] >= rmin)[0][0]
|
depth_data[data_id][freq_id, :]
|
||||||
ind_max = np.where(stg.depth_cross_section[self.fileListWidget.currentRow()][int(self.combobox_frequency_bathymetry.currentIndex()), :] <= rmax)[0][-1]
|
>= rmin
|
||||||
|
)[0][0]
|
||||||
|
ind_max = np.where(
|
||||||
|
depth_data[data_id][freq_id, :]
|
||||||
|
<= rmax
|
||||||
|
)[0][-1]
|
||||||
|
|
||||||
# Getting the peak
|
# Getting the peak
|
||||||
try:
|
try:
|
||||||
val_bottom[d] = np.nanmax(BS_smooth[ind_min:ind_max, d])
|
val_bottom[d] = np.nanmax(BS_smooth[ind_min:ind_max, d])
|
||||||
|
|
||||||
except ValueError as e:
|
except ValueError as e:
|
||||||
msgBox = QMessageBox()
|
msgBox = QMessageBox()
|
||||||
msgBox.setWindowTitle("Detect bottom Error")
|
msgBox.setWindowTitle("Detect bottom Error")
|
||||||
msgBox.setIcon(QMessageBox.Warning)
|
msgBox.setIcon(QMessageBox.Warning)
|
||||||
msgBox.setText(f"1/ {e} : maximum value of section bottom is not found. \n "
|
msgBox.setText(
|
||||||
f"Please change parameter of algorithm")
|
f"1/ {e} : maximum value of section bottom is not found. \n "
|
||||||
|
f"Please change parameter of algorithm"
|
||||||
|
)
|
||||||
msgBox.setStandardButtons(QMessageBox.Ok)
|
msgBox.setStandardButtons(QMessageBox.Ok)
|
||||||
msgBox_return = msgBox.exec()
|
msgBox_return = msgBox.exec()
|
||||||
if msgBox_return == msgBox.Ok:
|
if msgBox_return == msgBox.Ok:
|
||||||
break
|
break
|
||||||
else:
|
else:
|
||||||
|
ind_bottom = np.where(
|
||||||
ind_bottom = np.where((BS_smooth[ind_min:ind_max, d]) == val_bottom[d])[0][0]
|
(BS_smooth[ind_min:ind_max, d])
|
||||||
|
== val_bottom[d]
|
||||||
|
)[0][0]
|
||||||
np.append(stg.ind_bottom, ind_bottom)
|
np.append(stg.ind_bottom, ind_bottom)
|
||||||
|
|
||||||
r_bottom[d] = stg.depth_cross_section[self.fileListWidget.currentRow()][self.combobox_frequency_bathymetry.currentIndex(), ind_bottom + ind_min]
|
r_bottom[d] = depth_data[data_id][
|
||||||
|
freq_id, ind_bottom + ind_min
|
||||||
|
]
|
||||||
r_bottom_ind.append(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((stg.depth_cross_section[self.fileListWidget.currentRow()].shape[1],
|
# Updating the range where we will look for the peak (in the next cell)
|
||||||
stg.time_cross_section[self.fileListWidget.currentRow()].shape[1]))
|
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]):
|
for i in range(BS_section_bottom.shape[0]):
|
||||||
try:
|
try:
|
||||||
|
|
@ -2865,191 +2901,81 @@ class AcousticDataTab(QWidget):
|
||||||
msgBox = QMessageBox()
|
msgBox = QMessageBox()
|
||||||
msgBox.setWindowTitle("Detect bottom Error")
|
msgBox.setWindowTitle("Detect bottom Error")
|
||||||
msgBox.setIcon(QMessageBox.Warning)
|
msgBox.setIcon(QMessageBox.Warning)
|
||||||
msgBox.setText(f"2/ {e} : maximum value of section bottom is not found. \n "
|
msgBox.setText(
|
||||||
f"Please change parameter of algorithm")
|
f"2/ {e} : maximum value of section bottom is not found. \n "
|
||||||
|
f"Please change parameter of algorithm"
|
||||||
|
)
|
||||||
msgBox.setStandardButtons(QMessageBox.Ok)
|
msgBox.setStandardButtons(QMessageBox.Ok)
|
||||||
msgBox_return = msgBox.exec()
|
msgBox_return = msgBox.exec()
|
||||||
if msgBox_return == msgBox.Ok:
|
if msgBox_return == msgBox.Ok:
|
||||||
break
|
break
|
||||||
|
|
||||||
if BS_section_bottom.sum() > 2:
|
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
|
||||||
|
|
||||||
stg.depth_bottom[self.fileListWidget.currentRow()] = r_bottom
|
BS_stream_bed_copy = deepcopy(BS_data[data_id])
|
||||||
|
for f, _ in enumerate(stg.freq[data_id]):
|
||||||
stg.val_bottom[self.fileListWidget.currentRow()] = val_bottom
|
for k, _ in enumerate(stg.depth_bottom[data_id]):
|
||||||
|
|
||||||
stg.ind_bottom[self.fileListWidget.currentRow()] = r_bottom_ind
|
|
||||||
|
|
||||||
|
|
||||||
BS_stream_bed_copy = deepcopy(stg.BS_cross_section[self.fileListWidget.currentRow()])
|
|
||||||
for f, _ in enumerate(stg.freq[self.fileListWidget.currentRow()]):
|
|
||||||
for k, _ in enumerate(stg.depth_bottom[self.fileListWidget.currentRow()]):
|
|
||||||
BS_stream_bed_copy[
|
BS_stream_bed_copy[
|
||||||
f, np.where(stg.depth_cross_section[self.fileListWidget.currentRow()][self.combobox_frequency_bathymetry.currentIndex(), :]
|
f, np.where(
|
||||||
>= stg.depth_bottom[self.fileListWidget.currentRow()][k])[
|
depth_data[data_id][freq_id, :]
|
||||||
0], k] = np.nan
|
>= stg.depth_bottom[data_id][k]
|
||||||
|
)[0], k
|
||||||
|
] = np.nan
|
||||||
|
|
||||||
stg.BS_stream_bed[self.fileListWidget.currentRow()] = BS_stream_bed_copy
|
stg.BS_stream_bed[data_id] = BS_stream_bed_copy
|
||||||
|
|
||||||
# --- Plot transect BS with bathymetry ---
|
self.detect_bottom_compute_plot_BS_with_bathymetry(
|
||||||
for f, _ in enumerate(stg.freq[self.fileListWidget.currentRow()]):
|
BS_data, time_data, depth_data
|
||||||
self.axis_BS[f].cla()
|
)
|
||||||
|
|
||||||
val_min = np.min(stg.BS_raw_data[self.fileListWidget.currentRow()][f, :, :])
|
|
||||||
val_max = np.max(stg.BS_raw_data[self.fileListWidget.currentRow()][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_cross_section[self.fileListWidget.currentRow()][f, :],
|
|
||||||
-stg.depth_cross_section[self.fileListWidget.currentRow()][f, :],
|
|
||||||
stg.BS_cross_section[self.fileListWidget.currentRow()][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_cross_section[self.fileListWidget.currentRow()][f, :],
|
|
||||||
-stg.depth_cross_section[self.fileListWidget.currentRow()][f, :],
|
|
||||||
np.log(stg.BS_cross_section[self.fileListWidget.currentRow()][f, :, :]),
|
|
||||||
cmap='Blues')
|
|
||||||
|
|
||||||
self.axis_BS[f].plot(stg.time_cross_section[self.fileListWidget.currentRow()][self.combobox_frequency_bathymetry.currentIndex(), :],
|
|
||||||
-stg.depth_bottom[self.fileListWidget.currentRow()],
|
|
||||||
color='black', linewidth=1, linestyle="solid")
|
|
||||||
|
|
||||||
self.axis_BS[f].text(1, .70, stg.freq_text[self.fileListWidget.currentRow()][f],
|
|
||||||
fontsize=14, fontweight='bold', fontname="DejaVu Sans", c="black", alpha=0.5,
|
|
||||||
horizontalalignment='right', verticalalignment='bottom',
|
|
||||||
transform=self.axis_BS[f].transAxes)
|
|
||||||
|
|
||||||
# --- Update plot profile ---
|
# --- Update plot profile ---
|
||||||
self.update_plot_profile()
|
self.update_plot_profile()
|
||||||
|
|
||||||
self.fig_BS.canvas.draw_idle()
|
self.fig_BS.canvas.draw_idle()
|
||||||
|
|
||||||
elif stg.BS_raw_data[self.fileListWidget.currentRow()].shape != (0,):
|
def detect_bottom_compute_plot_BS_with_bathymetry(
|
||||||
|
self, BS_data, time_data, depth_data
|
||||||
|
):
|
||||||
|
data_id = self.fileListWidget.currentRow()
|
||||||
|
freq_id = self.combobox_frequency_bathymetry.currentIndex()
|
||||||
|
|
||||||
stg.freq_bottom_detection[self.fileListWidget.currentRow()] = (
|
for f, _ in enumerate(stg.freq[data_id]):
|
||||||
self.combobox_frequency_bathymetry.currentIndex(), self.combobox_frequency_bathymetry.currentText())
|
|
||||||
|
|
||||||
# Selecting the range in which we look for the bottom reflection
|
|
||||||
rmin = float("".join(findall("[.0-9]", self.lineEdit_depth_max_bathy.text())))
|
|
||||||
rmax = float("".join(findall("[.0-9]", self.lineEdit_depth_min_bathy.text())))
|
|
||||||
|
|
||||||
# empty result arrays
|
|
||||||
r_bottom = np.zeros(stg.time[self.fileListWidget.currentRow()].shape[1])
|
|
||||||
val_bottom = np.zeros(stg.time[self.fileListWidget.currentRow()].shape[1])
|
|
||||||
|
|
||||||
r_bottom_ind = []
|
|
||||||
|
|
||||||
BS_smooth = deepcopy(stg.BS_raw_data[self.fileListWidget.currentRow()][
|
|
||||||
self.combobox_frequency_bathymetry.currentIndex(), :, :])
|
|
||||||
for k in range(stg.time[self.fileListWidget.currentRow()].shape[1]):
|
|
||||||
BS_smooth[:, k] = savgol_filter(BS_smooth[:, k], 10, 2)
|
|
||||||
|
|
||||||
# ----------- Detecting the bottom -------------
|
|
||||||
for d in range(stg.time[self.fileListWidget.currentRow()].shape[1]):
|
|
||||||
# Index of the range where we look for the peak
|
|
||||||
ind_min = np.where(stg.depth[self.fileListWidget.currentRow()][
|
|
||||||
int(self.combobox_frequency_bathymetry.currentIndex()), :] >= rmin)[0][0]
|
|
||||||
ind_max = np.where(stg.depth[self.fileListWidget.currentRow()][
|
|
||||||
int(self.combobox_frequency_bathymetry.currentIndex()), :] <= 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 # msgBox.close()
|
|
||||||
else:
|
|
||||||
# Getting the range cell of the peak
|
|
||||||
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] = stg.depth[self.fileListWidget.currentRow()][
|
|
||||||
self.combobox_frequency_bathymetry.currentIndex(), 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((stg.depth[self.fileListWidget.currentRow()].shape[1],
|
|
||||||
stg.time[self.fileListWidget.currentRow()].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 # msgBox.close()
|
|
||||||
|
|
||||||
if BS_section_bottom.sum() > 2:
|
|
||||||
# --- Record r_bottom for other tabs ---
|
|
||||||
stg.depth_bottom[self.fileListWidget.currentRow()] = r_bottom
|
|
||||||
|
|
||||||
stg.val_bottom[self.fileListWidget.currentRow()] = val_bottom
|
|
||||||
|
|
||||||
stg.ind_bottom[self.fileListWidget.currentRow()] = r_bottom_ind
|
|
||||||
|
|
||||||
BS_stream_bed_copy = deepcopy(stg.BS_raw_data[self.fileListWidget.currentRow()])
|
|
||||||
for f, _ in enumerate(stg.freq[self.fileListWidget.currentRow()]):
|
|
||||||
for k, _ in enumerate(stg.depth_bottom[self.fileListWidget.currentRow()]):
|
|
||||||
BS_stream_bed_copy[
|
|
||||||
f, np.where(stg.depth[self.fileListWidget.currentRow()][
|
|
||||||
self.combobox_frequency_bathymetry.currentIndex(), :]
|
|
||||||
>= stg.depth_bottom[self.fileListWidget.currentRow()][k])[
|
|
||||||
0], k] = np.nan
|
|
||||||
|
|
||||||
stg.BS_stream_bed[self.fileListWidget.currentRow()] = BS_stream_bed_copy
|
|
||||||
|
|
||||||
# --- Plot transect BS with bathymetry ---
|
|
||||||
for f, _ in enumerate(stg.freq[self.fileListWidget.currentRow()]):
|
|
||||||
self.axis_BS[f].cla()
|
self.axis_BS[f].cla()
|
||||||
|
|
||||||
val_min = np.min(stg.BS_raw_data[self.fileListWidget.currentRow()][f, :, :])
|
val_min = np.min(stg.BS_raw_data[data_id][f, :, :])
|
||||||
val_max = np.max(stg.BS_raw_data[self.fileListWidget.currentRow()][f, :, :])
|
val_max = np.max(stg.BS_raw_data[data_id][f, :, :])
|
||||||
if val_min == 0:
|
if val_min == 0:
|
||||||
val_min = 1e-5
|
val_min = 1e-5
|
||||||
|
|
||||||
if self.combobox_ABS_system_choice.currentIndex() == 1:
|
if self.combobox_ABS_system_choice.currentIndex() == 1:
|
||||||
pcm = self.axis_BS[f].pcolormesh(
|
pcm = self.axis_BS[f].pcolormesh(
|
||||||
stg.time[self.fileListWidget.currentRow()][f, :],
|
time_data[data_id][f, :],
|
||||||
-stg.depth[self.fileListWidget.currentRow()][f, :],
|
-depth_data[data_id][f, :],
|
||||||
stg.BS_raw_data[self.fileListWidget.currentRow()][f, :, :],
|
BS_data[data_id][f, :, :],
|
||||||
cmap='viridis', norm=LogNorm(vmin=val_min, vmax=val_max))
|
cmap='viridis',
|
||||||
|
norm=LogNorm(vmin=val_min, vmax=val_max)
|
||||||
|
)
|
||||||
elif self.combobox_ABS_system_choice.currentIndex() == 2:
|
elif self.combobox_ABS_system_choice.currentIndex() == 2:
|
||||||
pcm = self.axis_BS[f].pcolormesh(
|
pcm = self.axis_BS[f].pcolormesh(
|
||||||
stg.time[self.fileListWidget.currentRow()][f, :],
|
time_data[data_id][f, :],
|
||||||
-stg.depth[self.fileListWidget.currentRow()][f, :],
|
-depth_data[data_id][f, :],
|
||||||
np.log(stg.BS_raw_data[self.fileListWidget.currentRow()][f, :, :]),
|
np.log(BS_data[data_id][f, :, :]),
|
||||||
cmap='Blues')
|
cmap='Blues'
|
||||||
|
)
|
||||||
|
|
||||||
self.axis_BS[f].plot(stg.time[self.fileListWidget.currentRow()][
|
self.axis_BS[f].plot(
|
||||||
self.combobox_frequency_bathymetry.currentIndex(), :],
|
time_data[data_id][freq_id, :],
|
||||||
-stg.depth_bottom[self.fileListWidget.currentRow()],
|
-stg.depth_bottom[data_id],
|
||||||
color='black', linewidth=1, linestyle="solid")
|
color='black', linewidth=1, linestyle="solid"
|
||||||
|
)
|
||||||
|
|
||||||
self.axis_BS[f].text(1, .70, stg.freq_text[self.fileListWidget.currentRow()][f],
|
self.axis_BS[f].text(
|
||||||
fontsize=14, fontweight='bold', fontname="DejaVu Sans", c="black",
|
1, .70, stg.freq_text[data_id][f],
|
||||||
alpha=0.5,
|
fontsize=14, fontweight='bold',
|
||||||
horizontalalignment='right', verticalalignment='bottom',
|
fontname="DejaVu Sans", c="black", alpha=0.5,
|
||||||
transform=self.axis_BS[f].transAxes)
|
horizontalalignment='right',
|
||||||
|
verticalalignment='bottom',
|
||||||
# --- Update plot profile ---
|
transform=self.axis_BS[f].transAxes
|
||||||
self.update_plot_profile()
|
)
|
||||||
|
|
||||||
self.fig_BS.canvas.draw_idle()
|
|
||||||
|
|
|
||||||
|
|
@ -1,3 +1,4 @@
|
||||||
|
import os
|
||||||
import logging
|
import logging
|
||||||
|
|
||||||
from PyQt5.QtWidgets import (
|
from PyQt5.QtWidgets import (
|
||||||
|
|
@ -6,7 +7,7 @@ from PyQt5.QtWidgets import (
|
||||||
QSizePolicy, QFontComboBox, QColorDialog
|
QSizePolicy, QFontComboBox, QColorDialog
|
||||||
)
|
)
|
||||||
from PyQt5.QtGui import QPixmap, QIcon, QFont
|
from PyQt5.QtGui import QPixmap, QIcon, QFont
|
||||||
from PyQt5.QtCore import Qt
|
from PyQt5.QtCore import Qt, QTimer
|
||||||
|
|
||||||
import settings as stg
|
import settings as stg
|
||||||
|
|
||||||
|
|
@ -18,13 +19,13 @@ class NoteTab(QWidget):
|
||||||
|
|
||||||
''' This class generates a enhanced notepad in Note Tab '''
|
''' This class generates a enhanced notepad in Note Tab '''
|
||||||
|
|
||||||
|
def _path_icon(self, icon):
|
||||||
|
return os.path.join("icons", icon)
|
||||||
|
|
||||||
def __init__(self, widget_tab):
|
def __init__(self, widget_tab):
|
||||||
super().__init__()
|
super().__init__()
|
||||||
|
|
||||||
path_icon = "./icons/"
|
self.changed = False
|
||||||
|
|
||||||
# FIXME: The note are disabled because there are never saved
|
|
||||||
widget_tab.setEnabled(False)
|
|
||||||
|
|
||||||
self.verticalLayout_main_note_tab = QVBoxLayout(widget_tab)
|
self.verticalLayout_main_note_tab = QVBoxLayout(widget_tab)
|
||||||
|
|
||||||
|
|
@ -36,96 +37,104 @@ class NoteTab(QWidget):
|
||||||
self.filename_text = ""
|
self.filename_text = ""
|
||||||
|
|
||||||
self.pushbutton_new_txt = QPushButton()
|
self.pushbutton_new_txt = QPushButton()
|
||||||
self.icon_new_txt = QPixmap(path_icon + "new_text.png")
|
self.icon_new_txt = QPixmap(self._path_icon("new_text.png"))
|
||||||
self.pushbutton_new_txt.setIcon(QIcon(self.icon_new_txt))
|
self.pushbutton_new_txt.setIcon(QIcon(self.icon_new_txt))
|
||||||
# self.pushbutton_new_txt.clicked.connect(self.new_text)
|
# self.pushbutton_new_txt.clicked.connect(self.new_text)
|
||||||
self.horizontalLayout_toolbar.addWidget(self.pushbutton_new_txt)
|
self.horizontalLayout_toolbar.addWidget(self.pushbutton_new_txt)
|
||||||
|
|
||||||
self.pushbutton_save_txt = QPushButton()
|
self.pushbutton_save_txt = QPushButton()
|
||||||
self.icon_save_txt = QPixmap(path_icon + "save_txt.png")
|
self.icon_save_txt = QPixmap(self._path_icon("save_txt.png"))
|
||||||
self.pushbutton_save_txt.setIcon(QIcon(self.icon_save_txt))
|
self.pushbutton_save_txt.setIcon(QIcon(self.icon_save_txt))
|
||||||
# self.pushbutton_save_txt.clicked.connect(self.save_text)
|
# self.pushbutton_save_txt.clicked.connect(self.save_text)
|
||||||
self.horizontalLayout_toolbar.addWidget(self.pushbutton_save_txt)
|
self.horizontalLayout_toolbar.addWidget(self.pushbutton_save_txt)
|
||||||
|
|
||||||
self.pushbutton_open_txt = QPushButton()
|
self.pushbutton_open_txt = QPushButton()
|
||||||
self.icon_open_txt = QPixmap(path_icon + "open_txt.png")
|
self.icon_open_txt = QPixmap(self._path_icon("open_txt.png"))
|
||||||
self.pushbutton_open_txt.setIcon(QIcon(self.icon_open_txt))
|
self.pushbutton_open_txt.setIcon(QIcon(self.icon_open_txt))
|
||||||
# self.pushbutton_open_txt.clicked.connect(self.open_text)
|
# self.pushbutton_open_txt.clicked.connect(self.open_text)
|
||||||
self.horizontalLayout_toolbar.addWidget(self.pushbutton_open_txt)
|
self.horizontalLayout_toolbar.addWidget(self.pushbutton_open_txt)
|
||||||
|
|
||||||
self.fontbox = QFontComboBox()
|
self.fontbox = QFontComboBox()
|
||||||
self.fontbox.currentFontChanged.connect(lambda font : self.textEdit.setCurrentFont(font))
|
self.fontbox.currentFontChanged.connect(
|
||||||
|
lambda font : self.textEdit.setCurrentFont(font)
|
||||||
|
)
|
||||||
self.horizontalLayout_toolbar.addWidget(self.fontbox)
|
self.horizontalLayout_toolbar.addWidget(self.fontbox)
|
||||||
|
|
||||||
self.fontSize = QSpinBox()
|
self.fontSize = QSpinBox()
|
||||||
self.fontSize.setSuffix("pt")
|
self.fontSize.setSuffix("pt")
|
||||||
self.fontSize.valueChanged.connect(lambda size: self.textEdit.setFontPointSize(size))
|
self.fontSize.valueChanged.connect(
|
||||||
|
lambda size: self.textEdit.setFontPointSize(size)
|
||||||
|
)
|
||||||
self.fontSize.setValue(14)
|
self.fontSize.setValue(14)
|
||||||
self.horizontalLayout_toolbar.addWidget(self.fontSize)
|
self.horizontalLayout_toolbar.addWidget(self.fontSize)
|
||||||
|
|
||||||
self.fontColor = QPushButton()
|
self.fontColor = QPushButton()
|
||||||
self.icon_fontColor = QPixmap(path_icon + "font_color.png")
|
self.icon_fontColor = QPixmap(self._path_icon("font_color.png"))
|
||||||
self.fontColor.setIcon(QIcon(self.icon_fontColor))
|
self.fontColor.setIcon(QIcon(self.icon_fontColor))
|
||||||
# self.QAction(QIcon("couleur_police.png"), "Changer la couleur du texte", self)couleur_fond.png
|
# self.QAction(QIcon("couleur_police.png"), "Changer la couleur du texte", self)couleur_fond.png
|
||||||
self.fontColor.clicked.connect(self.fontColorChanged)
|
self.fontColor.clicked.connect(self.fontColorChanged)
|
||||||
self.horizontalLayout_toolbar.addWidget(self.fontColor)
|
self.horizontalLayout_toolbar.addWidget(self.fontColor)
|
||||||
|
|
||||||
self.backColor = QPushButton()
|
self.backColor = QPushButton()
|
||||||
self.icon_backColor = QPixmap(path_icon + "background_color.png")
|
self.icon_backColor = QPixmap(self._path_icon("background_color.png"))
|
||||||
self.backColor.setIcon(QIcon(self.icon_backColor))
|
self.backColor.setIcon(QIcon(self.icon_backColor))
|
||||||
self.backColor.clicked.connect(self.highlight)
|
self.backColor.clicked.connect(self.highlight)
|
||||||
self.horizontalLayout_toolbar.addWidget(self.backColor)
|
self.horizontalLayout_toolbar.addWidget(self.backColor)
|
||||||
|
|
||||||
self.boldAction = QPushButton()
|
self.boldAction = QPushButton()
|
||||||
self.icon_boldAction = QPixmap(path_icon + "bold.png")
|
self.icon_boldAction = QPixmap(self._path_icon("bold.png"))
|
||||||
self.boldAction.setIcon(QIcon(self.icon_boldAction))
|
self.boldAction.setIcon(QIcon(self.icon_boldAction))
|
||||||
self.boldAction.clicked.connect(self.bold)
|
self.boldAction.clicked.connect(self.bold)
|
||||||
self.horizontalLayout_toolbar.addWidget(self.boldAction)
|
self.horizontalLayout_toolbar.addWidget(self.boldAction)
|
||||||
|
|
||||||
self.italicAction = QPushButton()
|
self.italicAction = QPushButton()
|
||||||
self.icon_italicAction = QPixmap(path_icon + "italic.png")
|
self.icon_italicAction = QPixmap(self._path_icon("italic.png"))
|
||||||
self.italicAction.setIcon(QIcon(self.icon_italicAction))
|
self.italicAction.setIcon(QIcon(self.icon_italicAction))
|
||||||
self.italicAction.clicked.connect(self.italic)
|
self.italicAction.clicked.connect(self.italic)
|
||||||
self.horizontalLayout_toolbar.addWidget(self.italicAction)
|
self.horizontalLayout_toolbar.addWidget(self.italicAction)
|
||||||
|
|
||||||
self.underlineAction = QPushButton()
|
self.underlineAction = QPushButton()
|
||||||
self.icon_underlineAction = QPixmap(path_icon + "underline.png")
|
self.icon_underlineAction = QPixmap(self._path_icon("underline.png"))
|
||||||
self.underlineAction.setIcon(QIcon(self.icon_underlineAction))
|
self.underlineAction.setIcon(QIcon(self.icon_underlineAction))
|
||||||
self.underlineAction.clicked.connect(self.underline)
|
self.underlineAction.clicked.connect(self.underline)
|
||||||
self.horizontalLayout_toolbar.addWidget(self.underlineAction)
|
self.horizontalLayout_toolbar.addWidget(self.underlineAction)
|
||||||
|
|
||||||
self.strikeAction = QPushButton()
|
self.strikeAction = QPushButton()
|
||||||
self.icon_strikeAction = QPixmap(path_icon + "strike.png")
|
self.icon_strikeAction = QPixmap(self._path_icon("strike.png"))
|
||||||
self.strikeAction.setIcon(QIcon(self.icon_strikeAction))
|
self.strikeAction.setIcon(QIcon(self.icon_strikeAction))
|
||||||
self.strikeAction.clicked.connect(self.strike)
|
self.strikeAction.clicked.connect(self.strike)
|
||||||
self.horizontalLayout_toolbar.addWidget(self.strikeAction)
|
self.horizontalLayout_toolbar.addWidget(self.strikeAction)
|
||||||
|
|
||||||
self.alignLeftAction = QPushButton()
|
self.alignLeftAction = QPushButton()
|
||||||
self.icon_alignLeftAction = QPixmap(path_icon + "left.png")
|
self.icon_alignLeftAction = QPixmap(self._path_icon("left.png"))
|
||||||
self.alignLeftAction.setIcon(QIcon(self.icon_alignLeftAction))
|
self.alignLeftAction.setIcon(QIcon(self.icon_alignLeftAction))
|
||||||
self.alignLeftAction.clicked.connect(self.alignLeft)
|
self.alignLeftAction.clicked.connect(self.alignLeft)
|
||||||
self.horizontalLayout_toolbar.addWidget(self.alignLeftAction)
|
self.horizontalLayout_toolbar.addWidget(self.alignLeftAction)
|
||||||
|
|
||||||
self.alignCenterAction = QPushButton()
|
self.alignCenterAction = QPushButton()
|
||||||
self.icon_alignCenterAction = QPixmap(path_icon + "centre.png")
|
self.icon_alignCenterAction = QPixmap(self._path_icon("centre.png"))
|
||||||
self.alignCenterAction.setIcon(QIcon(self.icon_alignCenterAction))
|
self.alignCenterAction.setIcon(QIcon(self.icon_alignCenterAction))
|
||||||
self.alignCenterAction.clicked.connect(self.alignCenter)
|
self.alignCenterAction.clicked.connect(self.alignCenter)
|
||||||
self.horizontalLayout_toolbar.addWidget(self.alignCenterAction)
|
self.horizontalLayout_toolbar.addWidget(self.alignCenterAction)
|
||||||
|
|
||||||
self.alignRightAction = QPushButton()
|
self.alignRightAction = QPushButton()
|
||||||
self.icon_alignRightAction = QPixmap(path_icon + "right.png")
|
self.icon_alignRightAction = QPixmap(self._path_icon("right.png"))
|
||||||
self.alignRightAction.setIcon(QIcon(self.icon_alignRightAction))
|
self.alignRightAction.setIcon(QIcon(self.icon_alignRightAction))
|
||||||
self.alignRightAction.clicked.connect(self.alignRight)
|
self.alignRightAction.clicked.connect(self.alignRight)
|
||||||
self.horizontalLayout_toolbar.addWidget(self.alignRightAction)
|
self.horizontalLayout_toolbar.addWidget(self.alignRightAction)
|
||||||
|
|
||||||
self.alignJustifyAction = QPushButton()
|
self.alignJustifyAction = QPushButton()
|
||||||
self.icon_alignJustifyAction = QPixmap(path_icon + "justify.png")
|
self.icon_alignJustifyAction = QPixmap(self._path_icon("justify.png"))
|
||||||
self.alignJustifyAction.setIcon(QIcon(self.icon_alignJustifyAction))
|
self.alignJustifyAction.setIcon(QIcon(self.icon_alignJustifyAction))
|
||||||
self.alignJustifyAction.clicked.connect(self.alignJustify)
|
self.alignJustifyAction.clicked.connect(self.alignJustify)
|
||||||
self.horizontalLayout_toolbar.addWidget(self.alignJustifyAction)
|
self.horizontalLayout_toolbar.addWidget(self.alignJustifyAction)
|
||||||
|
|
||||||
self.horizontalSpacerItem_toolbar_note_tab = QSpacerItem(500, 10, QSizePolicy.Expanding, QSizePolicy.Minimum)
|
self.horizontalSpacerItem_toolbar_note_tab = QSpacerItem(
|
||||||
self.horizontalLayout_toolbar.addItem(self.horizontalSpacerItem_toolbar_note_tab)
|
500, 10, QSizePolicy.Expanding, QSizePolicy.Minimum
|
||||||
|
)
|
||||||
|
self.horizontalLayout_toolbar.addItem(
|
||||||
|
self.horizontalSpacerItem_toolbar_note_tab
|
||||||
|
)
|
||||||
|
|
||||||
self.pushbutton_print_settings = QPushButton()
|
self.pushbutton_print_settings = QPushButton()
|
||||||
self.pushbutton_print_settings.setText("EDIT SETTINGS")
|
self.pushbutton_print_settings.setText("EDIT SETTINGS")
|
||||||
|
|
@ -134,19 +143,40 @@ class NoteTab(QWidget):
|
||||||
|
|
||||||
self.verticalLayout_main_note_tab.addWidget(self.textEdit)
|
self.verticalLayout_main_note_tab.addWidget(self.textEdit)
|
||||||
|
|
||||||
|
self.textEdit.textChanged.connect(self.setTextChanged)
|
||||||
|
|
||||||
|
self._alarm = QTimer()
|
||||||
|
self._alarm.timeout.connect(self.applyTextOnStg)
|
||||||
|
self._alarm.start(1000)
|
||||||
|
|
||||||
## -------------------------------
|
## -------------------------------
|
||||||
## ---------- Functions ----------
|
## ---------- Functions ----------
|
||||||
## -------------------------------
|
## -------------------------------
|
||||||
|
|
||||||
@trace
|
@trace
|
||||||
def full_update(self):
|
def full_update(self):
|
||||||
logger.debug(f"{__name__}: Update")
|
|
||||||
self.blockSignals(True)
|
self.blockSignals(True)
|
||||||
|
self.textEdit.blockSignals(True)
|
||||||
|
self._alarm.blockSignals(True)
|
||||||
|
|
||||||
# TODO: Update all widgets
|
logger.debug(f"{__name__}: Update")
|
||||||
|
|
||||||
|
self.applyStgOnText()
|
||||||
|
|
||||||
|
self._alarm.blockSignals(False)
|
||||||
|
self.textEdit.blockSignals(False)
|
||||||
self.blockSignals(False)
|
self.blockSignals(False)
|
||||||
|
|
||||||
|
def setTextChanged(self):
|
||||||
|
self.changed = True
|
||||||
|
|
||||||
|
def applyTextOnStg(self):
|
||||||
|
text = self.textEdit.toHtml()
|
||||||
|
stg.notes = text
|
||||||
|
|
||||||
|
def applyStgOnText(self):
|
||||||
|
text = self.textEdit.setText(stg.notes)
|
||||||
|
|
||||||
# def new_text(self):
|
# def new_text(self):
|
||||||
# window = self.ui_mainwindow.tab5
|
# window = self.ui_mainwindow.tab5
|
||||||
# window.show()
|
# window.show()
|
||||||
|
|
|
||||||
|
|
@ -95,8 +95,6 @@ class SedimentCalibrationTab(QWidget):
|
||||||
self.horizontalLayoutBottom = QHBoxLayout()
|
self.horizontalLayoutBottom = QHBoxLayout()
|
||||||
self.verticalLayoutMain.addLayout(self.horizontalLayoutBottom, 5)
|
self.verticalLayoutMain.addLayout(self.horizontalLayoutBottom, 5)
|
||||||
|
|
||||||
# --------------------------------------------------------------------------------------------------------------
|
|
||||||
|
|
||||||
self.groupbox_acoustic_data = QGroupBox()
|
self.groupbox_acoustic_data = QGroupBox()
|
||||||
self.horizontalLayoutTop.addWidget(self.groupbox_acoustic_data, 6)
|
self.horizontalLayoutTop.addWidget(self.groupbox_acoustic_data, 6)
|
||||||
|
|
||||||
|
|
@ -356,11 +354,17 @@ class SedimentCalibrationTab(QWidget):
|
||||||
# +++++++++++++++++++++++++++++++++++++
|
# +++++++++++++++++++++++++++++++++++++
|
||||||
# +++ Groupbox sediment calibration +++
|
# +++ Groupbox sediment calibration +++
|
||||||
|
|
||||||
self.groupbox_sediment_calibration.setTitle("Step 3 : Compute Calibration")
|
self.groupbox_sediment_calibration\
|
||||||
self.verticalLayout_groupbox_sediment_calibration = QVBoxLayout(self.groupbox_sediment_calibration)
|
.setTitle("Step 3 : Compute Calibration")
|
||||||
|
|
||||||
|
self.verticalLayout_groupbox_sediment_calibration = QVBoxLayout(
|
||||||
|
self.groupbox_sediment_calibration
|
||||||
|
)
|
||||||
|
|
||||||
self.horizontalLayout_groupboxes_Import_Compute_Calibration = QHBoxLayout()
|
self.horizontalLayout_groupboxes_Import_Compute_Calibration = QHBoxLayout()
|
||||||
self.verticalLayout_groupbox_sediment_calibration.addLayout(self.horizontalLayout_groupboxes_Import_Compute_Calibration)
|
self.verticalLayout_groupbox_sediment_calibration.addLayout(
|
||||||
|
self.horizontalLayout_groupboxes_Import_Compute_Calibration
|
||||||
|
)
|
||||||
|
|
||||||
self._setup_widgets_calibration_import_file()
|
self._setup_widgets_calibration_import_file()
|
||||||
self._setup_widgets_calibration_compute()
|
self._setup_widgets_calibration_compute()
|
||||||
|
|
@ -855,10 +859,6 @@ class SedimentCalibrationTab(QWidget):
|
||||||
self.fit_FCB_profile_with_linear_regression_and_compute_alphaS
|
self.fit_FCB_profile_with_linear_regression_and_compute_alphaS
|
||||||
)
|
)
|
||||||
|
|
||||||
# ==============================================================================================================
|
|
||||||
# ----------------------------------- Functions for Signal processing Tab --------------------------------------
|
|
||||||
# ==============================================================================================================
|
|
||||||
|
|
||||||
@trace
|
@trace
|
||||||
def full_update(self):
|
def full_update(self):
|
||||||
logger.debug(f"{__name__}: Update")
|
logger.debug(f"{__name__}: Update")
|
||||||
|
|
@ -2419,7 +2419,7 @@ class SedimentCalibrationTab(QWidget):
|
||||||
* np.ones(
|
* np.ones(
|
||||||
depth_data[data_id].shape[1]
|
depth_data[data_id].shape[1]
|
||||||
),
|
),
|
||||||
-stg.depth_data[data_id][freq2_id, :]
|
-depth_data[data_id][freq2_id, :]
|
||||||
)
|
)
|
||||||
|
|
||||||
self.fig_BS.canvas.draw_idle()
|
self.fig_BS.canvas.draw_idle()
|
||||||
|
|
|
||||||
10
main.py
10
main.py
|
|
@ -125,16 +125,6 @@ class MainApplication(QMainWindow):
|
||||||
for tab in self.tabs:
|
for tab in self.tabs:
|
||||||
tab.full_update()
|
tab.full_update()
|
||||||
|
|
||||||
# self.acoustic_data_tab.combobox_ABS_system_choice.setCurrentText(stg.ABS_name[0])
|
|
||||||
# self.acoustic_data_tab.fileListWidget.addFilenames(stg.filename_BS_raw_data)
|
|
||||||
|
|
||||||
# self.signal_processing_tab.combobox_acoustic_data_choice.addItems(stg.filename_BS_raw_data)
|
|
||||||
|
|
||||||
# self.sample_data_tab.fill_comboboxes_and_plot_transect()
|
|
||||||
# self.sample_data_tab.lineEdit_fine_sediment.setText(stg.filename_fine)
|
|
||||||
# self.sample_data_tab.lineEdit_fine_sediment.setToolTip(stg.path_fine)
|
|
||||||
# self.sample_data_tab.fill_table_fine()
|
|
||||||
|
|
||||||
if __name__ == '__main__':
|
if __name__ == '__main__':
|
||||||
# print("sys.argv:", [arg for arg in sys.argv])
|
# print("sys.argv:", [arg for arg in sys.argv])
|
||||||
# app = MainApplication(sys.argv)
|
# app = MainApplication(sys.argv)
|
||||||
|
|
|
||||||
14
settings.py
14
settings.py
|
|
@ -105,11 +105,11 @@ BS_stream_bed = [] # BS data (raw or cross_section) with detected b
|
||||||
depth_bottom = [] # Depth value of th bottom : 1D array # List of arrays
|
depth_bottom = [] # Depth value of th bottom : 1D array # List of arrays
|
||||||
val_bottom = [] # Level of the BS signal on the bottom : 1D array # List of arrays
|
val_bottom = [] # Level of the BS signal on the bottom : 1D array # List of arrays
|
||||||
ind_bottom = [] # Index of bottom in depth array : list of int # List of lists
|
ind_bottom = [] # Index of bottom in depth array : list of int # List of lists
|
||||||
freq_bottom_detection = [] # Frequency use to detect the bottom : (index, string) # List of tuple
|
|
||||||
|
|
||||||
# depth_bottom_detection_min = [] # Min value to detect bottom on the first vertical # List of float
|
freq_bottom_detection = [] # Frequency use to detect the bottom : (index, string) # List of tuple
|
||||||
# depth_bottom_detection_max = [] # Max value to detect bottom on the first vertical # List of float
|
depth_bottom_detection_min = [] # Min value to detect bottom on the first vertical # List of float
|
||||||
# depth_bottom_detection_1st_int_area = [] # interval for searching area # List of float
|
depth_bottom_detection_max = [] # Max value to detect bottom on the first vertical # List of float
|
||||||
|
depth_bottom_detection_interval = [] # interval for searching area # List of float
|
||||||
|
|
||||||
# ----------------------------------------------------------------------------------------------------------------------
|
# ----------------------------------------------------------------------------------------------------------------------
|
||||||
# =========================================================
|
# =========================================================
|
||||||
|
|
@ -265,3 +265,9 @@ fine_sample_position = [] # Fine samples indexes position for time and dep
|
||||||
sand_sample_position = [] # Sand samples indexes position for time and depth [(time_index, depth_index)] # List of tuples
|
sand_sample_position = [] # Sand samples indexes position for time and depth [(time_index, depth_index)] # List of tuples
|
||||||
SSC_fine = [] # Suspended Sediment Concentration of the fine sediments # List of one 3D array
|
SSC_fine = [] # Suspended Sediment Concentration of the fine sediments # List of one 3D array
|
||||||
SSC_sand = [] # Suspended Sediment Concentration of the sand sediments # List of one 3D array
|
SSC_sand = [] # Suspended Sediment Concentration of the sand sediments # List of one 3D array
|
||||||
|
|
||||||
|
# =========================================================
|
||||||
|
# --- ACOUSTIC NOTES TAB ---
|
||||||
|
# =========================================================
|
||||||
|
|
||||||
|
notes = ""
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue