refactor: change Pipe to Queue for configurable maxsize
This commit is contained in:
parent
0d8bea2678
commit
ae2e95283b
@ -1,11 +1,11 @@
|
|||||||
import logging
|
import logging
|
||||||
import multiprocessing as mp
|
import multiprocessing as mp
|
||||||
from multiprocessing.connection import Connection
|
|
||||||
from typing import NamedTuple
|
from typing import NamedTuple
|
||||||
|
|
||||||
from . import ingest
|
from . import ingest
|
||||||
from . import config
|
from . import config
|
||||||
from . import visualise
|
from . import visualise
|
||||||
|
from . import aoa
|
||||||
|
|
||||||
|
|
||||||
logging.basicConfig(
|
logging.basicConfig(
|
||||||
@ -17,28 +17,27 @@ logging.basicConfig(
|
|||||||
class Receiver(NamedTuple):
|
class Receiver(NamedTuple):
|
||||||
ip: str
|
ip: str
|
||||||
receiver: ingest.FeitReceiver
|
receiver: ingest.FeitReceiver
|
||||||
recv: Connection
|
queue: "mp.Queue[ingest.CSI]"
|
||||||
send: Connection
|
|
||||||
|
|
||||||
|
|
||||||
receivers = [
|
receivers = [
|
||||||
Receiver(ip, ingest.FeitReceiver(ip), *mp.Pipe(duplex=False))
|
Receiver(ip, ingest.FeitReceiver(ip), mp.Queue(config.SAMPLE_RATE))
|
||||||
for ip in config.RECEIVE_IP_ADDRESS_LIST
|
for ip in config.RECEIVE_IP_ADDRESS_LIST
|
||||||
]
|
]
|
||||||
|
|
||||||
# Start injecting CSI frames
|
# Start injecting CSI frames
|
||||||
transmitter = ingest.FeitTransmitter()
|
transmitter = ingest.FeitTransmitter()
|
||||||
|
|
||||||
webapp_conns = mp.Pipe()
|
webapp_queue: "mp.Queue[aoa.AoA]" = mp.Queue(config.SAMPLE_RATE)
|
||||||
|
|
||||||
processor = ingest.CSIProcessor({r.ip: r.recv for r in receivers}, webapp_conns[0])
|
processor = ingest.CSIProcessor({r.ip: r.queue for r in receivers}, webapp_queue)
|
||||||
|
|
||||||
# Start webapp in background process
|
# Start webapp in background process
|
||||||
webapp = mp.Process(target=visualise.start, args=(webapp_conns[1],))
|
webapp = mp.Process(target=visualise.start, args=(webapp_queue,))
|
||||||
webapp.start()
|
webapp.start()
|
||||||
|
|
||||||
receiver_processes = [
|
receiver_processes = [
|
||||||
mp.Process(target=r.receiver.listen, args=(r.send,)) for r in receivers
|
mp.Process(target=r.receiver.listen, args=(r.queue,)) for r in receivers
|
||||||
]
|
]
|
||||||
|
|
||||||
for proc in receiver_processes:
|
for proc in receiver_processes:
|
||||||
|
|||||||
11
src/aoa.py
11
src/aoa.py
@ -1,6 +1,7 @@
|
|||||||
import numpy as np
|
import numpy as np
|
||||||
import numpy.typing as npt
|
import numpy.typing as npt
|
||||||
from . import config
|
from . import config
|
||||||
|
from datetime import datetime
|
||||||
|
|
||||||
import logging
|
import logging
|
||||||
|
|
||||||
@ -10,8 +11,9 @@ logger = logging.getLogger(__name__)
|
|||||||
class AoA:
|
class AoA:
|
||||||
def __init__(self):
|
def __init__(self):
|
||||||
self.historical_autocorr = np.array([])
|
self.historical_autocorr = np.array([])
|
||||||
self.N_subcarriers = config.N_SUBCARRIERS - 2
|
self.N_subcarriers = -1
|
||||||
self.N_rx = len(config.ANTENNA_ORDER)
|
self.N_rx = -1
|
||||||
|
self.timestamp = datetime.now()
|
||||||
pass
|
pass
|
||||||
|
|
||||||
def smooth(self, data: npt.NDArray[np.complex128]):
|
def smooth(self, data: npt.NDArray[np.complex128]):
|
||||||
@ -21,8 +23,8 @@ class AoA:
|
|||||||
N = data.shape[1] # Number of RX antennas
|
N = data.shape[1] # Number of RX antennas
|
||||||
T = data.shape[2] # Number of TX antennas
|
T = data.shape[2] # Number of TX antennas
|
||||||
|
|
||||||
assert N == self.N_rx
|
self.N_subcarriers = M
|
||||||
assert M == self.N_subcarriers
|
self.N_rx = N
|
||||||
|
|
||||||
logger.debug(f"Smoothing: Subcarriers: {M}, RX antennas: {N}, TX antennas: {T}")
|
logger.debug(f"Smoothing: Subcarriers: {M}, RX antennas: {N}, TX antennas: {T}")
|
||||||
|
|
||||||
@ -43,6 +45,7 @@ class AoA:
|
|||||||
return H_sm
|
return H_sm
|
||||||
|
|
||||||
def update(self, data: npt.NDArray[np.complex128]):
|
def update(self, data: npt.NDArray[np.complex128]):
|
||||||
|
self.timestamp = datetime.now()
|
||||||
H_sm = self.smooth(data)
|
H_sm = self.smooth(data)
|
||||||
|
|
||||||
auto_corr = np.matmul(H_sm, np.conj(H_sm).T)
|
auto_corr = np.matmul(H_sm, np.conj(H_sm).T)
|
||||||
|
|||||||
@ -31,8 +31,6 @@ ANTENNA_SPACING = 0.0285 # 2.85 cm
|
|||||||
CHANNEL_WIDTH = 20
|
CHANNEL_WIDTH = 20
|
||||||
FRAME_FORMAT = "HT"
|
FRAME_FORMAT = "HT"
|
||||||
|
|
||||||
N_SUBCARRIERS = 56
|
|
||||||
|
|
||||||
|
|
||||||
CENTRAL_FREQUENCY_HZ = CENTRAL_FREQUENCY_MHZ * 1_000_000
|
CENTRAL_FREQUENCY_HZ = CENTRAL_FREQUENCY_MHZ * 1_000_000
|
||||||
C = 299_792_458 # m/s
|
C = 299_792_458 # m/s
|
||||||
|
|||||||
@ -2,7 +2,6 @@ import logging
|
|||||||
import time
|
import time
|
||||||
import socket
|
import socket
|
||||||
import multiprocessing as mp
|
import multiprocessing as mp
|
||||||
from multiprocessing.connection import Connection
|
|
||||||
import struct
|
import struct
|
||||||
from datetime import datetime
|
from datetime import datetime
|
||||||
import numpy as np
|
import numpy as np
|
||||||
@ -46,7 +45,7 @@ class FeitReceiver:
|
|||||||
f"{__name__}.{self.__class__.__name__}-{self.host}"
|
f"{__name__}.{self.__class__.__name__}-{self.host}"
|
||||||
)
|
)
|
||||||
|
|
||||||
def listen(self, conn: Connection):
|
def listen(self, queue: "mp.Queue[CSI]"):
|
||||||
prev_time = datetime.now()
|
prev_time = datetime.now()
|
||||||
while True:
|
while True:
|
||||||
# This is the max size of a UDP packet. The size of the actual CSI
|
# This is the max size of a UDP packet. The size of the actual CSI
|
||||||
@ -59,14 +58,16 @@ class FeitReceiver:
|
|||||||
f"Received CSI data after {datetime.now() - prev_time}"
|
f"Received CSI data after {datetime.now() - prev_time}"
|
||||||
)
|
)
|
||||||
prev_time = datetime.now()
|
prev_time = datetime.now()
|
||||||
conn.send(csidata)
|
queue.put(csidata)
|
||||||
except struct.error:
|
except struct.error:
|
||||||
self.logger.error("Failed to parse CSI data")
|
self.logger.error("Failed to parse CSI data")
|
||||||
|
|
||||||
|
|
||||||
class CSIProcessor:
|
class CSIProcessor:
|
||||||
def __init__(
|
def __init__(
|
||||||
self, receiver_connections: dict[str, Connection], webserver: Connection
|
self,
|
||||||
|
receiver_connections: dict[str, "mp.Queue[CSI]"],
|
||||||
|
webserver: "mp.Queue[AoA]",
|
||||||
):
|
):
|
||||||
self.pending_data: dict[str, tuple[datetime, CSI]] = {}
|
self.pending_data: dict[str, tuple[datetime, CSI]] = {}
|
||||||
self.pending_data_lock = mp.Lock()
|
self.pending_data_lock = mp.Lock()
|
||||||
@ -122,13 +123,14 @@ class CSIProcessor:
|
|||||||
processed = self.preprocess.preprocess(all_data)
|
processed = self.preprocess.preprocess(all_data)
|
||||||
visualise.add_data(all_data, processed)
|
visualise.add_data(all_data, processed)
|
||||||
self.aoa.update(processed)
|
self.aoa.update(processed)
|
||||||
self.webserver.send(self.aoa.E_n)
|
if not self.webserver.full():
|
||||||
|
self.webserver.put(self.aoa)
|
||||||
|
|
||||||
def process_forever(self):
|
def process_forever(self):
|
||||||
while True:
|
while True:
|
||||||
for ip, conn in self.connections.items():
|
for ip, queue in self.connections.items():
|
||||||
if conn.poll():
|
while not queue.empty():
|
||||||
self.add_data(ip, conn.recv())
|
self.add_data(ip, queue.get())
|
||||||
if self.is_ready():
|
if self.is_ready():
|
||||||
self.process_data()
|
self.process_data()
|
||||||
else:
|
else:
|
||||||
|
|||||||
@ -5,7 +5,7 @@ import numpy.typing as npt
|
|||||||
from simple_websocket import Server
|
from simple_websocket import Server
|
||||||
import time
|
import time
|
||||||
from datetime import datetime
|
from datetime import datetime
|
||||||
from multiprocessing.connection import Connection
|
import multiprocessing as mp
|
||||||
|
|
||||||
import matplotlib.pyplot as plt
|
import matplotlib.pyplot as plt
|
||||||
import io
|
import io
|
||||||
@ -20,7 +20,7 @@ matplotlib.use("agg")
|
|||||||
|
|
||||||
app = Flask(__name__)
|
app = Flask(__name__)
|
||||||
sock = Sock(app)
|
sock = Sock(app)
|
||||||
aoa_conn = None
|
aoa_queue = None
|
||||||
|
|
||||||
logger = logging.getLogger(__name__)
|
logger = logging.getLogger(__name__)
|
||||||
|
|
||||||
@ -92,7 +92,8 @@ def add_data(
|
|||||||
del subscriber_settings[subscriber]
|
del subscriber_settings[subscriber]
|
||||||
|
|
||||||
|
|
||||||
def make_heatmap(max_tof: float):
|
def make_heatmap(aoa: AoA, max_tof: float):
|
||||||
|
logger.info(f"Making heatmap with aoa of {aoa.timestamp}")
|
||||||
fig = plt.figure()
|
fig = plt.figure()
|
||||||
ax = fig.add_axes([0, 0, 1, 1], polar=True)
|
ax = fig.add_axes([0, 0, 1, 1], polar=True)
|
||||||
r = np.linspace(0, max_tof, 100) # Radius values
|
r = np.linspace(0, max_tof, 100) # Radius values
|
||||||
@ -112,20 +113,18 @@ def make_heatmap(max_tof: float):
|
|||||||
|
|
||||||
|
|
||||||
def gather_aoa(max_tof: float):
|
def gather_aoa(max_tof: float):
|
||||||
assert aoa_conn is not None
|
assert aoa_queue is not None
|
||||||
|
|
||||||
prev_frame = datetime.now()
|
prev_frame = datetime.now()
|
||||||
while True:
|
while True:
|
||||||
while (datetime.now() - prev_frame).total_seconds() < 1 / config.HEATMAP_FPS:
|
while (datetime.now() - prev_frame).total_seconds() < 1 / config.HEATMAP_FPS:
|
||||||
time.sleep(0.01)
|
time.sleep(0.01)
|
||||||
while aoa_conn.poll():
|
while not aoa_queue.empty():
|
||||||
logger.debug("Receiving from aoa pipe")
|
logger.debug("Receiving from aoa pipe")
|
||||||
E_n = aoa_conn.recv()
|
aoa = aoa_queue.get()
|
||||||
aoa.N_subcarriers = 54
|
|
||||||
aoa.E_n = E_n
|
|
||||||
prev_frame = datetime.now()
|
prev_frame = datetime.now()
|
||||||
logger.debug("Generating heatmap")
|
logger.debug(f"Generating heatmap of time {aoa.timestamp}")
|
||||||
buf = make_heatmap(max_tof)
|
buf = make_heatmap(aoa, max_tof)
|
||||||
yield (b"--frame\r\nContent-Type: image/jpeg\r\n\r\n" + buf.read() + b"\r\n")
|
yield (b"--frame\r\nContent-Type: image/jpeg\r\n\r\n" + buf.read() + b"\r\n")
|
||||||
buf.close()
|
buf.close()
|
||||||
|
|
||||||
@ -142,8 +141,8 @@ def aoa_tof():
|
|||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
def start(conn: Connection):
|
def start(conn: "mp.Queue[AoA]"):
|
||||||
global aoa_conn
|
global aoa_queue
|
||||||
|
|
||||||
aoa_conn = conn
|
aoa_queue = conn
|
||||||
app.run(debug=True, use_reloader=False, host="0.0.0.0")
|
app.run(debug=True, use_reloader=False, host="0.0.0.0")
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user