Sergey Revyakin 4 weeks ago
parent f7aed6b0e2
commit b8d7db91cf

@ -2,7 +2,7 @@
# GENERAL
#################
module_name=dronedetector
freqs=433,750,868,915,1200,2400,3300,4500,5200,5800
freqs=433,750,868,915,1200,1500,2400,3300,4500,5200,5800
signal_threshold=0.02
signal_threshold_433=0.0195

3
.gitignore vendored

@ -188,4 +188,5 @@ runtime/
/.venv-*/*
train_scripts/models/*
train_scripts/models/*
train_scripts/models/ensemble_1.2_jpg_*/

@ -173,8 +173,7 @@ sudo systemctl stop dronedetector-sdr-5800.service
sudo systemctl stop dronedetector-sdr-1200.service
sudo systemctl stop dronedetector-sdr-2400.service
sudo systemctl stop dronedetector-sdr-1500.service
sudo systemctl stop dronedetector-sdr-868.service
sudo systemctl stop dronedetector-sdr-868-915.service
sudo systemctl stop dronedetector-sdr-915.service
```
@ -210,4 +209,7 @@ docker compose -f deploy/docker/docker-compose.yml logs --timestamps dronedetect
sudo hackrf_spiflash -w hackrf_one_usb.bin
```
./.venv-sdr/bin/python scripts_nn/data_saver_headless.py --serial 000 --freq 4500000000 --save-dir /home/sibscience-4/Dataset/3300 --file-tag DJI_3_ --samp-rate 20000000 --split-size 400000 --delay 0.1 --rf-gain 12 --if-gain 30 --bb-gain 36
./.venv-sdr/bin/python scripts_nn/data_saver_headless.py --serial 000 --freq 4500000000 --save-dir /home/sibscience-4/Dataset/3300 --file-tag DJI_3_ --samp-rate 20000000 --split-size 400000 --delay 0.1 --rf-gain 12 --if-gain 30 --bb-gain 36
.venv-sdr/bin/python read_energy.py

@ -7,8 +7,8 @@ source .env
# НАСТРОЙКИ
############################
# ЗАМЕНИ на реальную точку монтирования nvme1n1
BASE_DIR="/mnt/nvme1/dataset"
BASE_DIR="/home/sibsci/dataset/drone"
# Путь к python из venv
PYTHON_BIN="${PYTHON_BIN:-$PWD/.venv-sdr/bin/python}"
@ -16,18 +16,19 @@ PYTHON_BIN="${PYTHON_BIN:-$PWD/.venv-sdr/bin/python}"
# Путь к headless скрипту
SCRIPT_PATH="${SCRIPT_PATH:-$PWD/scripts_nn/data_saver_headless.py}"
# Проверка, что каталог реально на nvme1n1
EXPECTED_DEVICE_PREFIX="/dev/nvme1n1"
# Лимиты
PER_FREQ_LIMIT_BYTES=$((3 * 1024 * 1024 * 1024)) # 3 GiB на частоту за запуск
TOTAL_LIMIT_BYTES=$((128 * 1024 * 1024 * 1024)) # общий лимит 512 GiB
CYCLE_SECONDS=36 # один цикл в час
lim_all=70
PER_FREQ_LIMIT_BYTES=$((7 * 1024 * 1024 * 1024)) # GiB на частоту за запуск
TOTAL_LIMIT_BYTES=$((lim_all * 1024 * 1024 * 1024)) # общий лимит GiB
CYCLE_SECONDS=1 # один цикл в час
# Параметры SDR
SAMP_RATE="20e6"
SPLIT_SIZE="400000"
DELAY="0.1"
DELAY="0.01"
RF_GAIN="12"
IF_GAIN="30"
BB_GAIN="36"
@ -36,7 +37,10 @@ BB_GAIN="36"
# ЧАСТОТЫ И SERIAL ИЗ ENV
############################
ORDER=(433 750 915 1200 2400 3300 4500 5200 5800)
#ORDER=(433 750 915 1200 2400 3300 4500 5200 5800)
ORDER=(2400)
declare -A SERIAL
declare -A FREQ_HZ
@ -47,8 +51,6 @@ FREQ_HZ[433]="433000000"
SERIAL[750]="$hack_750"
FREQ_HZ[750]="750000000"
SERIAL[868]="$hack_868"
FREQ_HZ[868]="868000000"
SERIAL[915]="$hack_915"
FREQ_HZ[915]="915000000"
@ -105,14 +107,6 @@ ensure_requirements() {
mkdir -p "$BASE_DIR"
local dev
dev="$(df -P "$BASE_DIR" | awk 'NR==2 {print $1}')"
if [[ "$dev" != ${EXPECTED_DEVICE_PREFIX}* ]]; then
echo "BASE_DIR=$BASE_DIR сейчас находится на $dev, а ожидался ${EXPECTED_DEVICE_PREFIX}*" >&2
echo "Исправь BASE_DIR на точку монтирования nvme1n1" >&2
exit 1
fi
}
run_one_freq() {
@ -151,7 +145,7 @@ run_one_freq() {
cur_total_size="$(total_size_bytes)"
if (( cur_total_size >= TOTAL_LIMIT_BYTES )); then
log "Достигнут общий лимит 512 GiB. Останавливаю PID=$pid"
log "Достигнут общий лимит $lim_all GiB. Останавливаю PID=$pid"
kill -TERM "$pid" 2>/dev/null || true
wait "$pid" 2>/dev/null || true
return 2
@ -190,7 +184,7 @@ main_loop() {
total_before="$(total_size_bytes)"
if (( total_before >= TOTAL_LIMIT_BYTES )); then
log "Общий размер уже >= 512 GiB, выхожу"
log "Общий размер уже >= GiB, выхожу"
break
fi

@ -11,13 +11,26 @@ services:
- PYTHONPATH=/app
- JAMMER_STATE_FILE=/app/runtime/jammer_active.flag
working_dir: /app
command: ["python3", "-m", "src.server_to_master"]
command:
- uvicorn
- src.server_to_master:app
- --host
- 0.0.0.0
- --port
- "5010"
- --reload
- --reload-dir
- /app/src
- --reload-dir
- /app/common
restart: unless-stopped
ports:
- "5010:5010"
volumes:
- ../../.env:/app/.env:ro
- ../../runtime:/app/runtime
- ../../src:/app/src
- ../../common:/app/common
networks:
- dronedetector-net
@ -62,7 +75,18 @@ services:
environment:
- PYTHONPATH=/app
working_dir: /app
command: ["python3", "-m", "telemetry.telemetry_server"]
command:
- uvicorn
- telemetry.telemetry_server:app
- --host
- 0.0.0.0
- --port
- "5020"
- --reload
- --reload-dir
- /app/telemetry
- --reload-dir
- /app/common
restart: unless-stopped
ports:
- "5020:5020"

@ -8,9 +8,9 @@ Requires=docker.service
Type=oneshot
WorkingDirectory=__PROJECT_ROOT__
RemainAfterExit=yes
ExecStart=/usr/bin/docker compose -f __PROJECT_ROOT__/deploy/docker/docker-compose.yml up -d --build
ExecStart=/usr/bin/docker compose -f __PROJECT_ROOT__/deploy/docker/docker-compose.yml up -d
ExecStop=/usr/bin/docker compose -f __PROJECT_ROOT__/deploy/docker/docker-compose.yml down
ExecReload=/usr/bin/docker compose -f __PROJECT_ROOT__/deploy/docker/docker-compose.yml up -d --build
ExecReload=/usr/bin/docker compose -f __PROJECT_ROOT__/deploy/docker/docker-compose.yml up -d
TimeoutStartSec=0
[Install]

@ -10,8 +10,7 @@ Group=__RUN_GROUP__
WorkingDirectory=__PROJECT_ROOT__
EnvironmentFile=__PROJECT_ROOT__/.env
Environment=PYTHONPATH=__PROJECT_ROOT__
ExecStartPre=/usr/local/bin/dronedetector-precheck-sdr.sh
ExecStart=__PROJECT_ROOT__/.venv-sdr/bin/python orange_scripts/main_1200.py
ExecStart=__PROJECT_ROOT__/.venv-sdr/bin/python src/main_1200.py
Restart=always
RestartSec=3

@ -10,7 +10,6 @@ Group=__RUN_GROUP__
WorkingDirectory=__PROJECT_ROOT__
EnvironmentFile=__PROJECT_ROOT__/.env
Environment=PYTHONPATH=__PROJECT_ROOT__
ExecStartPre=/usr/local/bin/dronedetector-precheck-sdr.sh
ExecStart=__PROJECT_ROOT__/.venv-sdr/bin/python src/main_1500.py
Restart=always
RestartSec=3

@ -10,8 +10,7 @@ Group=__RUN_GROUP__
WorkingDirectory=__PROJECT_ROOT__
EnvironmentFile=__PROJECT_ROOT__/.env
Environment=PYTHONPATH=__PROJECT_ROOT__
ExecStartPre=/usr/local/bin/dronedetector-precheck-sdr.sh
ExecStart=__PROJECT_ROOT__/.venv-sdr/bin/python orange_scripts/main_2400.py
ExecStart=__PROJECT_ROOT__/.venv-sdr/bin/python src/main_2400.py
Restart=always
RestartSec=3

@ -10,7 +10,6 @@ Group=__RUN_GROUP__
WorkingDirectory=__PROJECT_ROOT__
EnvironmentFile=__PROJECT_ROOT__/.env
Environment=PYTHONPATH=__PROJECT_ROOT__
ExecStartPre=/usr/local/bin/dronedetector-precheck-sdr.sh
ExecStart=__PROJECT_ROOT__/.venv-sdr/bin/python src/main_3300.py
Restart=always
RestartSec=3

@ -10,7 +10,6 @@ Group=__RUN_GROUP__
WorkingDirectory=__PROJECT_ROOT__
EnvironmentFile=__PROJECT_ROOT__/.env
Environment=PYTHONPATH=__PROJECT_ROOT__
ExecStartPre=/usr/local/bin/dronedetector-precheck-sdr.sh
ExecStart=__PROJECT_ROOT__/.venv-sdr/bin/python src/main_433.py
Restart=always
RestartSec=3

@ -10,7 +10,6 @@ Group=__RUN_GROUP__
WorkingDirectory=__PROJECT_ROOT__
EnvironmentFile=__PROJECT_ROOT__/.env
Environment=PYTHONPATH=__PROJECT_ROOT__
ExecStartPre=/usr/local/bin/dronedetector-precheck-sdr.sh
ExecStart=__PROJECT_ROOT__/.venv-sdr/bin/python src/main_4500.py
Restart=always
RestartSec=3

@ -10,7 +10,6 @@ Group=__RUN_GROUP__
WorkingDirectory=__PROJECT_ROOT__
EnvironmentFile=__PROJECT_ROOT__/.env
Environment=PYTHONPATH=__PROJECT_ROOT__
ExecStartPre=/usr/local/bin/dronedetector-precheck-sdr.sh
ExecStart=__PROJECT_ROOT__/.venv-sdr/bin/python src/main_5200.py
Restart=always
RestartSec=3

@ -10,7 +10,6 @@ Group=__RUN_GROUP__
WorkingDirectory=__PROJECT_ROOT__
EnvironmentFile=__PROJECT_ROOT__/.env
Environment=PYTHONPATH=__PROJECT_ROOT__
ExecStartPre=/usr/local/bin/dronedetector-precheck-sdr.sh
ExecStart=__PROJECT_ROOT__/.venv-sdr/bin/python src/main_5800.py
Restart=always
RestartSec=3

@ -10,7 +10,6 @@ Group=__RUN_GROUP__
WorkingDirectory=__PROJECT_ROOT__
EnvironmentFile=__PROJECT_ROOT__/.env
Environment=PYTHONPATH=__PROJECT_ROOT__
ExecStartPre=/usr/local/bin/dronedetector-precheck-sdr.sh
ExecStart=__PROJECT_ROOT__/.venv-sdr/bin/python src/main_750.py
Restart=always
RestartSec=3

@ -1,19 +0,0 @@
[Unit]
Description=DroneDetector SDR Router 868/915 Shared HackRF
After=network-online.target
Wants=network-online.target
[Service]
Type=simple
User=__RUN_USER__
Group=__RUN_GROUP__
WorkingDirectory=__PROJECT_ROOT__
EnvironmentFile=__PROJECT_ROOT__/.env
Environment=PYTHONPATH=__PROJECT_ROOT__
ExecStartPre=/usr/local/bin/dronedetector-precheck-sdr.sh
ExecStart=__PROJECT_ROOT__/.venv-sdr/bin/python src/main_868_915_router.py
Restart=always
RestartSec=3
[Install]
WantedBy=multi-user.target

@ -1,20 +0,0 @@
[Unit]
Description=DroneDetector SDR Scanner 868 MHz
After=network-online.target dronedetector-sdr-868-915.service
Wants=network-online.target
Requires=dronedetector-sdr-868-915.service
[Service]
Type=simple
User=__RUN_USER__
Group=__RUN_GROUP__
WorkingDirectory=__PROJECT_ROOT__
EnvironmentFile=__PROJECT_ROOT__/.env
Environment=PYTHONPATH=__PROJECT_ROOT__
ExecStartPre=/usr/local/bin/dronedetector-precheck-sdr.sh
ExecStart=__PROJECT_ROOT__/.venv-sdr/bin/python src/main_868.py
Restart=always
RestartSec=3
[Install]
WantedBy=multi-user.target

@ -1,8 +1,7 @@
[Unit]
Description=DroneDetector SDR Scanner 915 MHz
After=network-online.target dronedetector-sdr-868-915.service
After=network-online.target
Wants=network-online.target
Requires=dronedetector-sdr-868-915.service
[Service]
Type=simple
@ -11,8 +10,7 @@ Group=__RUN_GROUP__
WorkingDirectory=__PROJECT_ROOT__
EnvironmentFile=__PROJECT_ROOT__/.env
Environment=PYTHONPATH=__PROJECT_ROOT__
ExecStartPre=/usr/local/bin/dronedetector-precheck-sdr.sh
ExecStart=__PROJECT_ROOT__/.venv-sdr/bin/python orange_scripts/main_915.py
ExecStart=__PROJECT_ROOT__/.venv-sdr/bin/python src/main_915.py
Restart=always
RestartSec=3

@ -1,22 +0,0 @@
#!/usr/bin/env bash
set -euo pipefail
if ! command -v hackrf_info >/dev/null 2>&1; then
echo "[dronedetector-precheck] hackrf_info not found. Install hackrf-tools/hackrf package." >&2
exit 1
fi
if ! command -v gnuradio-config-info >/dev/null 2>&1; then
echo "[dronedetector-precheck] gnuradio-config-info not found. Install gnuradio." >&2
exit 1
fi
if ! python3 -c "import osmosdr" >/dev/null 2>&1; then
echo "[dronedetector-precheck] Python module osmosdr not importable." >&2
exit 1
fi
if ! hackrf_info 2>/dev/null | grep -q "Found HackRF"; then
echo "[dronedetector-precheck] HackRF device was not detected by hackrf_info." >&2
exit 1
fi

@ -14,8 +14,6 @@ SOURCE_ARCHIVES=(
SDR_UNITS=(
dronedetector-sdr-433.service
dronedetector-sdr-750.service
dronedetector-sdr-868-915.service
dronedetector-sdr-868.service
dronedetector-sdr-1500.service
dronedetector-sdr-3300.service
dronedetector-sdr-4500.service
@ -204,8 +202,6 @@ build_and_run_compose() {
install_systemd_units() {
log "Installing systemd units"
install -m 0755 "${PROJECT_ROOT}/deploy/systemd/precheck-sdr.sh" /usr/local/bin/dronedetector-precheck-sdr.sh
local src dst
for src in "${PROJECT_ROOT}"/deploy/systemd/*.service; do
dst="${SYSTEMD_TARGET_DIR}/$(basename "$src")"

@ -8,13 +8,13 @@ import json
import time
load_root_env(__file__)
validate_env("orange_scripts/compose_send_data_2400.py", {
"POROG_2400": as_float,
"SERVER_IP_2": as_str,
"SERVER_PORT_2": as_int,
})
porog = float(os.getenv('POROG_2400'))
load_root_env(__file__)
validate_env("orange_scripts/compose_send_data_5800.py", {
"POROG_5800": as_float,
"SERVER_IP_2": as_str,
"SERVER_PORT_2": as_int,
})
porog = float(os.getenv('POROG_5800'))
server_ip_1 = os.getenv('SERVER_IP_1')
server_port_1 = os.getenv('SERVER_PORT_1')
server_ip_2 = os.getenv('SERVER_IP_2')
@ -28,9 +28,9 @@ flag = 0
##############################
# HYPERPARAMETERS
##############################
f_base = 2.4e9
f_base = 5.9e9
f_step = 20e6
f_roof = 2.5e9
f_roof = 5.7e9
##############################
# Variables
##############################
@ -55,7 +55,7 @@ def send_data(sig):
print('#' * 10)
print('\nОтправка пакета ' + str(token+1))
data_to_send = {
"freq": 2400,
"freq": 5800,
"channel": int(channel),
"token": int(token+1),
"data_real": np.asarray(np.array(sig, dtype=np.complex64).real, dtype=np.float32),

@ -69,7 +69,7 @@ class ProbeTop(gr.top_block):
try:
getattr(self.src, fn)(val, 0)
except Exception:
pass
raise Exception("не ставится усиление")
try:
self.src.set_bandwidth(0, 0)
except Exception:
@ -260,7 +260,7 @@ def build_parser() -> argparse.ArgumentParser:
p.add_argument("--interval", type=float, default=0.5, help="Per-device read interval (s)")
p.add_argument("--refresh", type=float, default=0.5, help="Console refresh interval (s)")
p.add_argument("--reopen-delay", type=float, default=1.0, help="Retry delay after BUSY/ERR (s)")
p.add_argument("--gain", type=float, default=16.0, help="General gain")
p.add_argument("--gain", type=float, default=0.0, help="General gain")
p.add_argument("--if-gain", type=float, default=16.0, help="IF gain")
p.add_argument("--bb-gain", type=float, default=16.0, help="BB gain")
return p

@ -0,0 +1,408 @@
"""
./.venv-sdr/bin/python read_energy_wide.py \
--serial 0000000000000000a18c63dc2a83b813 \
--sample-rate 20000000 \
--base 6000 \
--roof 5700 \
--step 20
"""
#!/usr/bin/env python3
import argparse
import math
import re
import signal
import subprocess
import sys
import time
from dataclasses import dataclass
from typing import Dict, List, Optional, Tuple
try:
import numpy as np
except Exception as exc:
print(f"numpy import failed: {exc}", file=sys.stderr)
sys.exit(1)
try:
from gnuradio import blocks, gr
import osmosdr
except Exception as exc:
print(f"gnuradio/osmosdr import failed: {exc}", file=sys.stderr)
print("Run with the SDR venv, e.g. .venv-sdr/bin/python read_energy_wide.py", file=sys.stderr)
sys.exit(1)
EPS = 1e-20
@dataclass
class ScanWindow:
seq: int
start_mhz: float
end_mhz: float
low_mhz: float
high_mhz: float
center_mhz: float
status: str = "INIT"
rms: Optional[float] = None
power_lin: Optional[float] = None
dbfs: Optional[float] = None
samples: int = 0
updated_at: float = 0.0
error: str = ""
pass_no: int = 0
class WideProbeTop(gr.top_block):
def __init__(
self,
index: int,
center_freq_hz: float,
sample_rate: float,
vec_len: int,
gain: float,
if_gain: float,
bb_gain: float,
):
super().__init__("hackrf_energy_wide_probe")
self.probe = blocks.probe_signal_vc(vec_len)
self.stream_to_vec = blocks.stream_to_vector(gr.sizeof_gr_complex * 1, vec_len)
self.src = osmosdr.source(args=f"numchan=1 hackrf={index}")
self.src.set_time_unknown_pps(osmosdr.time_spec_t())
self.src.set_sample_rate(sample_rate)
self.src.set_center_freq(center_freq_hz, 0)
try:
self.src.set_freq_corr(0, 0)
except Exception:
pass
try:
self.src.set_gain_mode(False, 0)
except Exception:
pass
for fn, val in (("set_gain", gain), ("set_if_gain", if_gain), ("set_bb_gain", bb_gain)):
try:
getattr(self.src, fn)(val, 0)
except Exception:
pass
try:
self.src.set_bandwidth(0, 0)
except Exception:
pass
try:
self.src.set_antenna("", 0)
except Exception:
pass
self.connect((self.src, 0), (self.stream_to_vec, 0))
self.connect((self.stream_to_vec, 0), (self.probe, 0))
def tune(self, freq_hz: float) -> None:
self.src.set_center_freq(freq_hz, 0)
def read_metrics(self) -> Tuple[float, float, float, int]:
arr = np.asarray(self.probe.level(), dtype=np.complex64)
if arr.size == 0:
raise RuntimeError("no samples")
power_lin = float(np.mean(arr.real * arr.real + arr.imag * arr.imag))
rms = math.sqrt(max(power_lin, 0.0))
dbfs = 10.0 * math.log10(max(power_lin, EPS))
return rms, power_lin, dbfs, int(arr.size)
def read_window(self, settle: float, avg_reads: int, pause_between_reads: float) -> Tuple[float, float, float, int]:
if settle > 0:
time.sleep(settle)
read_count = max(1, avg_reads)
powers: List[float] = []
sample_sizes: List[int] = []
last_error: Optional[Exception] = None
for idx in range(read_count):
deadline = time.time() + 1.0
while True:
try:
_, power_lin, _, samples = self.read_metrics()
powers.append(power_lin)
sample_sizes.append(samples)
break
except Exception as exc:
last_error = exc
if time.time() >= deadline:
raise RuntimeError(str(last_error) if last_error else "no samples")
time.sleep(0.02)
if idx + 1 < read_count and pause_between_reads > 0:
time.sleep(pause_between_reads)
power_lin = float(sum(powers) / len(powers))
rms = math.sqrt(max(power_lin, 0.0))
dbfs = 10.0 * math.log10(max(power_lin, EPS))
samples = int(sum(sample_sizes) / len(sample_sizes))
return rms, power_lin, dbfs, samples
def parse_hackrf_info() -> Dict[str, int]:
try:
proc = subprocess.run(["hackrf_info"], capture_output=True, text=True, timeout=15)
except FileNotFoundError:
raise RuntimeError("hackrf_info not found")
except subprocess.TimeoutExpired:
raise RuntimeError("hackrf_info timeout")
text = (proc.stdout or "") + "\n" + (proc.stderr or "")
out: Dict[str, int] = {}
cur_idx: Optional[int] = None
for line in text.splitlines():
m = re.search(r"^Index:\s*(\d+)", line)
if m:
cur_idx = int(m.group(1))
continue
m = re.search(r"^Serial number:\s*([0-9a-fA-F]+)", line)
if m and cur_idx is not None:
out[m.group(1).lower()] = cur_idx
if not out:
raise RuntimeError("no devices parsed from hackrf_info")
return out
def fmt(value: Optional[float], spec: str) -> str:
return "-" if value is None else format(value, spec)
def build_windows(base_mhz: float, roof_mhz: float, step_mhz: float) -> List[ScanWindow]:
if step_mhz <= 0:
raise ValueError("step must be > 0")
if base_mhz == roof_mhz:
raise ValueError("base and roof must be different")
direction = -1.0 if roof_mhz < base_mhz else 1.0
edge = base_mhz
seq = 1
windows: List[ScanWindow] = []
while True:
next_edge = edge + direction * step_mhz
if direction < 0 and next_edge < roof_mhz:
next_edge = roof_mhz
if direction > 0 and next_edge > roof_mhz:
next_edge = roof_mhz
low_mhz = min(edge, next_edge)
high_mhz = max(edge, next_edge)
center_mhz = (low_mhz + high_mhz) / 2.0
windows.append(
ScanWindow(
seq=seq,
start_mhz=edge,
end_mhz=next_edge,
low_mhz=low_mhz,
high_mhz=high_mhz,
center_mhz=center_mhz,
)
)
if next_edge == roof_mhz:
break
edge = next_edge
seq += 1
return windows
def render(
windows: List[ScanWindow],
serial: str,
index: int,
sample_rate: float,
base_mhz: float,
roof_mhz: float,
step_mhz: float,
started_at: float,
pass_no: int,
current_seq: int,
) -> None:
now = time.time()
capture_bw_mhz = sample_rate / 1e6
current_row = next((row for row in windows if row.seq == current_seq), None)
best_row = max(
(row for row in windows if row.status == "OK" and row.dbfs is not None),
key=lambda row: row.dbfs if row.dbfs is not None else float("-inf"),
default=None,
)
print("\x1b[2J\x1b[H", end="")
print("HackRF Wide Energy Monitor (relative power: RMS / linear / dBFS)")
print(
f"serial: {serial} | idx: {index} | sample-rate: {capture_bw_mhz:.3f} MHz | "
f"scan: {base_mhz:.3f}->{roof_mhz:.3f} MHz step {step_mhz:.3f} MHz | "
f"pass: {pass_no} | uptime: {int(now-started_at)}s | {time.strftime('%Y-%m-%d %H:%M:%S')}"
)
print()
header = (
f"{'cur':>3} {'seq':>3} {'window MHz':>23} {'center':>9} {'status':>8} "
f"{'dBFS':>9} {'rms':>10} {'power':>12} {'N':>5} {'age':>5} error"
)
print(header)
print("-" * len(header))
for row in windows:
age = "-" if row.updated_at <= 0 else f"{(now-row.updated_at):.1f}"
err = row.error
if len(err) > 50:
err = err[:47] + "..."
marker = ">>>" if row.seq == current_seq else ""
print(
f"{marker:>3} {row.seq:>3} "
f"{f'{row.high_mhz:.3f}-{row.low_mhz:.3f}':>23} {row.center_mhz:>9.3f} {row.status:>8} "
f"{fmt(row.dbfs, '.2f'):>9} {fmt(row.rms, '.6f'):>10} {fmt(row.power_lin, '.8f'):>12} "
f"{row.samples:>5} {age:>5} {err}"
)
print()
if best_row is not None:
best_age = "-" if best_row.updated_at <= 0 else f"{(now-best_row.updated_at):.1f}"
print(
f"{'':>3} {'MAX':>3} "
f"{f'{best_row.high_mhz:.3f}-{best_row.low_mhz:.3f}':>23} {best_row.center_mhz:>9.3f} {best_row.status:>8} "
f"{fmt(best_row.dbfs, '.2f'):>9} {fmt(best_row.rms, '.6f'):>10} {fmt(best_row.power_lin, '.8f'):>12} "
f"{best_row.samples:>5} {best_age:>5} pass={best_row.pass_no}"
)
elif current_row is not None:
current_age = "-" if current_row.updated_at <= 0 else f"{(now-current_row.updated_at):.1f}"
print(
f"{'':>3} {'MAX':>3} "
f"{f'{current_row.high_mhz:.3f}-{current_row.low_mhz:.3f}':>23} {current_row.center_mhz:>9.3f} {'INIT':>8} "
f"{fmt(None, '.2f'):>9} {fmt(None, '.6f'):>10} {fmt(None, '.8f'):>12} "
f"{0:>5} {current_age:>5} no successful windows yet"
)
print("Ctrl+C to stop. Window width equals step; sample-rate must be >= step to cover each window.")
sys.stdout.flush()
def build_parser() -> argparse.ArgumentParser:
parser = argparse.ArgumentParser(description="Retune one HackRF across a wide frequency range and measure energy")
parser.add_argument("--serial", required=True, help="HackRF serial number from hackrf_info")
parser.add_argument("--sample-rate", type=float, required=True, help="Sample rate in Hz")
parser.add_argument("--base", type=float, required=True, help="Scan start edge in MHz")
parser.add_argument("--roof", type=float, required=True, help="Scan end edge in MHz")
parser.add_argument("--step", type=float, required=True, help="Window width / retune step in MHz")
parser.add_argument("--vec-len", type=int, default=4096, help="Probe vector length")
parser.add_argument("--settle", type=float, default=0.12, help="Wait time after retune before reading (s)")
parser.add_argument("--avg-reads", type=int, default=3, help="How many probe reads to average per window")
parser.add_argument("--pause-between-reads", type=float, default=0.02, help="Pause between averaged reads (s)")
parser.add_argument("--passes", type=int, default=0, help="Number of sweep passes, 0 means infinite")
parser.add_argument("--gain", type=float, default=16.0, help="General gain")
parser.add_argument("--if-gain", type=float, default=16.0, help="IF gain")
parser.add_argument("--bb-gain", type=float, default=16.0, help="BB gain")
return parser
def main() -> int:
args = build_parser().parse_args()
serial = args.serial.lower()
try:
windows = build_windows(args.base, args.roof, args.step)
except ValueError as exc:
print(f"invalid scan range: {exc}", file=sys.stderr)
return 2
step_hz = args.step * 1e6
if args.sample_rate < step_hz:
print(
f"sample-rate {args.sample_rate:.0f} Hz is smaller than step window {step_hz:.0f} Hz; "
"this would leave gaps in the scan",
file=sys.stderr,
)
return 2
try:
serial_to_index = parse_hackrf_info()
except Exception as exc:
print(f"hackrf discovery failed: {exc}", file=sys.stderr)
return 3
index = serial_to_index.get(serial)
if index is None:
print(f"serial {serial} not found in hackrf_info", file=sys.stderr)
print("available serials:", file=sys.stderr)
for item_serial, item_index in sorted(serial_to_index.items(), key=lambda item: item[1]):
print(f" idx={item_index} serial={item_serial}", file=sys.stderr)
return 4
stop_requested = False
def on_signal(signum, frame):
nonlocal stop_requested
stop_requested = True
signal.signal(signal.SIGINT, on_signal)
signal.signal(signal.SIGTERM, on_signal)
probe: Optional[WideProbeTop] = None
started_at = time.time()
pass_no = 0
current_seq = windows[0].seq
try:
probe = WideProbeTop(
index=index,
center_freq_hz=windows[0].center_mhz * 1e6,
sample_rate=args.sample_rate,
vec_len=args.vec_len,
gain=args.gain,
if_gain=args.if_gain,
bb_gain=args.bb_gain,
)
probe.start()
time.sleep(max(args.settle, 0.12))
while not stop_requested:
pass_no += 1
for row in windows:
if stop_requested:
break
current_seq = row.seq
try:
probe.tune(row.center_mhz * 1e6)
rms, power_lin, dbfs, samples = probe.read_window(
settle=args.settle,
avg_reads=args.avg_reads,
pause_between_reads=args.pause_between_reads,
)
row.status = "OK"
row.rms = rms
row.power_lin = power_lin
row.dbfs = dbfs
row.samples = samples
row.error = ""
row.updated_at = time.time()
row.pass_no = pass_no
except Exception as exc:
row.status = "ERR"
row.error = str(exc)
row.updated_at = time.time()
render(
windows=windows,
serial=serial,
index=index,
sample_rate=args.sample_rate,
base_mhz=args.base,
roof_mhz=args.roof,
step_mhz=args.step,
started_at=started_at,
pass_no=pass_no,
current_seq=current_seq,
)
if args.passes > 0 and pass_no >= args.passes:
break
except Exception as exc:
print(f"scanner failed: {exc}", file=sys.stderr)
return 5
finally:
if probe is not None:
try:
probe.stop()
probe.wait()
except Exception:
pass
return 0
if __name__ == "__main__":
raise SystemExit(main())

@ -7,8 +7,6 @@ COMPOSE_FILE="${PROJECT_ROOT}/deploy/docker/docker-compose.yml"
SDR_UNITS=(
dronedetector-sdr-433.service
dronedetector-sdr-750.service
#dronedetector-sdr-868-915.service
#dronedetector-sdr-868.service
dronedetector-sdr-1500.service
dronedetector-sdr-3300.service
dronedetector-sdr-4500.service
@ -37,10 +35,6 @@ restart_docker_services() {
else
log "Compose file not found: $COMPOSE_FILE"
fi
if ${SUDO[@]} systemctl list-unit-files dronedetector-compose.service >/dev/null 2>&1; then
${SUDO[@]} systemctl restart dronedetector-compose.service || true
fi
}
restart_sdr_services() {

@ -40,8 +40,8 @@ class get_center_freq(gr.top_block):
self.rtlsdr_source_0.set_sample_rate(self.samp_rate)
self.rtlsdr_source_0.set_center_freq(self.center_freq, 0)
self.rtlsdr_source_0.set_freq_corr(0, 0)
self.rtlsdr_source_0.set_gain(24, 0)
self.rtlsdr_source_0.set_if_gain(24, 0)
self.rtlsdr_source_0.set_gain(16, 0)
self.rtlsdr_source_0.set_if_gain(16, 0)
self.rtlsdr_source_0.set_bb_gain(100, 0)
self.rtlsdr_source_0.set_antenna('', 0)
self.rtlsdr_source_0.set_bandwidth(0, 0)

@ -40,8 +40,8 @@ class get_center_freq(gr.top_block):
self.rtlsdr_source_0.set_sample_rate(self.samp_rate)
self.rtlsdr_source_0.set_center_freq(self.center_freq, 0)
self.rtlsdr_source_0.set_freq_corr(0, 0)
self.rtlsdr_source_0.set_gain(24, 0)
self.rtlsdr_source_0.set_if_gain(24, 0)
self.rtlsdr_source_0.set_gain(16, 0)
self.rtlsdr_source_0.set_if_gain(16, 0)
self.rtlsdr_source_0.set_bb_gain(100, 0)
self.rtlsdr_source_0.set_antenna('', 0)
self.rtlsdr_source_0.set_bandwidth(0, 0)

@ -40,8 +40,8 @@ class get_center_freq(gr.top_block):
self.rtlsdr_source_0.set_sample_rate(self.samp_rate)
self.rtlsdr_source_0.set_center_freq(self.center_freq, 0)
self.rtlsdr_source_0.set_freq_corr(0, 0)
self.rtlsdr_source_0.set_gain(24, 0)
self.rtlsdr_source_0.set_if_gain(24, 0)
self.rtlsdr_source_0.set_gain(16, 0)
self.rtlsdr_source_0.set_if_gain(16, 0)
self.rtlsdr_source_0.set_bb_gain(100, 0)
self.rtlsdr_source_0.set_antenna('', 0)
self.rtlsdr_source_0.set_bandwidth(0, 0)

@ -94,8 +94,8 @@ class get_center_freq(gr.top_block):
self.rtlsdr_source_0.set_sample_rate(samp_rate)
self.rtlsdr_source_0.set_center_freq(center_freq, 0)
self.rtlsdr_source_0.set_freq_corr(0, 0)
self.rtlsdr_source_0.set_gain(100, 0)
self.rtlsdr_source_0.set_if_gain(100, 0)
self.rtlsdr_source_0.set_gain(16, 0)
self.rtlsdr_source_0.set_if_gain(16, 0)
self.rtlsdr_source_0.set_bb_gain(100, 0)
self.rtlsdr_source_0.set_antenna('', 0)
self.rtlsdr_source_0.set_bandwidth(0, 0)

@ -94,8 +94,8 @@ class get_center_freq(gr.top_block):
self.rtlsdr_source_0.set_sample_rate(samp_rate)
self.rtlsdr_source_0.set_center_freq(center_freq, 0)
self.rtlsdr_source_0.set_freq_corr(0, 0)
self.rtlsdr_source_0.set_gain(24, 0)
self.rtlsdr_source_0.set_if_gain(24, 0)
self.rtlsdr_source_0.set_gain(16, 0)
self.rtlsdr_source_0.set_if_gain(16, 0)
self.rtlsdr_source_0.set_bb_gain(100, 0)
self.rtlsdr_source_0.set_antenna('', 0)
self.rtlsdr_source_0.set_bandwidth(0, 0)

@ -94,8 +94,8 @@ class get_center_freq(gr.top_block):
self.rtlsdr_source_0.set_sample_rate(samp_rate)
self.rtlsdr_source_0.set_center_freq(center_freq, 0)
self.rtlsdr_source_0.set_freq_corr(0, 0)
self.rtlsdr_source_0.set_gain(100, 0)
self.rtlsdr_source_0.set_if_gain(100, 0)
self.rtlsdr_source_0.set_gain(16, 0)
self.rtlsdr_source_0.set_if_gain(16, 0)
self.rtlsdr_source_0.set_bb_gain(100, 0)
self.rtlsdr_source_0.set_antenna('', 0)
self.rtlsdr_source_0.set_bandwidth(0, 0)

@ -93,8 +93,8 @@ class get_center_freq(gr.top_block):
self.rtlsdr_source_0.set_sample_rate(samp_rate)
self.rtlsdr_source_0.set_center_freq(center_freq, 0)
self.rtlsdr_source_0.set_freq_corr(0, 0)
self.rtlsdr_source_0.set_gain(100, 0)
self.rtlsdr_source_0.set_if_gain(100, 0)
self.rtlsdr_source_0.set_gain(16, 0)
self.rtlsdr_source_0.set_if_gain(16, 0)
self.rtlsdr_source_0.set_bb_gain(100, 0)
self.rtlsdr_source_0.set_antenna('', 0)
self.rtlsdr_source_0.set_bandwidth(0, 0)

@ -94,8 +94,8 @@ class get_center_freq(gr.top_block):
self.rtlsdr_source_0.set_sample_rate(samp_rate)
self.rtlsdr_source_0.set_center_freq(center_freq, 0)
self.rtlsdr_source_0.set_freq_corr(0, 0)
self.rtlsdr_source_0.set_gain(100, 0)
self.rtlsdr_source_0.set_if_gain(100, 0)
self.rtlsdr_source_0.set_gain(16, 0)
self.rtlsdr_source_0.set_if_gain(16, 0)
self.rtlsdr_source_0.set_bb_gain(100, 0)
self.rtlsdr_source_0.set_antenna('', 0)
self.rtlsdr_source_0.set_bandwidth(0, 0)

@ -94,8 +94,8 @@ class get_center_freq(gr.top_block):
self.rtlsdr_source_0.set_sample_rate(samp_rate)
self.rtlsdr_source_0.set_center_freq(center_freq, 0)
self.rtlsdr_source_0.set_freq_corr(0, 0)
self.rtlsdr_source_0.set_gain(24, 0)
self.rtlsdr_source_0.set_if_gain(24, 0)
self.rtlsdr_source_0.set_gain(16, 0)
self.rtlsdr_source_0.set_if_gain(16, 0)
self.rtlsdr_source_0.set_bb_gain(100, 0)
self.rtlsdr_source_0.set_antenna('', 0)
self.rtlsdr_source_0.set_bandwidth(0, 0)

@ -1,99 +0,0 @@
#!/usr/bin/env python3
# -*- coding: utf-8 -*-
from gnuradio import blocks
from gnuradio import gr
from gnuradio import zeromq
import signal
import sys
import threading
import time
import embedded_868 as my_freq
from common.runtime import load_root_env
from common.shared_stream_addrs import SHARED_868_ADDR, SHARED_VECTOR_LEN
load_root_env(__file__)
class get_center_freq(gr.top_block):
def __init__(self):
gr.top_block.__init__(self, 'get_center_freq')
self.prob_freq = 0
self.poll_rate = 10000
self.vector_len = SHARED_VECTOR_LEN
self.center_freq = 0
self.shared_addr = SHARED_868_ADDR
self._stop_polling = threading.Event()
self._prob_freq_thread = None
self.probSigVec = blocks.probe_signal_vc(self.vector_len)
self.shared_source_0 = zeromq.pull_source(
gr.sizeof_gr_complex,
self.vector_len,
self.shared_addr,
100,
False,
-1,
False,
)
self.connect((self.shared_source_0, 0), (self.probSigVec, 0))
def start_polling(self):
if self._prob_freq_thread is not None:
return
def _prob_freq_probe():
while not self._stop_polling.is_set():
self.set_prob_freq(self.probSigVec.level())
time.sleep(1.0 / self.poll_rate)
self._prob_freq_thread = threading.Thread(target=_prob_freq_probe, daemon=True)
self._prob_freq_thread.start()
def get_prob_freq(self):
return self.prob_freq
def set_prob_freq(self, prob_freq):
self.prob_freq = prob_freq
self.center_freq = my_freq.work(self.prob_freq)
def get_center_freq(self):
return self.center_freq
def set_center_freq(self, center_freq):
self.center_freq = center_freq
def close(self):
self._stop_polling.set()
self.stop()
self.wait()
def main(top_block_cls=get_center_freq, options=None):
tb = top_block_cls()
def sig_handler(sig=None, frame=None):
tb.close()
sys.exit(0)
signal.signal(signal.SIGINT, sig_handler)
signal.signal(signal.SIGTERM, sig_handler)
tb.start()
tb.start_polling()
try:
print('shared_pull_addr:', SHARED_868_ADDR)
print('debug_flag:', my_freq.debug_flag)
print('save_data_flag:', my_freq.save_data_flag)
print('send_to_module_flag:', my_freq.send_to_module_flag)
except EOFError:
pass
tb.wait()
if __name__ == '__main__':
main()

@ -1,122 +0,0 @@
#!/usr/bin/env python3
# -*- coding: utf-8 -*-
from gnuradio import blocks
from gnuradio import gr
import signal
import sys
import threading
import time
import osmosdr
from common.runtime import load_root_env, resolve_hackrf_index
from common.shared_stream_addrs import SHARED_VECTOR_LEN
from shared_router_868_915 import SharedRouter868915
load_root_env(__file__)
def get_hack_id():
return resolve_hackrf_index('hack_868', 'src/main_868_915_router.py')
class get_center_freq(gr.top_block):
def __init__(self):
gr.top_block.__init__(self, 'get_center_freq')
self.prob_freq = 0
self.poll_rate = 10000
self.vector_len = SHARED_VECTOR_LEN
self.router = SharedRouter868915()
self.active_lane = self.router.get_active_name()
self.center_freq = self.router.get_start_freq()
self._stop_polling = threading.Event()
self._prob_freq_thread = None
self.probSigVec = blocks.probe_signal_vc(self.vector_len)
self.rtlsdr_source_0 = osmosdr.source(
args='numchan=' + str(1) + ' ' + 'hackrf=' + get_hack_id()
)
self.rtlsdr_source_0.set_time_unknown_pps(osmosdr.time_spec_t())
self.rtlsdr_source_0.set_freq_corr(0, 0)
self.rtlsdr_source_0.set_antenna('', 0)
self.rtlsdr_source_0.set_min_output_buffer(self.vector_len)
self.apply_active_frontend()
self.rtlsdr_source_0.set_center_freq(self.center_freq, 0)
self.blocks_stream_to_vector_1 = blocks.stream_to_vector(gr.sizeof_gr_complex * 1, self.vector_len)
self.connect((self.rtlsdr_source_0, 0), (self.blocks_stream_to_vector_1, 0))
self.connect((self.blocks_stream_to_vector_1, 0), (self.probSigVec, 0))
def start_polling(self):
if self._prob_freq_thread is not None:
return
def _prob_freq_probe():
while not self._stop_polling.is_set():
self.set_prob_freq(self.probSigVec.level())
time.sleep(1.0 / self.poll_rate)
self._prob_freq_thread = threading.Thread(target=_prob_freq_probe, daemon=True)
self._prob_freq_thread.start()
def apply_active_frontend(self):
frontend = self.router.get_active_frontend()
self.rtlsdr_source_0.set_sample_rate(frontend['sample_rate'])
self.rtlsdr_source_0.set_gain(frontend['gain'], 0)
self.rtlsdr_source_0.set_if_gain(frontend['if_gain'], 0)
self.rtlsdr_source_0.set_bb_gain(frontend['bb_gain'], 0)
self.rtlsdr_source_0.set_bandwidth(frontend['bandwidth'], 0)
def get_prob_freq(self):
return self.prob_freq
def set_prob_freq(self, prob_freq):
self.prob_freq = prob_freq
next_center, lane_switched = self.router.route_vector(self.prob_freq)
if lane_switched:
self.active_lane = self.router.get_active_name()
self.apply_active_frontend()
if next_center != self.center_freq:
self.set_center_freq(next_center)
def get_center_freq(self):
return self.center_freq
def set_center_freq(self, center_freq):
self.center_freq = center_freq
self.rtlsdr_source_0.set_center_freq(self.center_freq, 0)
def close(self):
self._stop_polling.set()
try:
self.router.close()
finally:
self.stop()
self.wait()
def main(top_block_cls=get_center_freq, options=None):
tb = top_block_cls()
def sig_handler(sig=None, frame=None):
tb.close()
sys.exit(0)
signal.signal(signal.SIGINT, sig_handler)
signal.signal(signal.SIGTERM, sig_handler)
tb.start()
tb.start_polling()
try:
print('shared_router_active_lane:', tb.router.get_active_name())
print('shared_router_start_freq:', tb.get_center_freq())
except EOFError:
pass
tb.wait()
if __name__ == '__main__':
main()

@ -40,8 +40,8 @@ class get_center_freq(gr.top_block):
self.rtlsdr_source_0.set_sample_rate(self.samp_rate)
self.rtlsdr_source_0.set_center_freq(self.center_freq, 0)
self.rtlsdr_source_0.set_freq_corr(0, 0)
self.rtlsdr_source_0.set_gain(24, 0)
self.rtlsdr_source_0.set_if_gain(24, 0)
self.rtlsdr_source_0.set_gain(16, 0)
self.rtlsdr_source_0.set_if_gain(16, 0)
self.rtlsdr_source_0.set_bb_gain(100, 0)
self.rtlsdr_source_0.set_antenna('', 0)
self.rtlsdr_source_0.set_bandwidth(0, 0)

@ -1,173 +0,0 @@
import os
import numpy as np
import zmq
from common.runtime import load_root_env
from common.shared_stream_addrs import SHARED_868_ADDR, SHARED_915_ADDR
from core.multichannelswitcher import MultiChannel
from core.sig_n_medi_collect import Signal
load_root_env(__file__)
class Scheduler868:
def __init__(self):
self.signal_length = int(os.getenv('signal_length_868'))
self.multi_channel = MultiChannel(
[*map(float, os.getenv('f_step_868').split())],
[*map(float, os.getenv('f_bases_868').split())],
[*map(float, os.getenv('f_roofs_868').split())],
)
self.base_freq = float(self.multi_channel.init_f())
self.signal = Signal()
def get_current_freq(self):
return float(self.multi_channel.get_cur_channel())
def process(self, lvl):
current_before = self.get_current_freq()
metric = self.signal.fill_signal(lvl, self.signal_length)
if metric == 0:
return current_before, False
next_freq = float(self.multi_channel.change_channel())
self.signal.clear()
lane_complete = next_freq == self.base_freq and current_before != self.base_freq
return next_freq, lane_complete
class Scheduler915:
def __init__(self):
self.porog = float(os.getenv('POROG_915'))
self.point_amount = 100_000
self.split_size = 400_000
self.show_amount = int(0.8 * self.point_amount)
self.f_base = 0.91e9
self.f_step = 20e6
self.f_roof = 0.98e9
self.f = self.f_base
self.channel = 1
self.flag = 0
self.signal_arr = np.array([], dtype=np.complex64)
def get_current_freq(self):
return float(self.f)
def _median(self, sig):
samples = np.asarray(np.abs(np.array(sig, dtype=np.complex64)), dtype=np.float32)
sorted_samples = sorted(samples)
median = abs(float(np.median(sorted_samples[self.show_amount:])))
self.flag = 0 if self.porog > median else 1
def _advance(self):
next_freq = self.f + self.f_step
if next_freq >= self.f_roof:
self.f = self.f_base
self.channel = 1
return float(self.f), True
self.f = next_freq
self.channel += 1
return float(self.f), False
def process(self, lvl):
y = np.asarray(lvl, dtype=np.complex64).ravel()
self.signal_arr = np.concatenate((self.signal_arr, y), axis=None)
if self.flag == 0 and len(self.signal_arr) >= self.point_amount:
self._median(self.signal_arr[:self.point_amount])
self.signal_arr = np.array([], dtype=np.complex64)
if self.flag == 0:
return self._advance()
if len(self.signal_arr) >= self.split_size:
self.flag = 0
self.signal_arr = np.array([], dtype=np.complex64)
return self._advance()
return float(self.f), False
class SharedRouter868915:
def __init__(self):
self.frontends = {
'868': {
'sample_rate': 20e6,
'gain': 24,
'if_gain': 24,
'bb_gain': 100,
'bandwidth': 0,
},
'915': {
'sample_rate': 20e6,
'gain': 16,
'if_gain': 16,
'bb_gain': 0,
'bandwidth': 0,
},
}
self.schedulers = {
'868': Scheduler868(),
'915': Scheduler915(),
}
self.context = zmq.Context.instance()
self.sockets = {
'868': self._make_socket(SHARED_868_ADDR),
'915': self._make_socket(SHARED_915_ADDR),
}
self.active_name = '868'
self.switch_counter = 0
def _make_socket(self, addr):
sock = self.context.socket(zmq.PUSH)
sock.setsockopt(zmq.SNDHWM, 64)
sock.setsockopt(zmq.LINGER, 0)
sock.setsockopt(zmq.IMMEDIATE, 1)
sock.bind(addr)
return sock
def close(self):
for sock in self.sockets.values():
try:
sock.close(0)
except Exception:
pass
def get_active_name(self):
return self.active_name
def get_active_freq(self):
return self.schedulers[self.active_name].get_current_freq()
def get_active_frontend(self):
return dict(self.frontends[self.active_name])
def get_start_freq(self):
return self.get_active_freq()
def route_vector(self, lvl):
vector = np.asarray(lvl, dtype=np.complex64).ravel()
active_name = self.active_name
try:
self.sockets[active_name].send(vector.tobytes(), zmq.NOBLOCK)
except zmq.Again:
pass
next_freq, lane_complete = self.schedulers[active_name].process(vector)
lane_switched = False
if lane_complete:
previous = self.active_name
self.active_name = '915' if self.active_name == '868' else '868'
next_freq = self.get_active_freq()
self.switch_counter += 1
lane_switched = True
print(
f'[shared-router-868-915] switch#{self.switch_counter}: '
f'{previous} -> {self.active_name}, tune={next_freq}'
)
return float(next_freq), lane_switched

@ -2,7 +2,7 @@
"cells": [
{
"cell_type": "code",
"execution_count": 2,
"execution_count": 3,
"id": "4fdb98fc-65bb-467e-be0c-168fee9b0fca",
"metadata": {},
"outputs": [
@ -16,10 +16,10 @@
{
"data": {
"text/plain": [
"<contextlib.ExitStack at 0x7d183e4bd220>"
"<contextlib.ExitStack at 0x76adb5fa4260>"
]
},
"execution_count": 2,
"execution_count": 3,
"metadata": {},
"output_type": "execute_result"
}
@ -64,7 +64,7 @@
},
{
"cell_type": "code",
"execution_count": 3,
"execution_count": 4,
"id": "4848b066-2e09-4c1c-b8fa-8e3fa84d907a",
"metadata": {},
"outputs": [],
@ -74,7 +74,7 @@
},
{
"cell_type": "code",
"execution_count": 4,
"execution_count": 5,
"id": "9267fbe1",
"metadata": {},
"outputs": [],
@ -147,20 +147,20 @@
},
{
"cell_type": "code",
"execution_count": 12,
"execution_count": null,
"id": "448da74a-e0ae-44d8-9877-8dd1f257a24f",
"metadata": {},
"outputs": [],
"source": [
"selected_freq=750\n",
"selected_freq=915\n",
"\n",
"path_to_binaries = f'/mnt/nvme1/dataset/{selected_freq}'\n",
"path_to_pictures = f'/mnt/nvme1/dataset_img/noise/{selected_freq}_jpg'"
"path_to_binaries = f'/home/sibsci/dataset/drone/{selected_freq}'\n",
"path_to_pictures = f'/home/sibsci/dataset_img/drone/{selected_freq}_jpg'"
]
},
{
"cell_type": "code",
"execution_count": 6,
"execution_count": 7,
"id": "ac4945a8-29c4-4da4-945f-08658953e3e5",
"metadata": {},
"outputs": [],
@ -170,7 +170,7 @@
},
{
"cell_type": "code",
"execution_count": 13,
"execution_count": 8,
"id": "6f226f86-5d72-4573-8af6-750128b70263",
"metadata": {},
"outputs": [
@ -178,287 +178,14 @@
"name": "stderr",
"output_type": "stream",
"text": [
"2026-03-25_16-59-25: 0%| | 0/40 [00:00<?, ?it/s]"
]
},
{
"name": "stderr",
"output_type": "stream",
"text": [
"2026-03-25_16-59-25: 100%|██████████| 40/40 [00:47<00:00, 1.18s/it]\n"
]
},
{
"name": "stdout",
"output_type": "stream",
"text": [
"Dir: 2026-03-25_16-59-25 finished!\n"
]
},
{
"name": "stderr",
"output_type": "stream",
"text": [
"2026-03-26_02-59-25: 100%|██████████| 40/40 [00:47<00:00, 1.18s/it]\n"
]
},
{
"name": "stdout",
"output_type": "stream",
"text": [
"Dir: 2026-03-26_02-59-25 finished!\n"
]
},
{
"name": "stderr",
"output_type": "stream",
"text": [
"2026-03-25_14-59-25: 100%|██████████| 40/40 [00:35<00:00, 1.11it/s]\n"
]
},
{
"name": "stdout",
"output_type": "stream",
"text": [
"Dir: 2026-03-25_14-59-25 finished!\n"
]
},
{
"name": "stderr",
"output_type": "stream",
"text": [
"2026-03-26_04-59-26: 100%|██████████| 40/40 [00:49<00:00, 1.23s/it]\n"
]
},
{
"name": "stdout",
"output_type": "stream",
"text": [
"Dir: 2026-03-26_04-59-26 finished!\n"
]
},
{
"name": "stderr",
"output_type": "stream",
"text": [
"2026-03-25_17-59-26: 100%|██████████| 40/40 [00:44<00:00, 1.12s/it]\n"
]
},
{
"name": "stdout",
"output_type": "stream",
"text": [
"Dir: 2026-03-25_17-59-26 finished!\n"
]
},
{
"name": "stderr",
"output_type": "stream",
"text": [
"2026-03-25_20-59-26: 100%|██████████| 40/40 [00:47<00:00, 1.20s/it]\n"
]
},
{
"name": "stdout",
"output_type": "stream",
"text": [
"Dir: 2026-03-25_20-59-26 finished!\n"
]
},
{
"name": "stderr",
"output_type": "stream",
"text": [
"2026-03-25_22-59-25: 100%|██████████| 40/40 [00:45<00:00, 1.13s/it]\n"
]
},
{
"name": "stdout",
"output_type": "stream",
"text": [
"Dir: 2026-03-25_22-59-25 finished!\n"
]
},
{
"name": "stderr",
"output_type": "stream",
"text": [
"2026-03-25_14-56-12: 100%|██████████| 25/25 [00:22<00:00, 1.12it/s]\n"
]
},
{
"name": "stdout",
"output_type": "stream",
"text": [
"Dir: 2026-03-25_14-56-12 finished!\n"
]
},
{
"name": "stderr",
"output_type": "stream",
"text": [
"2026-03-26_00-59-27: 100%|██████████| 40/40 [00:46<00:00, 1.16s/it]\n"
]
},
{
"name": "stdout",
"output_type": "stream",
"text": [
"Dir: 2026-03-26_00-59-27 finished!\n"
]
},
{
"name": "stderr",
"output_type": "stream",
"text": [
"2026-03-25_19-59-25: 100%|██████████| 40/40 [00:44<00:00, 1.11s/it]\n"
]
},
{
"name": "stdout",
"output_type": "stream",
"text": [
"Dir: 2026-03-25_19-59-25 finished!\n"
]
},
{
"name": "stderr",
"output_type": "stream",
"text": [
"2026-03-26_05-59-25: 100%|██████████| 40/40 [00:48<00:00, 1.20s/it]\n"
]
},
{
"name": "stdout",
"output_type": "stream",
"text": [
"Dir: 2026-03-26_05-59-25 finished!\n"
]
},
{
"name": "stderr",
"output_type": "stream",
"text": [
"2026-03-26_08-59-25: 100%|██████████| 40/40 [00:47<00:00, 1.18s/it]\n"
]
},
{
"name": "stdout",
"output_type": "stream",
"text": [
"Dir: 2026-03-26_08-59-25 finished!\n"
]
},
{
"name": "stderr",
"output_type": "stream",
"text": [
"2026-03-26_07-59-25: 100%|██████████| 40/40 [00:46<00:00, 1.16s/it]\n"
]
},
{
"name": "stdout",
"output_type": "stream",
"text": [
"Dir: 2026-03-26_07-59-25 finished!\n"
]
},
{
"name": "stderr",
"output_type": "stream",
"text": [
"2026-03-26_06-59-26: 100%|██████████| 40/40 [00:48<00:00, 1.20s/it]\n"
]
},
{
"name": "stdout",
"output_type": "stream",
"text": [
"Dir: 2026-03-26_06-59-26 finished!\n"
]
},
{
"name": "stderr",
"output_type": "stream",
"text": [
"2026-03-26_01-59-26: 100%|██████████| 40/40 [00:47<00:00, 1.20s/it]\n"
]
},
{
"name": "stdout",
"output_type": "stream",
"text": [
"Dir: 2026-03-26_01-59-26 finished!\n"
]
},
{
"name": "stderr",
"output_type": "stream",
"text": [
"2026-03-25_15-59-26: 100%|██████████| 40/40 [00:45<00:00, 1.14s/it]\n"
]
},
{
"name": "stdout",
"output_type": "stream",
"text": [
"Dir: 2026-03-25_15-59-26 finished!\n"
]
},
{
"name": "stderr",
"output_type": "stream",
"text": [
"2026-03-25_23-59-26: 100%|██████████| 40/40 [00:48<00:00, 1.20s/it]\n"
]
},
{
"name": "stdout",
"output_type": "stream",
"text": [
"Dir: 2026-03-25_23-59-26 finished!\n"
]
},
{
"name": "stderr",
"output_type": "stream",
"text": [
"2026-03-25_21-59-26: 100%|██████████| 40/40 [00:46<00:00, 1.17s/it]\n"
]
},
{
"name": "stdout",
"output_type": "stream",
"text": [
"Dir: 2026-03-25_21-59-26 finished!\n"
]
},
{
"name": "stderr",
"output_type": "stream",
"text": [
"2026-03-25_18-59-25: 100%|██████████| 40/40 [00:47<00:00, 1.19s/it]\n"
]
},
{
"name": "stdout",
"output_type": "stream",
"text": [
"Dir: 2026-03-25_18-59-25 finished!\n"
]
},
{
"name": "stderr",
"output_type": "stream",
"text": [
"2026-03-26_03-59-26: 100%|██████████| 40/40 [00:47<00:00, 1.19s/it]"
"2026-04-06_11-37-43: 100%|██████████| 42/42 [00:11<00:00, 3.55it/s]"
]
},
{
"name": "stdout",
"output_type": "stream",
"text": [
"Dir: 2026-03-26_03-59-26 finished!\n"
"Dir: 2026-04-06_11-37-43 finished!\n"
]
},
{
@ -473,7 +200,7 @@
"size = (256,256)\n",
"\n",
"if not os.path.exists(path_to_pictures):\n",
" os.mkdir(path_to_pictures)\n",
" os.makedirs(path_to_pictures,exist_ok=True)\n",
"\n",
"for subdir in os.listdir(path_to_binaries):\n",
" filepath = path_to_binaries + '/' + subdir + '/'\n",
@ -542,7 +269,7 @@
],
"metadata": {
"kernelspec": {
"display_name": ".venv-train (3.12.3)",
"display_name": ".venv-train",
"language": "python",
"name": "python3"
},

File diff suppressed because one or more lines are too long
Loading…
Cancel
Save