upd path
This commit is contained in:
2
.gitignore
vendored
Normal file
2
.gitignore
vendored
Normal file
@ -0,0 +1,2 @@
|
|||||||
|
.venv
|
||||||
|
__pycache__
|
||||||
440
main.py
440
main.py
@ -17,7 +17,7 @@ import queue
|
|||||||
# ПАРАМЕТРЫ И КОНСТАНТЫ
|
# ПАРАМЕТРЫ И КОНСТАНТЫ
|
||||||
# ================================================================================
|
# ================================================================================
|
||||||
#data_dir = r"D:\data"
|
#data_dir = r"D:\data"
|
||||||
data_dir = "./data"
|
data_dir = "/home/awe/Documents/E502_ADC_BF_PC_companion/tmp"
|
||||||
PeriodIntegrate = 2
|
PeriodIntegrate = 2
|
||||||
pontInOneFqChange = 86
|
pontInOneFqChange = 86
|
||||||
|
|
||||||
@ -40,10 +40,10 @@ STANDARD_FOURIER_COLS = 100
|
|||||||
MAX_PROCESSING_TIME_MS = 250
|
MAX_PROCESSING_TIME_MS = 250
|
||||||
|
|
||||||
# ПЕРЕЧИСЛЕНИЕ ТИПОВ ДАННЫХ
|
# ПЕРЕЧИСЛЕНИЕ ТИПОВ ДАННЫХ
|
||||||
DATA_TYPE_RAW = "RAW"
|
DATA_TYPE_RAW = "RAW"
|
||||||
DATA_TYPE_SYNC_DET = "SYNC_DET"
|
DATA_TYPE_SYNC_DET = "SYNC_DET"
|
||||||
DATA_TYPE_FOURIER = "FOURIER"
|
DATA_TYPE_FOURIER = "FOURIER"
|
||||||
DATA_TYPE_HEX = "HEX"
|
DATA_TYPE_HEX = "HEX"
|
||||||
|
|
||||||
# Режим обработки FOURIER файлов
|
# Режим обработки FOURIER файлов
|
||||||
FOURIER_MODE = 'collapse_mean'
|
FOURIER_MODE = 'collapse_mean'
|
||||||
@ -63,23 +63,23 @@ DEFAULT_FILE_POLL_INTERVAL_MS = 100 # 100 мс
|
|||||||
# ВСПОМОГАТЕЛЬНЫЕ ФУНКЦИИ
|
# ВСПОМОГАТЕЛЬНЫЕ ФУНКЦИИ
|
||||||
# ================================================================================
|
# ================================================================================
|
||||||
|
|
||||||
def detect_data_type(first_line):
|
def detect_data_type(first_line):
|
||||||
"""Определяет тип данных по первой строке файла.
|
"""Определяет тип данных по первой строке файла.
|
||||||
|
|
||||||
Логика: если первая строка начинается с ключевого слова RAW/SYNC_DET/FOURIER/FFT,
|
Логика: если первая строка начинается с ключевого слова RAW/SYNC_DET/FOURIER/FFT,
|
||||||
считаем соответствующий тип. Иначе — HEX.
|
считаем соответствующий тип. Иначе — HEX.
|
||||||
"""
|
"""
|
||||||
try:
|
try:
|
||||||
up = first_line.strip().upper()
|
up = first_line.strip().upper()
|
||||||
if up.startswith('RAW'):
|
if up.startswith('RAW'):
|
||||||
return DATA_TYPE_RAW
|
return DATA_TYPE_RAW
|
||||||
if up.startswith('SYNC_DET') or up.startswith('SYNC DET'):
|
if up.startswith('SYNC_DET') or up.startswith('SYNC DET'):
|
||||||
return DATA_TYPE_SYNC_DET
|
return DATA_TYPE_SYNC_DET
|
||||||
if up.startswith('FOURIER') or up.startswith('FFT'):
|
if up.startswith('FOURIER') or up.startswith('FFT'):
|
||||||
return DATA_TYPE_FOURIER
|
return DATA_TYPE_FOURIER
|
||||||
return DATA_TYPE_HEX
|
return DATA_TYPE_HEX
|
||||||
except Exception:
|
except Exception:
|
||||||
return DATA_TYPE_HEX
|
return DATA_TYPE_HEX
|
||||||
|
|
||||||
|
|
||||||
def resize_1d_interpolate(data, target_size):
|
def resize_1d_interpolate(data, target_size):
|
||||||
@ -114,128 +114,128 @@ def resize_2d_interpolate(data, target_rows, target_cols):
|
|||||||
return data_resampled
|
return data_resampled
|
||||||
|
|
||||||
|
|
||||||
def load_data_with_type(filename):
|
def load_data_with_type(filename):
|
||||||
"""Загружает данные и определяет их тип по первой строке."""
|
"""Загружает данные и определяет их тип по первой строке."""
|
||||||
with open(filename, 'r') as f:
|
with open(filename, 'r') as f:
|
||||||
first_line = f.readline()
|
first_line = f.readline()
|
||||||
|
|
||||||
detected_type = detect_data_type(first_line)
|
detected_type = detect_data_type(first_line)
|
||||||
|
|
||||||
if detected_type != DATA_TYPE_HEX:
|
if detected_type != DATA_TYPE_HEX:
|
||||||
try:
|
try:
|
||||||
data = np.loadtxt(filename, skiprows=1)
|
data = np.loadtxt(filename, skiprows=1)
|
||||||
except:
|
except:
|
||||||
data = np.loadtxt(filename)
|
data = np.loadtxt(filename)
|
||||||
return detected_type, data
|
return detected_type, data
|
||||||
|
|
||||||
# HEX формат: строки вида 0xAABBBBBB, где AA — тип, BBBBBB — int24_t
|
# HEX формат: строки вида 0xAABBBBBB, где AA — тип, BBBBBB — int24_t
|
||||||
return parse_hex_file(filename)
|
return parse_hex_file(filename)
|
||||||
|
|
||||||
|
|
||||||
def parse_hex_file(filename):
|
def parse_hex_file(filename):
|
||||||
"""Парсит HEX формат с разделением по FE и мапит к RAW/SYNC_DET/FOURIER.
|
"""Парсит HEX формат с разделением по FE и мапит к RAW/SYNC_DET/FOURIER.
|
||||||
|
|
||||||
Возвращает (data_type, data), где data может быть:
|
Возвращает (data_type, data), где data может быть:
|
||||||
- numpy.ndarray (1D) для одного сегмента
|
- numpy.ndarray (1D) для одного сегмента
|
||||||
- list[numpy.ndarray] для нескольких сегментов (используется для FOURIER, а также RAW/SYNC_DET)
|
- list[numpy.ndarray] для нескольких сегментов (используется для FOURIER, а также RAW/SYNC_DET)
|
||||||
"""
|
"""
|
||||||
|
|
||||||
def to_int24(v):
|
def to_int24(v):
|
||||||
x = int(v, 16)
|
x = int(v, 16)
|
||||||
if x & 0x800000:
|
if x & 0x800000:
|
||||||
x -= 0x1000000
|
x -= 0x1000000
|
||||||
return float(x)
|
return float(x)
|
||||||
|
|
||||||
# Текущий накапливаемый сегмент
|
# Текущий накапливаемый сегмент
|
||||||
cur = {"D0": [], "F0": [], "F1": [], "F2": [], "F3": [], "F4": []}
|
cur = {"D0": [], "F0": [], "F1": [], "F2": [], "F3": [], "F4": []}
|
||||||
# Списки сегментов по типам данных
|
# Списки сегментов по типам данных
|
||||||
seg_raw = []
|
seg_raw = []
|
||||||
seg_sync = []
|
seg_sync = []
|
||||||
seg_fourier = []
|
seg_fourier = []
|
||||||
|
|
||||||
def finalize_segment():
|
def finalize_segment():
|
||||||
nonlocal cur
|
nonlocal cur
|
||||||
# Приоритет выбора, что считать сегментом
|
# Приоритет выбора, что считать сегментом
|
||||||
if cur["F4"]:
|
if cur["F4"]:
|
||||||
seg_fourier.append(np.asarray(cur["F4"], dtype=float))
|
seg_fourier.append(np.asarray(cur["F4"], dtype=float))
|
||||||
elif cur["F3"]:
|
elif cur["F3"]:
|
||||||
arr = np.asarray(cur["F3"], dtype=float)
|
arr = np.asarray(cur["F3"], dtype=float)
|
||||||
seg_fourier.append(np.sqrt(np.maximum(0.0, arr)))
|
seg_fourier.append(np.sqrt(np.maximum(0.0, arr)))
|
||||||
elif cur["F1"] and cur["F2"] and len(cur["F1"]) == len(cur["F2"]):
|
elif cur["F1"] and cur["F2"] and len(cur["F1"]) == len(cur["F2"]):
|
||||||
re = np.asarray(cur["F1"], dtype=float)
|
re = np.asarray(cur["F1"], dtype=float)
|
||||||
im = np.asarray(cur["F2"], dtype=float)
|
im = np.asarray(cur["F2"], dtype=float)
|
||||||
seg_fourier.append(np.sqrt(re * re + im * im))
|
seg_fourier.append(np.sqrt(re * re + im * im))
|
||||||
elif cur["F0"]:
|
elif cur["F0"]:
|
||||||
seg_sync.append(np.asarray(cur["F0"], dtype=float))
|
seg_sync.append(np.asarray(cur["F0"], dtype=float))
|
||||||
elif cur["D0"]:
|
elif cur["D0"]:
|
||||||
seg_raw.append(np.asarray(cur["D0"], dtype=float))
|
seg_raw.append(np.asarray(cur["D0"], dtype=float))
|
||||||
# Сброс
|
# Сброс
|
||||||
cur = {"D0": [], "F0": [], "F1": [], "F2": [], "F3": [], "F4": []}
|
cur = {"D0": [], "F0": [], "F1": [], "F2": [], "F3": [], "F4": []}
|
||||||
|
|
||||||
with open(filename, 'r') as f:
|
with open(filename, 'r') as f:
|
||||||
for line in f:
|
for line in f:
|
||||||
s = line.strip()
|
s = line.strip()
|
||||||
if not s:
|
if not s:
|
||||||
continue
|
continue
|
||||||
# Требование: учитывать только строки, начинающиеся с 0x/0X
|
# Требование: учитывать только строки, начинающиеся с 0x/0X
|
||||||
if not (s.startswith('0x') or s.startswith('0X')):
|
if not (s.startswith('0x') or s.startswith('0X')):
|
||||||
continue
|
continue
|
||||||
h = s[2:]
|
h = s[2:]
|
||||||
h = ''.join(ch for ch in h if ch in '0123456789abcdefABCDEF')
|
h = ''.join(ch for ch in h if ch in '0123456789abcdefABCDEF')
|
||||||
if len(h) < 2:
|
if len(h) < 2:
|
||||||
continue
|
continue
|
||||||
t_byte = h[:2].upper()
|
t_byte = h[:2].upper()
|
||||||
|
|
||||||
# FE — завершить текущий сегмент
|
# FE — завершить текущий сегмент
|
||||||
if t_byte == 'FE':
|
if t_byte == 'FE':
|
||||||
finalize_segment()
|
finalize_segment()
|
||||||
continue
|
continue
|
||||||
|
|
||||||
# E0..E9 — игнор
|
# E0..E9 — игнор
|
||||||
if t_byte.startswith('E') and len(t_byte) == 2 and t_byte[1] in '0123456789':
|
if t_byte.startswith('E') and len(t_byte) == 2 and t_byte[1] in '0123456789':
|
||||||
continue
|
continue
|
||||||
|
|
||||||
# 00 — цифровые биты, пока пропускаем
|
# 00 — цифровые биты, пока пропускаем
|
||||||
if t_byte == '00':
|
if t_byte == '00':
|
||||||
continue
|
continue
|
||||||
|
|
||||||
if len(h) < 8:
|
if len(h) < 8:
|
||||||
continue
|
continue
|
||||||
# Значение 24 бита
|
# Значение 24 бита
|
||||||
val_hex = h[2:8]
|
val_hex = h[2:8]
|
||||||
try:
|
try:
|
||||||
value = to_int24(val_hex)
|
value = to_int24(val_hex)
|
||||||
except Exception:
|
except Exception:
|
||||||
continue
|
continue
|
||||||
|
|
||||||
if t_byte == 'D0':
|
if t_byte == 'D0':
|
||||||
cur['D0'].append(value)
|
cur['D0'].append(value)
|
||||||
elif t_byte == 'F0':
|
elif t_byte == 'F0':
|
||||||
cur['F0'].append(value)
|
cur['F0'].append(value)
|
||||||
elif t_byte == 'F1':
|
elif t_byte == 'F1':
|
||||||
cur['F1'].append(value)
|
cur['F1'].append(value)
|
||||||
elif t_byte == 'F2':
|
elif t_byte == 'F2':
|
||||||
cur['F2'].append(value)
|
cur['F2'].append(value)
|
||||||
elif t_byte == 'F3':
|
elif t_byte == 'F3':
|
||||||
cur['F3'].append(value)
|
cur['F3'].append(value)
|
||||||
elif t_byte == 'F4':
|
elif t_byte == 'F4':
|
||||||
cur['F4'].append(value)
|
cur['F4'].append(value)
|
||||||
else:
|
else:
|
||||||
# Неизвестные — пропускаем
|
# Неизвестные — пропускаем
|
||||||
continue
|
continue
|
||||||
|
|
||||||
# Финализируем хвост
|
# Финализируем хвост
|
||||||
finalize_segment()
|
finalize_segment()
|
||||||
|
|
||||||
if seg_fourier:
|
if seg_fourier:
|
||||||
return DATA_TYPE_FOURIER, seg_fourier
|
return DATA_TYPE_FOURIER, seg_fourier
|
||||||
if seg_sync:
|
if seg_sync:
|
||||||
# Если несколько, вернём список сегментов
|
# Если несколько, вернём список сегментов
|
||||||
return DATA_TYPE_SYNC_DET, seg_sync if len(seg_sync) > 1 else seg_sync[0]
|
return DATA_TYPE_SYNC_DET, seg_sync if len(seg_sync) > 1 else seg_sync[0]
|
||||||
if seg_raw:
|
if seg_raw:
|
||||||
return DATA_TYPE_RAW, seg_raw if len(seg_raw) > 1 else seg_raw[0]
|
return DATA_TYPE_RAW, seg_raw if len(seg_raw) > 1 else seg_raw[0]
|
||||||
|
|
||||||
return DATA_TYPE_RAW, np.asarray([], dtype=float)
|
return DATA_TYPE_RAW, np.asarray([], dtype=float)
|
||||||
|
|
||||||
|
|
||||||
def get_file_time_with_milliseconds(filename):
|
def get_file_time_with_milliseconds(filename):
|
||||||
@ -279,10 +279,10 @@ class DataAnalyzerApp:
|
|||||||
os.chdir(self.data_dir)
|
os.chdir(self.data_dir)
|
||||||
|
|
||||||
# Инициализируем с существующими файлами
|
# Инициализируем с существующими файлами
|
||||||
existing_files = sorted([
|
existing_files = sorted([
|
||||||
f for f in os.listdir()
|
f for f in os.listdir()
|
||||||
if f.lower().endswith(('.txt', '.txt1', '.txt2', '.csv'))
|
if f.lower().endswith(('.txt', '.txt1', '.txt2', '.csv'))
|
||||||
])
|
])
|
||||||
self.processed_files = set(existing_files)
|
self.processed_files = set(existing_files)
|
||||||
|
|
||||||
if existing_files:
|
if existing_files:
|
||||||
@ -916,33 +916,33 @@ class DataAnalyzerApp:
|
|||||||
|
|
||||||
return True, None
|
return True, None
|
||||||
|
|
||||||
def process_fourier_data(self, A, original_size):
|
def process_fourier_data(self, A, original_size):
|
||||||
"""Обработка FOURIER без интерполяции. Поддерживает несколько сегментов."""
|
"""Обработка FOURIER без интерполяции. Поддерживает несколько сегментов."""
|
||||||
columns_to_add = []
|
columns_to_add = []
|
||||||
|
|
||||||
# A может быть: list[np.ndarray] (из HEX) или numpy.ndarray
|
# A может быть: list[np.ndarray] (из HEX) или numpy.ndarray
|
||||||
if isinstance(A, list):
|
if isinstance(A, list):
|
||||||
for seg in A:
|
for seg in A:
|
||||||
col = np.asarray(seg, dtype=float)
|
col = np.asarray(seg, dtype=float)
|
||||||
columns_to_add.append(col)
|
columns_to_add.append(col)
|
||||||
return True, columns_to_add
|
return True, columns_to_add
|
||||||
|
|
||||||
if A.ndim == 1:
|
if A.ndim == 1:
|
||||||
columns_to_add.append(A.astype(float))
|
columns_to_add.append(A.astype(float))
|
||||||
return True, columns_to_add
|
return True, columns_to_add
|
||||||
|
|
||||||
# Если A двумерный: считаем колонками столбцы или строки — выбираем более длинное измерение как длину спектра
|
# Если A двумерный: считаем колонками столбцы или строки — выбираем более длинное измерение как длину спектра
|
||||||
if A.ndim == 2:
|
if A.ndim == 2:
|
||||||
rows, cols = A.shape
|
rows, cols = A.shape
|
||||||
if rows >= cols:
|
if rows >= cols:
|
||||||
for i in range(cols):
|
for i in range(cols):
|
||||||
columns_to_add.append(A[:, i].astype(float))
|
columns_to_add.append(A[:, i].astype(float))
|
||||||
else:
|
else:
|
||||||
for i in range(rows):
|
for i in range(rows):
|
||||||
columns_to_add.append(A[i, :].astype(float))
|
columns_to_add.append(A[i, :].astype(float))
|
||||||
return True, columns_to_add
|
return True, columns_to_add
|
||||||
|
|
||||||
return True, columns_to_add
|
return True, columns_to_add
|
||||||
|
|
||||||
def add_bscan_column(self, data_col, current_time, data_type):
|
def add_bscan_column(self, data_col, current_time, data_type):
|
||||||
"""Добавить колонку в B-скан (может быть разного размера)."""
|
"""Добавить колонку в B-скан (может быть разного размера)."""
|
||||||
@ -1105,34 +1105,34 @@ class DataAnalyzerApp:
|
|||||||
bscan_col = None
|
bscan_col = None
|
||||||
add_to_bscan = False
|
add_to_bscan = False
|
||||||
|
|
||||||
if data_type == DATA_TYPE_RAW:
|
if data_type == DATA_TYPE_RAW:
|
||||||
# Может прийти список сегментов (HEX с FE)
|
# Может прийти список сегментов (HEX с FE)
|
||||||
if isinstance(A, list):
|
if isinstance(A, list):
|
||||||
for i, seg in enumerate(A):
|
for i, seg in enumerate(A):
|
||||||
add_to_bscan, bscan_col = self.process_raw_data(np.asarray(seg), len(seg))
|
add_to_bscan, bscan_col = self.process_raw_data(np.asarray(seg), len(seg))
|
||||||
if add_to_bscan and bscan_col is not None:
|
if add_to_bscan and bscan_col is not None:
|
||||||
col_time = file_time + timedelta(milliseconds=i * 10)
|
col_time = file_time + timedelta(milliseconds=i * 10)
|
||||||
self.bscan_queue.put((bscan_col, col_time, DATA_TYPE_RAW))
|
self.bscan_queue.put((bscan_col, col_time, DATA_TYPE_RAW))
|
||||||
add_to_bscan, bscan_col = False, None
|
add_to_bscan, bscan_col = False, None
|
||||||
else:
|
else:
|
||||||
add_to_bscan, bscan_col = self.process_raw_data(A, original_size)
|
add_to_bscan, bscan_col = self.process_raw_data(A, original_size)
|
||||||
elif data_type == DATA_TYPE_SYNC_DET:
|
elif data_type == DATA_TYPE_SYNC_DET:
|
||||||
if isinstance(A, list):
|
if isinstance(A, list):
|
||||||
for i, seg in enumerate(A):
|
for i, seg in enumerate(A):
|
||||||
add_to_bscan, bscan_col = self.process_sync_det_data(np.asarray(seg), len(seg))
|
add_to_bscan, bscan_col = self.process_sync_det_data(np.asarray(seg), len(seg))
|
||||||
if add_to_bscan and bscan_col is not None:
|
if add_to_bscan and bscan_col is not None:
|
||||||
col_time = file_time + timedelta(milliseconds=i * 10)
|
col_time = file_time + timedelta(milliseconds=i * 10)
|
||||||
self.bscan_queue.put((bscan_col, col_time, DATA_TYPE_SYNC_DET))
|
self.bscan_queue.put((bscan_col, col_time, DATA_TYPE_SYNC_DET))
|
||||||
add_to_bscan, bscan_col = False, None
|
add_to_bscan, bscan_col = False, None
|
||||||
else:
|
else:
|
||||||
add_to_bscan, bscan_col = self.process_sync_det_data(A, original_size)
|
add_to_bscan, bscan_col = self.process_sync_det_data(A, original_size)
|
||||||
elif data_type == DATA_TYPE_FOURIER:
|
elif data_type == DATA_TYPE_FOURIER:
|
||||||
add_to_bscan, columns = self.process_fourier_data(A, original_size)
|
add_to_bscan, columns = self.process_fourier_data(A, original_size)
|
||||||
if add_to_bscan and columns:
|
if add_to_bscan and columns:
|
||||||
for i, col in enumerate(columns):
|
for i, col in enumerate(columns):
|
||||||
col_time = file_time + timedelta(milliseconds=i * 10)
|
col_time = file_time + timedelta(milliseconds=i * 10)
|
||||||
self.bscan_queue.put((col, col_time, DATA_TYPE_FOURIER))
|
self.bscan_queue.put((col, col_time, DATA_TYPE_FOURIER))
|
||||||
bscan_col = None
|
bscan_col = None
|
||||||
|
|
||||||
if add_to_bscan and bscan_col is not None and data_type != DATA_TYPE_FOURIER:
|
if add_to_bscan and bscan_col is not None and data_type != DATA_TYPE_FOURIER:
|
||||||
self.bscan_queue.put((bscan_col, file_time, data_type))
|
self.bscan_queue.put((bscan_col, file_time, data_type))
|
||||||
@ -1177,23 +1177,23 @@ class DataAnalyzerApp:
|
|||||||
for fname in new_files:
|
for fname in new_files:
|
||||||
time_start = time.perf_counter()
|
time_start = time.perf_counter()
|
||||||
|
|
||||||
try:
|
try:
|
||||||
data_type, A = load_data_with_type(fname)
|
data_type, A = load_data_with_type(fname)
|
||||||
# Поддержка списка сегментов (HEX с FE)
|
# Поддержка списка сегментов (HEX с FE)
|
||||||
if isinstance(A, list):
|
if isinstance(A, list):
|
||||||
original_size = len(A[0]) if len(A) > 0 else 0
|
original_size = len(A[0]) if len(A) > 0 else 0
|
||||||
elif isinstance(A, np.ndarray):
|
elif isinstance(A, np.ndarray):
|
||||||
original_size = A.shape[0]
|
original_size = A.shape[0]
|
||||||
else:
|
else:
|
||||||
original_size = 0
|
original_size = 0
|
||||||
|
|
||||||
# Если после парсинга данных нет — пропускаем файл
|
# Если после парсинга данных нет — пропускаем файл
|
||||||
if (isinstance(A, list) and len(A) == 0) or (isinstance(A, np.ndarray) and A.size == 0):
|
if (isinstance(A, list) and len(A) == 0) or (isinstance(A, np.ndarray) and A.size == 0):
|
||||||
timestamp = datetime.now().strftime("%H:%M:%S.%f")[:-3]
|
timestamp = datetime.now().strftime("%H:%M:%S.%f")[:-3]
|
||||||
print(f"[{timestamp}] ⏭️ SKIP {fname} (no data parsed)")
|
print(f"[{timestamp}] ⏭️ SKIP {fname} (no data parsed)")
|
||||||
self.skipped_count += 1
|
self.skipped_count += 1
|
||||||
self.processed_files.add(fname)
|
self.processed_files.add(fname)
|
||||||
continue
|
continue
|
||||||
|
|
||||||
elapsed_time_ms = (time.perf_counter() - time_start) * 1000
|
elapsed_time_ms = (time.perf_counter() - time_start) * 1000
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user