Support multiple receiving hosts
This commit is contained in:
parent
25e259f038
commit
a9d05ca975
11
src/aoa.py
11
src/aoa.py
@ -34,15 +34,10 @@ class AoA:
|
||||
for j in range(M // 2):
|
||||
H_n[i, j] = data[j : j + M // 2 + 1, i, 0]
|
||||
|
||||
H_sm = np.vstack([H_n[0], H_n[1]])
|
||||
H_sm_rows = [np.hstack(H_n[i : i + N // 2 + 1]) for i in range(N // 2)]
|
||||
H_sm = np.vstack(H_sm_rows)
|
||||
|
||||
# This would normally have to be arranged as follows:
|
||||
# H_0 H_1 ... H_{N//2 - 1}
|
||||
# H_1 H_2 ... H_{N//2}
|
||||
# ...
|
||||
# H_{N//2} ... H{N-1}
|
||||
# But this doesn't work when we only have 2 receiving antennas
|
||||
assert N == 2, "The current implementation only supports 2 RX antennas"
|
||||
logger.info(f"Smoothed: {H_sm.shape}")
|
||||
|
||||
return H_sm
|
||||
|
||||
|
||||
@ -6,20 +6,27 @@ PREPROCESSING_LONG_TERM_ALPHA = 0.01
|
||||
PREPROCESSING_BANDPASS_LOW_CUTOFF = 2
|
||||
PREPROCESSING_BANDPASS_HIGH_CUTOFF = 40
|
||||
|
||||
AOA_SLIDING_WINDOW_SIZE = 20
|
||||
AOA_SLIDING_WINDOW_SIZE = 40
|
||||
|
||||
RECEIVE_IP_ADDRESS = os.getenv("IP_ADDRESS", "10.0.12.64")
|
||||
RECEIVE_IP_ADDRESS_LIST = ["10.0.12.64", "10.0.12.62"]
|
||||
INJECT_IP_ADDRESS = os.getenv("INJECT_IP_ADDRESS", "10.0.12.63")
|
||||
FEITCSI_PORT = 8008
|
||||
|
||||
ANTENNA_ORDER = [
|
||||
("10.0.12.62", 0),
|
||||
("10.0.12.64", 1),
|
||||
("10.0.12.64", 0),
|
||||
("10.0.12.62", 1),
|
||||
]
|
||||
|
||||
SAMPLE_RATE = 100 # Hz
|
||||
|
||||
EIGVAL_THRESHOLD = 1000
|
||||
EIGVAL_THRESHOLD = 10
|
||||
|
||||
|
||||
# DELTA_F = 78_125 # Spacing between subcarriers in Hz
|
||||
DELTA_F = 312_500 # Spacing between subcarriers in Hz
|
||||
CENTRAL_FREQUENCY_MHZ = 5220
|
||||
CENTRAL_FREQUENCY_MHZ = 6195
|
||||
ANTENNA_SPACING = 0.0285 # 2.85 cm
|
||||
CHANNEL_WIDTH = 20
|
||||
FRAME_FORMAT = "HT"
|
||||
|
||||
109
src/main.py
109
src/main.py
@ -3,6 +3,8 @@ import socket
|
||||
from typing import Callable
|
||||
import threading
|
||||
import struct
|
||||
from datetime import datetime
|
||||
import numpy as np
|
||||
|
||||
from .csi import CSI
|
||||
from .aoa import AoA
|
||||
@ -12,28 +14,16 @@ from . import visualise
|
||||
|
||||
logging.basicConfig(
|
||||
level=logging.INFO,
|
||||
format="%(asctime)s %(levelname)-8s %(message)s",
|
||||
format="%(asctime)s %(name)-8s %(levelname)-8s %(message)s",
|
||||
)
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
class FeitServer:
|
||||
def __init__(
|
||||
self,
|
||||
):
|
||||
self.port = config.FEITCSI_PORT
|
||||
self.server = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
|
||||
self.server.connect((config.RECEIVE_IP_ADDRESS, self.port))
|
||||
self.start_string = (
|
||||
f"feitcsi --frequency {config.CENTRAL_FREQUENCY_MHZ} "
|
||||
f"--channel-width {config.CHANNEL_WIDTH} "
|
||||
f"--format {config.FRAME_FORMAT} "
|
||||
f"--mode measure"
|
||||
)
|
||||
self.server.send(b"stop\n")
|
||||
self.server.send(self.start_string.encode())
|
||||
|
||||
class FeitTransmitter:
|
||||
def __init__(self):
|
||||
self.inject_server = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
|
||||
self.inject_server.connect((config.INJECT_IP_ADDRESS, self.port))
|
||||
self.inject_server.connect((config.INJECT_IP_ADDRESS, config.FEITCSI_PORT))
|
||||
inject_start_string = (
|
||||
f"feitcsi --frequency {config.CENTRAL_FREQUENCY_MHZ} "
|
||||
f"--channel-width {config.CHANNEL_WIDTH} "
|
||||
@ -44,7 +34,23 @@ class FeitServer:
|
||||
self.inject_server.send(b"stop\n")
|
||||
self.inject_server.send(inject_start_string.encode())
|
||||
|
||||
def listen(self, callback: Callable[[CSI], None]):
|
||||
|
||||
class FeitServer:
|
||||
def __init__(self, host: str):
|
||||
self.host = host
|
||||
self.server = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
|
||||
self.server.connect((self.host, config.FEITCSI_PORT))
|
||||
self.start_string = (
|
||||
f"feitcsi --frequency {config.CENTRAL_FREQUENCY_MHZ} "
|
||||
f"--channel-width {config.CHANNEL_WIDTH} "
|
||||
f"--format {config.FRAME_FORMAT} "
|
||||
f"--mode measure"
|
||||
)
|
||||
self.server.send(b"stop\n")
|
||||
self.server.send(self.start_string.encode())
|
||||
|
||||
def listen(self, callback: Callable[[str, CSI], None]):
|
||||
prev_time = datetime.now()
|
||||
while True:
|
||||
# This is the max size of a UDP packet. The size of the actual CSI
|
||||
# packet will depend on the frame format and channel width, which
|
||||
@ -52,20 +58,66 @@ class FeitServer:
|
||||
data = self.server.recv(65535)
|
||||
try:
|
||||
csidata = CSI(data)
|
||||
callback(csidata)
|
||||
logger.debug(f"Received CSI data after {datetime.now() - prev_time}")
|
||||
prev_time = datetime.now()
|
||||
callback(self.host, csidata)
|
||||
except struct.error:
|
||||
logging.error("Failed to parse CSI data")
|
||||
logger.error("Failed to parse CSI data")
|
||||
|
||||
|
||||
def process_data(data: CSI):
|
||||
logging.debug("Got CSI frame")
|
||||
processed = preprocess.preprocess(data)
|
||||
visualise.add_data(processed)
|
||||
pending_data: dict[str, tuple[datetime, CSI]] = {}
|
||||
pending_data_lock = threading.Lock()
|
||||
|
||||
|
||||
def process_data(host: str, data: CSI):
|
||||
global pending_data
|
||||
current_time = datetime.now()
|
||||
|
||||
logger.debug(f"Got CSI data from {host}")
|
||||
|
||||
with pending_data_lock:
|
||||
if host in pending_data and (
|
||||
current_time - pending_data[host][0]
|
||||
).total_seconds() < 1 / (2 * config.SAMPLE_RATE):
|
||||
logger.warning(f"Received CSI data from {host} too quickly")
|
||||
return
|
||||
elif host in pending_data:
|
||||
logger.warning(f"Skipping existing CSI data from {host}")
|
||||
pending_data[host] = (datetime.now(), data)
|
||||
|
||||
for ip in config.RECEIVE_IP_ADDRESS_LIST:
|
||||
if ip not in pending_data:
|
||||
return
|
||||
|
||||
logger.debug(
|
||||
"Antenna RSSI values:"
|
||||
+ str(
|
||||
[
|
||||
(ip, csi.header.rssi1, csi.header.rssi2)
|
||||
for ip, (_, csi) in sorted(pending_data.items())
|
||||
]
|
||||
),
|
||||
)
|
||||
|
||||
antenna_data = [
|
||||
np.expand_dims(pending_data[ip][1].matrix[:, antenna], axis=2)
|
||||
for ip, antenna in config.ANTENNA_ORDER
|
||||
]
|
||||
|
||||
# We have data from all servers
|
||||
all_data = np.concat(antenna_data, axis=1)
|
||||
logger.info(f"Got final CSI data with shape {all_data.shape}")
|
||||
pending_data = {}
|
||||
|
||||
# logging.info(f"Got CSI frame with shape {data.matrix.shape}")
|
||||
processed = preprocess.preprocess(all_data)
|
||||
visualise.add_data(data.matrix, processed)
|
||||
aoa.update(processed)
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
server = FeitServer()
|
||||
servers = [FeitServer(ip) for ip in config.RECEIVE_IP_ADDRESS_LIST]
|
||||
transmitter = FeitTransmitter()
|
||||
preprocess = Preprocessor()
|
||||
aoa = AoA()
|
||||
|
||||
@ -74,4 +126,9 @@ if __name__ == "__main__":
|
||||
webapp = threading.Thread(target=visualise.start)
|
||||
webapp.start()
|
||||
|
||||
server.listen(process_data)
|
||||
server_threads = [
|
||||
threading.Thread(target=server.listen, args=(process_data,))
|
||||
for server in servers
|
||||
]
|
||||
for thread in server_threads:
|
||||
thread.start()
|
||||
|
||||
Loading…
Reference in New Issue
Block a user