From 9d3fc41c4b87edacdbc7190c99ff94e32b30bf48 Mon Sep 17 00:00:00 2001 From: Sergey Revyakin Date: Fri, 6 Mar 2026 17:34:30 +0700 Subject: [PATCH] =?UTF-8?q?=D0=B4=D0=BE=D0=B1=D0=B0=D0=B2=D0=B8=D0=BB=20?= =?UTF-8?q?=D0=BB=D0=BE=D0=B3=D0=B8=D1=80=D0=BE=D0=B2=D0=B0=D0=BD=D0=B8?= =?UTF-8?q?=D0=B5=20=D0=B2=D1=80=D0=B5=D0=BC=D0=B5=D0=BD=D0=B8=20=D0=BF?= =?UTF-8?q?=D1=80=D0=B8=D1=85=D0=BE=D0=B4=D0=B0=20=D0=BF=D0=B0=D0=BA=D0=B5?= =?UTF-8?q?=D1=82=D0=B0=20=D0=B2=20=D0=B1=D1=83=D1=84=D0=B5=D1=80=20=D0=B4?= =?UTF-8?q?=D0=BB=D1=8F=20=D0=B4=D0=B5=D0=B1=D0=B0=D0=B3=D0=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/core/data_buffer.py | 44 +++++++++++++++++++++++++++++++++- src/core/sig_n_medi_collect.py | 20 ++++++++++++---- src/embedded_3300.py | 5 ++-- src/embedded_433.py | 5 ++-- src/embedded_4500.py | 5 ++-- src/embedded_5200.py | 5 ++-- src/embedded_5800.py | 5 ++-- src/embedded_750.py | 5 ++-- src/embedded_868.py | 5 ++-- 9 files changed, 80 insertions(+), 19 deletions(-) diff --git a/src/core/data_buffer.py b/src/core/data_buffer.py index 388b0b5..3b961df 100644 --- a/src/core/data_buffer.py +++ b/src/core/data_buffer.py @@ -1,5 +1,6 @@ import os import statistics +from datetime import datetime # Более лучшая версия кода есть в FRScanner @@ -36,6 +37,7 @@ class DataBuffer: self.is_init = False self.buffer = [[0 for _ in range(self.columns_size)] for _ in range(self.line_size)] + self.buffer_timestamps = [[None for _ in range(self.columns_size)] for _ in range(self.line_size)] self.buffer_medians = [0.0] * self.line_size self.buffer_mads = [0.0] * self.line_size self.buffer_alarms = [0] * self.line_size @@ -60,6 +62,9 @@ class DataBuffer: def get_buffer(self): return self.buffer + def get_timestamps(self): + return self.buffer_timestamps + def get_medians(self): return self.buffer_medians @@ -86,6 +91,15 @@ class DataBuffer: deviations = [abs(v - median) for v in values] return statistics.median(deviations) + @staticmethod + def _format_ts(timestamp): + if timestamp is None: + return 'None' + try: + return datetime.fromtimestamp(float(timestamp)).isoformat(sep=' ', timespec='milliseconds') + except Exception: + return str(timestamp) + def medians(self): """ Вычислить медиану и MAD по строкам буфера. @@ -116,13 +130,31 @@ class DataBuffer: return [None] * self.line_size return [self.get_threshold(i, k) for i in range(self.line_size)] + def log_threshold_update(self, updated_column): + if not self.check_init(): + return + + now_str = datetime.now().isoformat(sep=' ', timespec='milliseconds') + freq_tag = self.freq_tag or 'unknown' + print(f'[threshold-update][{freq_tag}] now={now_str} updated_column={updated_column}') + for i in range(self.line_size): + threshold_on = self.get_threshold(i, self.mad_k_on) + threshold_off = self.get_threshold(i, self.mad_k_off) + packet_times = [self._format_ts(ts) for ts in self.buffer_timestamps[i]] + print( + f' ch={i} median={self.buffer_medians[i]:.6f} ' + f'mad={self.buffer_mads[i]:.6f} ' + f'threshold_on={threshold_on:.6f} threshold_off={threshold_off:.6f} ' + f'packet_times={packet_times}' + ) + def alarms_fill_zeros(self): self.buffer_alarms = [0] * self.line_size self.trend_streak = [0] * self.line_size self.prev_values = [None] * self.line_size self.last_alarm_channels = [] - def update(self, data): + def update(self, data, packet_timestamps=None): """ Обновление буфера. Если номер текущего чтения совпадает с количеством прореживающего множителя на текущем обновлении буфера, то @@ -135,20 +167,30 @@ class DataBuffer: До тех пор, пока множитель на итерации меньше фиксированного, увеличиваем в два раза. В противном случае - увеличиваем номер чтения. :param data: Массив с метриками сигнала по каналам. + :param packet_timestamps: Времена пакетов SDR для каждой метрики канала. :return: None """ + if packet_timestamps is None: + packet_timestamps = [None] * self.line_size + if len(packet_timestamps) != self.line_size: + raise ValueError('packet_timestamps length must match number of channels') if self.current_counter == self.thinning_counter: + updated_column = self.current_column for i in range(self.line_size): self.buffer[i][self.current_column] = data[i] + self.buffer_timestamps[i][self.current_column] = packet_timestamps[i] self.current_column = (self.current_column + 1) % self.columns_size self.medians() + if self.check_init(): + self.log_threshold_update(updated_column) self.current_counter = 1 if self.current_column == 0: if self.thinning_counter == 1: self.is_init = True self.medians() print('Начальная калибровка завершена.') + self.log_threshold_update(updated_column) if self.thinning_counter < self.num_of_thinning_iter: self.thinning_counter *= 2 else: diff --git a/src/core/sig_n_medi_collect.py b/src/core/sig_n_medi_collect.py index bd196f4..be703ee 100644 --- a/src/core/sig_n_medi_collect.py +++ b/src/core/sig_n_medi_collect.py @@ -1,5 +1,6 @@ import os import math +import time import numpy as np from typing import Union from common.runtime import load_root_env @@ -25,6 +26,7 @@ class Signal: self.conv_method = conv_method self.signal = [] self.signal_abs = [] + self.last_packet_ts = None def get_signal(self): """ @@ -33,6 +35,9 @@ class Signal: """ return self.signal, self.signal_abs + def get_last_packet_ts(self): + return self.last_packet_ts + def clear(self) -> None: """ Очистить массив с сигналом после предобработки? @@ -40,6 +45,7 @@ class Signal: """ self.signal = [] self.signal_abs = [] + self.last_packet_ts = None def signal_preprocessing(self, length) -> float: """ @@ -91,6 +97,7 @@ class Signal: self.signal = np.concatenate((self.signal, y), axis=None) return 0 else: + self.last_packet_ts = time.time() preproc_signal = self.signal_preprocessing(length) return preproc_signal @@ -105,25 +112,30 @@ class SignalsArray: def __init__(self): self.sig_array = [] + self.sig_ts_array = [] self.counter = 0 - def fill_sig_arr(self, metrica, num_chs=3): + def fill_sig_arr(self, metrica, packet_ts=None, num_chs=3): """ Аппендим характеристику сигнала (метрику) в массив длиной num_chs. :param metrica: Характеристика сигнала (метрика). + :param packet_ts: Время завершения набора пакета с SDR для текущей метрики. :param num_chs: Количество каналов на частоте. :return: Индекс канала внутри частоты и массив с характеристиками, если заполнен, иначе - пустой. """ if num_chs: if self.counter < num_chs: self.sig_array.append(metrica) + self.sig_ts_array.append(packet_ts) self.counter += 1 if self.counter == num_chs: arr = self.sig_array + arr_ts = self.sig_ts_array self.sig_array = [] + self.sig_ts_array = [] self.counter = 0 - return num_chs - 1, arr + return num_chs - 1, arr, arr_ts else: - return self.counter - 1, [] + return self.counter - 1, [], [] else: - return 0, [] + return 0, [], [] diff --git a/src/embedded_3300.py b/src/embedded_3300.py index 4165edf..d1267c3 100644 --- a/src/embedded_3300.py +++ b/src/embedded_3300.py @@ -75,11 +75,12 @@ def work(lvl): freq = get_centre_freq(f) signal_length = get_signal_length(freq) median = tmp_signal.fill_signal(lvl, signal_length) + packet_ts = tmp_signal.get_last_packet_ts() if median: try: num_chs, circle_buffer = multi_channel.check_f(f) - cur_channel, sigs_array = tmp_sigs_array.fill_sig_arr(median, num_chs) + cur_channel, sigs_array, sigs_ts_array = tmp_sigs_array.fill_sig_arr(median, packet_ts=packet_ts, num_chs=num_chs) if sigs_array: print('Значения на {0}: {1}'.format(freq, sigs_array)) @@ -90,7 +91,7 @@ def work(lvl): print('----ALARM---- ', freq) multi_channel.db_alarms_zeros(circle_buffer) else: - circle_buffer.update(sigs_array) + circle_buffer.update(sigs_array, packet_timestamps=sigs_ts_array) if telemetry_enabled: diff --git a/src/embedded_433.py b/src/embedded_433.py index 0471e22..3f72a6f 100644 --- a/src/embedded_433.py +++ b/src/embedded_433.py @@ -75,11 +75,12 @@ def work(lvl): freq = get_centre_freq(f) signal_length = get_signal_length(freq) median = tmp_signal.fill_signal(lvl, signal_length) + packet_ts = tmp_signal.get_last_packet_ts() if median: try: num_chs, circle_buffer = multi_channel.check_f(f) - cur_channel, sigs_array = tmp_sigs_array.fill_sig_arr(median, num_chs) + cur_channel, sigs_array, sigs_ts_array = tmp_sigs_array.fill_sig_arr(median, packet_ts=packet_ts, num_chs=num_chs) if sigs_array: print('Значения на {0}: {1}'.format(freq, sigs_array)) @@ -90,7 +91,7 @@ def work(lvl): print('----ALARM---- ', freq) multi_channel.db_alarms_zeros(circle_buffer) else: - circle_buffer.update(sigs_array) + circle_buffer.update(sigs_array, packet_timestamps=sigs_ts_array) if telemetry_enabled: diff --git a/src/embedded_4500.py b/src/embedded_4500.py index 298dbcd..a921188 100644 --- a/src/embedded_4500.py +++ b/src/embedded_4500.py @@ -75,11 +75,12 @@ def work(lvl): freq = get_centre_freq(f) signal_length = get_signal_length(freq) median = tmp_signal.fill_signal(lvl, signal_length) + packet_ts = tmp_signal.get_last_packet_ts() if median: try: num_chs, circle_buffer = multi_channel.check_f(f) - cur_channel, sigs_array = tmp_sigs_array.fill_sig_arr(median, num_chs) + cur_channel, sigs_array, sigs_ts_array = tmp_sigs_array.fill_sig_arr(median, packet_ts=packet_ts, num_chs=num_chs) if sigs_array: print('Значения на {0}: {1}'.format(freq, sigs_array)) @@ -90,7 +91,7 @@ def work(lvl): print('----ALARM---- ', freq) multi_channel.db_alarms_zeros(circle_buffer) else: - circle_buffer.update(sigs_array) + circle_buffer.update(sigs_array, packet_timestamps=sigs_ts_array) if telemetry_enabled: diff --git a/src/embedded_5200.py b/src/embedded_5200.py index 576a7fb..91a3f04 100644 --- a/src/embedded_5200.py +++ b/src/embedded_5200.py @@ -75,11 +75,12 @@ def work(lvl): freq = get_centre_freq(f) signal_length = get_signal_length(freq) median = tmp_signal.fill_signal(lvl, signal_length) + packet_ts = tmp_signal.get_last_packet_ts() if median: try: num_chs, circle_buffer = multi_channel.check_f(f) - cur_channel, sigs_array = tmp_sigs_array.fill_sig_arr(median, num_chs) + cur_channel, sigs_array, sigs_ts_array = tmp_sigs_array.fill_sig_arr(median, packet_ts=packet_ts, num_chs=num_chs) if sigs_array: print('Значения на {0}: {1}'.format(freq, sigs_array)) @@ -90,7 +91,7 @@ def work(lvl): print('----ALARM---- ', freq) multi_channel.db_alarms_zeros(circle_buffer) else: - circle_buffer.update(sigs_array) + circle_buffer.update(sigs_array, packet_timestamps=sigs_ts_array) if telemetry_enabled: diff --git a/src/embedded_5800.py b/src/embedded_5800.py index a87b1cd..f7dd93d 100644 --- a/src/embedded_5800.py +++ b/src/embedded_5800.py @@ -75,11 +75,12 @@ def work(lvl): freq = get_centre_freq(f) signal_length = get_signal_length(freq) median = tmp_signal.fill_signal(lvl, signal_length) + packet_ts = tmp_signal.get_last_packet_ts() if median: try: num_chs, circle_buffer = multi_channel.check_f(f) - cur_channel, sigs_array = tmp_sigs_array.fill_sig_arr(median, num_chs) + cur_channel, sigs_array, sigs_ts_array = tmp_sigs_array.fill_sig_arr(median, packet_ts=packet_ts, num_chs=num_chs) if sigs_array: print('Значения на {0}: {1}'.format(freq, sigs_array)) @@ -90,7 +91,7 @@ def work(lvl): print('----ALARM---- ', freq) multi_channel.db_alarms_zeros(circle_buffer) else: - circle_buffer.update(sigs_array) + circle_buffer.update(sigs_array, packet_timestamps=sigs_ts_array) if telemetry_enabled: diff --git a/src/embedded_750.py b/src/embedded_750.py index 8ead9b9..38c36e7 100644 --- a/src/embedded_750.py +++ b/src/embedded_750.py @@ -75,13 +75,14 @@ def work(lvl): freq = get_centre_freq(f) signal_length = get_signal_length(freq) median = tmp_signal.fill_signal(lvl, signal_length) + packet_ts = tmp_signal.get_last_packet_ts() if median: print(1) try: num_chs, circle_buffer = multi_channel.check_f(f) print(num_chs, circle_buffer) - cur_channel, sigs_array = tmp_sigs_array.fill_sig_arr(median, num_chs) + cur_channel, sigs_array, sigs_ts_array = tmp_sigs_array.fill_sig_arr(median, packet_ts=packet_ts, num_chs=num_chs) print(3) if sigs_array: @@ -93,7 +94,7 @@ def work(lvl): print('----ALARM---- ', freq) multi_channel.db_alarms_zeros(circle_buffer) else: - circle_buffer.update(sigs_array) + circle_buffer.update(sigs_array, packet_timestamps=sigs_ts_array) if telemetry_enabled: diff --git a/src/embedded_868.py b/src/embedded_868.py index fea476a..cc7bbe8 100644 --- a/src/embedded_868.py +++ b/src/embedded_868.py @@ -75,11 +75,12 @@ def work(lvl): freq = get_centre_freq(f) signal_length = get_signal_length(freq) median = tmp_signal.fill_signal(lvl, signal_length) + packet_ts = tmp_signal.get_last_packet_ts() if median: try: num_chs, circle_buffer = multi_channel.check_f(f) - cur_channel, sigs_array = tmp_sigs_array.fill_sig_arr(median, num_chs) + cur_channel, sigs_array, sigs_ts_array = tmp_sigs_array.fill_sig_arr(median, packet_ts=packet_ts, num_chs=num_chs) if sigs_array: print('Значения на {0}: {1}'.format(freq, sigs_array)) @@ -90,7 +91,7 @@ def work(lvl): print('----ALARM---- ', freq) multi_channel.db_alarms_zeros(circle_buffer) else: - circle_buffer.update(sigs_array) + circle_buffer.update(sigs_array, packet_timestamps=sigs_ts_array) if telemetry_enabled: