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 queue
|
||||
from sys import argv
|
||||
from collections import deque
|
||||
|
||||
# ================================================================================
|
||||
# ПАРАМЕТРЫ И КОНСТАНТЫ
|
||||
@ -45,6 +46,13 @@ FILES_STORED_N_MAX = 100
|
||||
# Минимально допустимое число точек F0 для принятия данных
|
||||
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_SYNC_DET = "SYNC_DET"
|
||||
@ -453,6 +461,13 @@ class DataAnalyzerApp:
|
||||
self.processed_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_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):
|
||||
col_data = self.B_scan_data[i]
|
||||
col_type = self.B_scan_types[i]
|
||||
@ -862,7 +884,13 @@ class DataAnalyzerApp:
|
||||
row_end = min(row_max + 1, len(col_data))
|
||||
row_start = min(row_min, len(col_data) - 1)
|
||||
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_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_types.append(data_type)
|
||||
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
|
||||
|
||||
# Используем переменный интервал между файлами
|
||||
@ -1084,6 +1116,61 @@ class DataAnalyzerApp:
|
||||
self.B_scan_times.append(current_time)
|
||||
self.B_scan_types.append(data_type)
|
||||
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):
|
||||
"""Вычисляем FFT спектр."""
|
||||
|
||||
Reference in New Issue
Block a user