добавил подсчет по dbfs

fft
Sergey Revyakin 3 weeks ago
parent 3a936fac9c
commit 6911d8ab25

@ -12,7 +12,6 @@ from common.runtime import load_root_env, resolve_hackrf_index
load_root_env(__file__) load_root_env(__file__)
def get_hack_id(): def get_hack_id():
return resolve_hackrf_index('HACKID_1200', 'orange_scripts/main_1200.py') return resolve_hackrf_index('HACKID_1200', 'orange_scripts/main_1200.py')
serial_number = os.getenv('HACKID_1200') serial_number = os.getenv('HACKID_1200')

@ -12,7 +12,6 @@ from common.runtime import load_root_env, resolve_hackrf_index
load_root_env(__file__) load_root_env(__file__)
def get_hack_id(): def get_hack_id():
return resolve_hackrf_index('HACKID_2400', 'orange_scripts/main_2400.py') return resolve_hackrf_index('HACKID_2400', 'orange_scripts/main_2400.py')
serial_number = os.getenv('HACKID_2400') serial_number = os.getenv('HACKID_2400')

@ -12,7 +12,6 @@ from common.runtime import load_root_env, resolve_hackrf_index
load_root_env(__file__) load_root_env(__file__)
def get_hack_id(): def get_hack_id():
return resolve_hackrf_index('HACKID_915', 'orange_scripts/main_915.py') return resolve_hackrf_index('HACKID_915', 'orange_scripts/main_915.py')
serial_number = os.getenv('HACKID_915') serial_number = os.getenv('HACKID_915')

@ -1,7 +1,10 @@
import os
import math
import statistics import statistics
# Более лучшая версия кода есть в FRScanner # Более лучшая версия кода есть в FRScanner
class DataBuffer: class DataBuffer:
""" """
Класс с реализацией циклического буффера. Класс с реализацией циклического буффера.
@ -13,9 +16,8 @@ class DataBuffer:
num_of_thinning_iter: Прореживающий множитель. Раз в это количечество раз будет обнволяться столбец буфера. num_of_thinning_iter: Прореживающий множитель. Раз в это количечество раз будет обнволяться столбец буфера.
line_size: Количество строк буфера = количеству каналов. line_size: Количество строк буфера = количеству каналов.
columns_size: Количество столбцов = фиксированное число. columns_size: Количество столбцов = фиксированное число.
multiply_factor: Процентный показатель превышения сигналом уровня шума. ex m_p = 1.1 => триггер, если multiply_factor: Процентный показатель превышения сигналом уровня шума.
сигнал превышает шум на 10%. num_for_alarm: Количество раз, превышающих шум, при которых триггеримся.
num_for_alarm: Количество раз, превышающих шум, при которых триггеримся = фиксированное число.
is_init: Флаг инициализации буфера. = True, если инициализирован. is_init: Флаг инициализации буфера. = True, если инициализирован.
buffer: Массив для буфера. buffer: Массив для буфера.
buffer_medians: Массив для медиан столбцов букера. buffer_medians: Массив для медиан столбцов букера.
@ -45,6 +47,16 @@ class DataBuffer:
self.buffer_medians = [0] * self.line_size self.buffer_medians = [0] * self.line_size
self.buffer_alarms = [0] * self.line_size self.buffer_alarms = [0] * self.line_size
self.prev_values = [None] * self.line_size
self.trend_streak = [0] * self.line_size
# Рост в 15% по линейной мощности относительно фоновой медианы в dBFS.
self.dbfs_delta_ratio = float(os.getenv('dbfs_delta_percent', 15)) / 100.0
# Допускаем небольшой обратный ход, чтобы не сбрасываться от микрошума.
self.dbfs_max_backstep_db = float(os.getenv('dbfs_max_backstep_db', 0.25))
# Минимум подряд "плавных" шагов перед учетом как устойчивого роста.
self.dbfs_min_trend_steps = int(os.getenv('dbfs_min_trend_steps', max(1, self.num_for_alarm)))
def get_buffer(self): def get_buffer(self):
return self.buffer return self.buffer
@ -71,11 +83,16 @@ class DataBuffer:
if self.check_init(): if self.check_init():
for i in range(self.line_size): for i in range(self.line_size):
self.buffer_medians[i] = statistics.median(self.buffer[i]) self.buffer_medians[i] = statistics.median(self.buffer[i])
# print('medians is: ', self.buffer_medians)
# return self.buffer_medians
def alarms_fill_zeros(self): def alarms_fill_zeros(self):
self.buffer_alarms = [0] * self.line_size self.buffer_alarms = [0] * self.line_size
self.trend_streak = [0] * self.line_size
self.prev_values = [None] * self.line_size
@staticmethod
def _dbfs_growth_ratio(current_db, baseline_db):
return math.pow(10.0, (current_db - baseline_db) / 10.0) - 1.0
def update(self, data): def update(self, data):
""" """
Обновление буфера. Обновление буфера.
@ -85,26 +102,17 @@ class DataBuffer:
3. Берем медианы по буферу, если он уже проиницализирован. 3. Берем медианы по буферу, если он уже проиницализирован.
4. Сбрасываем счетчик текущих чтений. 4. Сбрасываем счетчик текущих чтений.
5. Если был последний столбец (и мы уже переключились на первый), то 5. Если был последний столбец (и мы уже переключились на первый), то
Если прореживающий множитель на текующей итерации был единица, то мы иницилизировались Если прореживающий множитель на текующей итерации был единица, то мы иницилизировались.
До тех пор, пока множитель на итерации меньше фиксированного, увеличиваем в два раза. До тех пор, пока множитель на итерации меньше фиксированного, увеличиваем в два раза.
В противном случае - увеличиваем номер чтения. В противном случае - увеличиваем номер чтения.
:param data: Массив с метриками сигнала по каналам. :param data: Массив с метриками сигнала по каналам.
:return: None :return: None
""" """
# TODO: Добавить время релаксации - если система затриггерилась, то перестать обновлять буфер на N чтений,
# где N задается в .env-template. Сейчас есть бага, что буфер перестает обновляться только когда система
# триггерится. Между тем, когда приходит аларм и num_for_alarm, когда сигнал алармовский, но система еще не
# триггерится, буфер продолжает обновляться. В таких условиях буфер может набрать в себя алармовских сигналов
# и повысить пороги. Пример такой ситуации: дрон висит на 1км, система его видит, но сигнал превышает порог раз
# через раз и аларм срабатывает не всегда. В таких условиях наберется высокий сигнал, повысятся пороги и когда
# дрон начнет движение вперед, он будет заметен на более низкой дистанции, чем обычно, так как пороги повышены.
if self.current_counter == self.thinning_counter: if self.current_counter == self.thinning_counter:
for i in range(self.line_size): for i in range(self.line_size):
self.buffer[i][self.current_column] = data[i] self.buffer[i][self.current_column] = data[i]
self.current_column = (self.current_column + 1) % self.columns_size self.current_column = (self.current_column + 1) % self.columns_size
#print('Столбец {0} обновлен. Перешли к столбцу {1}: '.format(self.current_column - 1, self.current_column))
self.medians() self.medians()
self.current_counter = 1 self.current_counter = 1
if self.current_column == 0: if self.current_column == 0:
@ -114,56 +122,60 @@ class DataBuffer:
print('Начальная калибровка завершена.') print('Начальная калибровка завершена.')
if self.thinning_counter < self.num_of_thinning_iter: if self.thinning_counter < self.num_of_thinning_iter:
self.thinning_counter *= 2 self.thinning_counter *= 2
# print('thinning counter обновлен: ', self.thinning_counter)
else: else:
self.current_counter += 1 self.current_counter += 1
# print('curr counter обновлен: ', self.current_counter)
def check_alarm(self, data): def check_alarm(self, data):
""" """
Проверка триггера системы. Проверка триггера системы по dBFS во времени.
Если значение по каналу превышает медиану (порог) шума на какой-то процент, то инкремент буфер аларма по каналу. Триггер: устойчивый рост относительно фоновой медианы не меньше dbfs_delta_percent,
Превышение num_for_alarm подряд - триггер. Если после n превышений, где n<num_for_alarm приходит сигнал не подтвержденный несколькими последовательными чтениями.
первышающий порог, то сбрасываем буфер алармов.
:param data:
:return: Да/нет.
""" """
if self.check_init(): if self.check_init():
ratios=[]
print("="*50)
for i in range(len(data)): for i in range(len(data)):
exceeding = data[i] > self.multiply_factor * self.buffer_medians[i] baseline = self.buffer_medians[i]
ratios.append(data[i]/self.buffer_medians[i]) current = data[i]
growth_ratio = self._dbfs_growth_ratio(current, baseline)
prev = self.prev_values[i]
delta_db = 0.0 if prev is None else current - prev
monotonic_or_stable = (prev is None) or (delta_db >= -self.dbfs_max_backstep_db)
if monotonic_or_stable:
self.trend_streak[i] += 1
else:
self.trend_streak[i] = 0
exceeding = (
growth_ratio >= self.dbfs_delta_ratio
and self.trend_streak[i] >= self.dbfs_min_trend_steps
)
if exceeding: if exceeding:
self.buffer_alarms[i] += 1 self.buffer_alarms[i] += 1
# print('Инкремент буффер алармов по каналу {0}, текущее число по этому каналу: {1}'.format(i,self.buffer_alarms[i]))
else: else:
self.buffer_alarms[i] = 0 self.buffer_alarms[i] = 0
# print('Обнулили буффер алармов по каналу {0}, текущее число по этому каналу: {1}'.format(i,self.buffer_alarms[i]))
self.prev_values[i] = current
if self.buffer_alarms[i] >= self.num_for_alarm: if self.buffer_alarms[i] >= self.num_for_alarm:
# print('Сработала тревога по каналу {0}, текущее число по этому каналу: {1}'.format(i,self.buffer_alarms[i]))
self.buffer_alarms = [0] * self.line_size self.buffer_alarms = [0] * self.line_size
print("Отношения:", [f"{r:.3f}" for r in ratios]) self.trend_streak = [0] * self.line_size
print("!"*50)
return True return True
print("Отношения:", [f"{r:.3f}" for r in ratios])
print("="*50)
return False return False
def check_single_alarm(self, median, cur_channel): def check_single_alarm(self, median, cur_channel):
""" """
Проверка, является ли текущая медиана по каналу превышающей порог. Проверка, является ли текущая метрика по каналу превышающей порог роста.
:param median: меди (хар-ка) по каналу. :param median: текущая метрика в dBFS.
:param cur_channel: индекс канала внутри частоты. :param cur_channel: индекс канала внутри частоты.
:return: Да/нет. :return: Да/нет.
""" """
if self.check_init(): if self.check_init():
exceeding = median > self.multiply_factor * self.buffer_medians[cur_channel] baseline = self.buffer_medians[cur_channel]
print(median/self.buffer_medians[cur_channel]) exceeding = self._dbfs_growth_ratio(median, baseline) >= self.dbfs_delta_ratio
if exceeding: if exceeding:
return True return True
else: else:

@ -23,7 +23,6 @@ from common.runtime import load_root_env, resolve_hackrf_index
load_root_env(__file__) load_root_env(__file__)
def get_hack_id(): def get_hack_id():
return resolve_hackrf_index('hack_3300', 'src/main_3300.py') return resolve_hackrf_index('hack_3300', 'src/main_3300.py')
serial_number = os.getenv('hack_3300') serial_number = os.getenv('hack_3300')

@ -23,7 +23,6 @@ from common.runtime import load_root_env, resolve_hackrf_index
load_root_env(__file__) load_root_env(__file__)
def get_hack_id(): def get_hack_id():
return resolve_hackrf_index('hack_433', 'src/main_433.py') return resolve_hackrf_index('hack_433', 'src/main_433.py')
serial_number = os.getenv('hack_433') serial_number = os.getenv('hack_433')

@ -23,7 +23,6 @@ from common.runtime import load_root_env, resolve_hackrf_index
load_root_env(__file__) load_root_env(__file__)
def get_hack_id(): def get_hack_id():
return resolve_hackrf_index('hack_4500', 'src/main_4500.py') return resolve_hackrf_index('hack_4500', 'src/main_4500.py')
serial_number = os.getenv('hack_4500') serial_number = os.getenv('hack_4500')

@ -18,12 +18,10 @@ import time
import threading import threading
import subprocess import subprocess
import os import os
from common.runtime import load_root_env, resolve_hackrf_index from common.runtime import load_root_env, resolve_hackrf_index
load_root_env(__file__) load_root_env(__file__)
def get_hack_id(): def get_hack_id():
return resolve_hackrf_index('hack_5200', 'src/main_5200.py') return resolve_hackrf_index('hack_5200', 'src/main_5200.py')
serial_number = os.getenv('hack_5200') serial_number = os.getenv('hack_5200')

@ -23,7 +23,6 @@ from common.runtime import load_root_env, resolve_hackrf_index
load_root_env(__file__) load_root_env(__file__)
def get_hack_id(): def get_hack_id():
return resolve_hackrf_index('hack_5800', 'src/main_5800.py') return resolve_hackrf_index('hack_5800', 'src/main_5800.py')
serial_number = os.getenv('hack_5800') serial_number = os.getenv('hack_5800')

@ -23,7 +23,6 @@ from common.runtime import load_root_env, resolve_hackrf_index
load_root_env(__file__) load_root_env(__file__)
def get_hack_id(): def get_hack_id():
return resolve_hackrf_index('hack_750', 'src/main_750.py') return resolve_hackrf_index('hack_750', 'src/main_750.py')
serial_number = os.getenv('hack_750') serial_number = os.getenv('hack_750')

@ -23,7 +23,6 @@ from common.runtime import load_root_env, resolve_hackrf_index
load_root_env(__file__) load_root_env(__file__)
def get_hack_id(): def get_hack_id():
return resolve_hackrf_index('hack_868', 'src/main_868.py') return resolve_hackrf_index('hack_868', 'src/main_868.py')
serial_number = os.getenv('hack_868') serial_number = os.getenv('hack_868')

Loading…
Cancel
Save