implemented averagignd and subtracting avg from B-scan. Control byBG_AVG_WINDOW_SEC = 5.0
BG_SUBTRACT_ALPHA = 1.0 BG_SUBTRACT_ENABLED = True # Метод расчёта фона: 'median' или 'mean' BG_BASELINE_METHOD = 'median'
This commit is contained in:
89
main.py
89
main.py
@ -14,6 +14,7 @@ from datetime import datetime, timedelta
|
|||||||
import threading
|
import threading
|
||||||
import queue
|
import queue
|
||||||
from sys import argv
|
from sys import argv
|
||||||
|
from collections import deque
|
||||||
|
|
||||||
# ================================================================================
|
# ================================================================================
|
||||||
# ПАРАМЕТРЫ И КОНСТАНТЫ
|
# ПАРАМЕТРЫ И КОНСТАНТЫ
|
||||||
@ -45,6 +46,13 @@ FILES_STORED_N_MAX = 100
|
|||||||
# Минимально допустимое число точек F0 для принятия данных
|
# Минимально допустимое число точек F0 для принятия данных
|
||||||
MIN_F0_POINTS = 100
|
MIN_F0_POINTS = 100
|
||||||
|
|
||||||
|
# Усреднение B-scan по времени (фон)
|
||||||
|
BG_AVG_WINDOW_SEC = 5.0
|
||||||
|
BG_SUBTRACT_ALPHA = 1.0
|
||||||
|
BG_SUBTRACT_ENABLED = True
|
||||||
|
# Метод расчёта фона: 'median' или 'mean'
|
||||||
|
BG_BASELINE_METHOD = 'median'
|
||||||
|
|
||||||
# ПЕРЕЧИСЛЕНИЕ ТИПОВ ДАННЫХ
|
# ПЕРЕЧИСЛЕНИЕ ТИПОВ ДАННЫХ
|
||||||
DATA_TYPE_RAW = "RAW"
|
DATA_TYPE_RAW = "RAW"
|
||||||
DATA_TYPE_SYNC_DET = "SYNC_DET"
|
DATA_TYPE_SYNC_DET = "SYNC_DET"
|
||||||
@ -453,6 +461,13 @@ class DataAnalyzerApp:
|
|||||||
self.processed_count = 0
|
self.processed_count = 0
|
||||||
self.skipped_count = 0
|
self.skipped_count = 0
|
||||||
|
|
||||||
|
# Буфер последних колонок для фонового усреднения B-scan
|
||||||
|
self.bscan_buffer = deque() # элементов: (np.ndarray col, datetime t, str type)
|
||||||
|
self.bg_avg_window_sec = BG_AVG_WINDOW_SEC
|
||||||
|
self.bg_subtract_alpha = BG_SUBTRACT_ALPHA
|
||||||
|
self.bg_subtract_enabled = BG_SUBTRACT_ENABLED
|
||||||
|
self.bg_method = BG_BASELINE_METHOD
|
||||||
|
|
||||||
# ============================================================================
|
# ============================================================================
|
||||||
# ИНИЦИАЛИЗАЦИЯ ИНТЕРФЕЙСА
|
# ИНИЦИАЛИЗАЦИЯ ИНТЕРФЕЙСА
|
||||||
# ============================================================================
|
# ============================================================================
|
||||||
@ -854,6 +869,13 @@ class DataAnalyzerApp:
|
|||||||
# Собираем данные для отображения
|
# Собираем данные для отображения
|
||||||
display_cols = []
|
display_cols = []
|
||||||
display_types = [] # Тип каждого столбца
|
display_types = [] # Тип каждого столбца
|
||||||
|
# Предрасчёт фонового усреднения по строкам текущего окна
|
||||||
|
bg_vec = None
|
||||||
|
if self.bg_subtract_enabled and self.bscan_buffer:
|
||||||
|
desired_row_start = row_min
|
||||||
|
desired_row_end = row_max + 1
|
||||||
|
bg_vec = self.compute_background_slice(desired_row_start, desired_row_end)
|
||||||
|
alpha = self.bg_subtract_alpha if self.bg_subtract_enabled else 0.0
|
||||||
for i in range(col_min, col_max):
|
for i in range(col_min, col_max):
|
||||||
col_data = self.B_scan_data[i]
|
col_data = self.B_scan_data[i]
|
||||||
col_type = self.B_scan_types[i]
|
col_type = self.B_scan_types[i]
|
||||||
@ -862,7 +884,13 @@ class DataAnalyzerApp:
|
|||||||
row_end = min(row_max + 1, len(col_data))
|
row_end = min(row_max + 1, len(col_data))
|
||||||
row_start = min(row_min, len(col_data) - 1)
|
row_start = min(row_min, len(col_data) - 1)
|
||||||
if row_end > row_start:
|
if row_end > row_start:
|
||||||
display_cols.append(col_data[row_start:row_end])
|
seg = col_data[row_start:row_end]
|
||||||
|
if bg_vec is not None and col_type != "GAP":
|
||||||
|
take = min(len(seg), len(bg_vec))
|
||||||
|
if take > 0 and alpha != 0.0:
|
||||||
|
seg = seg.copy()
|
||||||
|
seg[:take] = seg[:take] - alpha * bg_vec[:take]
|
||||||
|
display_cols.append(seg)
|
||||||
display_types.append(col_type)
|
display_types.append(col_type)
|
||||||
|
|
||||||
display_times = self.B_scan_times[col_min:col_max]
|
display_times = self.B_scan_times[col_min:col_max]
|
||||||
@ -1054,6 +1082,10 @@ class DataAnalyzerApp:
|
|||||||
self.B_scan_times.append(current_time)
|
self.B_scan_times.append(current_time)
|
||||||
self.B_scan_types.append(data_type)
|
self.B_scan_types.append(data_type)
|
||||||
self.last_file_time = current_time
|
self.last_file_time = current_time
|
||||||
|
# Сохраняем в буфер для фонового усреднения (не добавляем GAP)
|
||||||
|
if data_type != "GAP":
|
||||||
|
self.bscan_buffer.append((np.asarray(data_col, dtype=float), current_time, data_type))
|
||||||
|
self.prune_bscan_buffer(current_time)
|
||||||
return
|
return
|
||||||
|
|
||||||
# Используем переменный интервал между файлами
|
# Используем переменный интервал между файлами
|
||||||
@ -1084,6 +1116,61 @@ class DataAnalyzerApp:
|
|||||||
self.B_scan_times.append(current_time)
|
self.B_scan_times.append(current_time)
|
||||||
self.B_scan_types.append(data_type)
|
self.B_scan_types.append(data_type)
|
||||||
self.last_file_time = current_time
|
self.last_file_time = current_time
|
||||||
|
# Сохраняем в буфер для фонового усреднения (не добавляем GAP)
|
||||||
|
if data_type != "GAP":
|
||||||
|
self.bscan_buffer.append((np.asarray(data_col, dtype=float), current_time, data_type))
|
||||||
|
self.prune_bscan_buffer(current_time)
|
||||||
|
|
||||||
|
def prune_bscan_buffer(self, now_time: datetime):
|
||||||
|
"""Удаляет столбцы старше окна усреднения."""
|
||||||
|
try:
|
||||||
|
threshold = now_time - timedelta(seconds=self.bg_avg_window_sec)
|
||||||
|
while self.bscan_buffer and self.bscan_buffer[0][1] < threshold:
|
||||||
|
self.bscan_buffer.popleft()
|
||||||
|
except Exception:
|
||||||
|
pass
|
||||||
|
|
||||||
|
def compute_background_slice(self, row_start: int, row_end: int) -> np.ndarray:
|
||||||
|
"""Пер-строчная статистика (median/mean) по окну последних колонок для строк [row_start:row_end)."""
|
||||||
|
n_rows = max(0, row_end - row_start)
|
||||||
|
if n_rows <= 0 or not self.bscan_buffer:
|
||||||
|
return np.zeros((0,), dtype=float)
|
||||||
|
|
||||||
|
# Собираем сегменты для указанного диапазона строк
|
||||||
|
segments = []
|
||||||
|
for col, t, tname in self.bscan_buffer:
|
||||||
|
if col is None:
|
||||||
|
continue
|
||||||
|
L = len(col)
|
||||||
|
if L <= row_start:
|
||||||
|
continue
|
||||||
|
take = min(n_rows, L - row_start)
|
||||||
|
if take <= 0:
|
||||||
|
continue
|
||||||
|
seg = np.asarray(col[row_start:row_start + take], dtype=float)
|
||||||
|
segments.append(seg)
|
||||||
|
|
||||||
|
if not segments:
|
||||||
|
return np.zeros((n_rows,), dtype=float)
|
||||||
|
|
||||||
|
# Формируем матрицу (num_cols x n_rows) с NaN, заполняя доступные значения
|
||||||
|
num_cols = len(segments)
|
||||||
|
M = np.full((num_cols, n_rows), np.nan, dtype=float)
|
||||||
|
for i, seg in enumerate(segments):
|
||||||
|
take = min(n_rows, seg.shape[0])
|
||||||
|
if take > 0:
|
||||||
|
M[i, :take] = seg[:take]
|
||||||
|
|
||||||
|
# Агрегирование по времени (ось 0), игнорируя NaN
|
||||||
|
with np.errstate(all='ignore'):
|
||||||
|
if getattr(self, 'bg_method', 'median') == 'mean':
|
||||||
|
bg = np.nanmean(M, axis=0)
|
||||||
|
else:
|
||||||
|
bg = np.nanmedian(M, axis=0)
|
||||||
|
|
||||||
|
# Заменим NaN на 0 (строки без данных в окне)
|
||||||
|
bg = np.nan_to_num(bg, nan=0.0)
|
||||||
|
return bg
|
||||||
|
|
||||||
def compute_fft(self):
|
def compute_fft(self):
|
||||||
"""Вычисляем FFT спектр."""
|
"""Вычисляем FFT спектр."""
|
||||||
|
|||||||
Reference in New Issue
Block a user