format: re-format with ruff and isort

This commit is contained in:
Christos Falas 2025-01-23 11:13:17 +00:00
parent 5a481ae13b
commit 8e1a849b7c
No known key found for this signature in database
6 changed files with 65 additions and 57 deletions

View File

@ -1,6 +1,12 @@
[tool.ruff]
line-length = 88
[tool.ruff.lint]
extend-select = ["I", "E", "W", "F", "B", "Q", "ANN"]
[tool.ruff.lint.pycodestyle]
max-doc-length = 88
[tool.pyright]
typeCheckingMode = "strict"
reportMissingTypeStubs = "warning"

View File

@ -1,20 +1,19 @@
import typer
import multiprocessing as mp
from .collection import ingest
from .processing.preprocess import Preprocessor
from .processing.aoa import AoA
from . import config
from . import visualise
import numpy as np
import numpy.typing as npt
import typer
from . import config, visualise
from .collection import ingest
from .processing.aoa import AoA
from .processing.preprocess import Preprocessor
app = typer.Typer()
@app.command()
def heatmap():
def heatmap() -> None:
preprocessor = Preprocessor()
aoa = AoA()
webapp_queue: "mp.Queue[AoA]" = mp.Queue(config.SAMPLE_RATE)
@ -22,7 +21,7 @@ def heatmap():
webapp = mp.Process(target=visualise.start, args=(webapp_queue,))
webapp.start()
def callback(antenna_data: npt.NDArray[np.complex128]):
def callback(antenna_data: npt.NDArray[np.complex128]) -> None:
processed = preprocessor.preprocess(antenna_data)
# visualise.add_data(all_data, processed)
aoa.update(processed)

View File

@ -1,8 +1,8 @@
import struct
import numpy as np
import numpy.typing as npt
RATE_MCS_MOD_TYPE_POS = 8
RATE_MCS_MOD_TYPE_MSK = 0x7 << RATE_MCS_MOD_TYPE_POS
RATE_MCS_CCK_MSK = 0 << RATE_MCS_MOD_TYPE_POS
@ -37,7 +37,7 @@ RATE_MCS_BEAMF_MSK = 1 << RATE_MCS_BEAMF_POS
class CSIHeader:
def __init__(self, data: bytes):
def __init__(self, data: bytes) -> None:
self.csi_size = struct.unpack("I", data[0:4])[0]
self.ftm_clock = struct.unpack("I", data[8:12])[0]
self.num_rx = data[46]
@ -93,7 +93,7 @@ class CSIHeader:
class CSI:
@staticmethod
def parseCsiData(data: bytes, header: CSIHeader):
def parseCsiData(data: bytes, header: CSIHeader) -> npt.NDArray[np.complex128]:
csi_matrix: npt.NDArray[np.complex128] = np.zeros(
(
header.num_subcarriers,
@ -113,7 +113,7 @@ class CSI:
return csi_matrix
def __init__(self, data: bytes):
def __init__(self, data: bytes) -> None:
self.header = CSIHeader(data[:272])
self.matrix = self.parseCsiData(
data[272 : 272 + self.header.csi_size], self.header

View File

@ -1,26 +1,25 @@
import logging
import time
import socket
import multiprocessing as mp
import threading
import subprocess
import socket
import struct
from typing import Callable
import subprocess
import threading
import time
from datetime import datetime
from typing import Callable, NamedTuple, NoReturn
import numpy as np
import numpy.typing as npt
from typing import NamedTuple
from .csi_frame import CSI
from .. import config
from .csi_frame import CSI
Host = tuple[str, int]
CSICallback = Callable[[npt.NDArray[np.complex128]], None]
class FeitHost:
def __init__(self, host: Host, command: str):
def __init__(self, host: Host, command: str) -> None:
self.command = command
self.host = host
self.logger = logging.getLogger(
@ -29,7 +28,7 @@ class FeitHost:
self.checker = threading.Thread(target=self.check_continuous)
self.checker.start()
def check_connection(self):
def check_connection(self) -> bool:
feitcsi_status = subprocess.run(
f"ssh root@{self.host[0]} pgrep feitcsi",
check=False,
@ -38,18 +37,20 @@ class FeitHost:
)
return feitcsi_status.returncode == 0
def connect(self):
def connect(self) -> None:
self.server = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
self.server.connect(self.host)
self.server.send(b"stop\n")
self.server.send(self.command.encode())
self.logger.info(f"Connected to {self.host}")
def check_continuous(self):
def check_continuous(self) -> NoReturn:
"""
Repeatedly check if the FeitCSI service is running
Because FeitCSI is using TCP, we will get no information if the service stops, or the computer is not reachable. In order to make debugging easier, this checks and logs continuously if the service is running.
Because FeitCSI is using TCP, we will get no information if the service stops,
or the computer is not reachable. In order to make debugging easier, this checks
and logs continuously if the service is running.
"""
last_status = False
while True:
@ -64,7 +65,7 @@ class FeitHost:
class FeitTransmitter(FeitHost):
def __init__(self):
def __init__(self) -> None:
command = (
f"feitcsi --frequency {config.CENTRAL_FREQUENCY_MHZ} "
f"--channel-width {config.CHANNEL_WIDTH} "
@ -76,7 +77,7 @@ class FeitTransmitter(FeitHost):
class FeitReceiver(FeitHost):
def __init__(self, host: Host):
def __init__(self, host: Host) -> None:
command = (
f"feitcsi --frequency {config.CENTRAL_FREQUENCY_MHZ} "
f"--channel-width {config.CHANNEL_WIDTH} "
@ -85,7 +86,7 @@ class FeitReceiver(FeitHost):
)
super().__init__(host, command)
def listen(self, queue: "mp.Queue[CSI]"):
def listen(self, queue: "mp.Queue[CSI]") -> NoReturn:
prev_time = datetime.now()
self.logger.info("Listening for CSI data")
while True:
@ -110,14 +111,14 @@ class CSIProcessor:
def __init__(
self,
receiver_connections: dict[Host, "mp.Queue[CSI]"],
):
) -> None:
self.pending_data: dict[Host, tuple[datetime, CSI]] = {}
self.pending_data_lock = mp.Lock()
self.logger = logging.getLogger(f"{__name__}.{self.__class__.__name__}")
self.last_processed = datetime.now()
self.connections = receiver_connections
def add_data(self, host: Host, data: CSI):
def add_data(self, host: Host, data: CSI) -> None:
if (
host in self.pending_data
and self.last_processed < self.pending_data[host][0]
@ -129,15 +130,15 @@ class CSIProcessor:
with self.pending_data_lock:
self.pending_data[host] = (datetime.now(), data)
# Useful for figuring out the correct antenna order - RSSI values will decrease
# when the specific antenna is disconnected
# Useful for figuring out the correct antenna order - RSSI values will
# decrease when the specific antenna is disconnected
rssis = [
(ip, csi.header.rssi1, csi.header.rssi2)
for ip, (_, csi) in sorted(self.pending_data.items())
]
self.logger.debug("Antenna RSSI values: {}".format(rssis))
def is_ready(self):
def is_ready(self) -> bool:
for host in config.RECEIVE_HOSTS:
if (
host not in self.pending_data
@ -146,7 +147,7 @@ class CSIProcessor:
return False
return True
def process_data(self, callback: CSICallback):
def process_data(self, callback: CSICallback) -> None:
self.last_processed = datetime.now()
antenna_data = [
np.expand_dims(self.pending_data[ip][1].matrix[:, antenna], axis=2)
@ -162,7 +163,7 @@ class CSIProcessor:
def process_forever(
self,
callback: CSICallback,
):
) -> NoReturn:
while True:
for ip, queue in self.connections.items():
while not queue.empty():
@ -180,7 +181,7 @@ class Receiver(NamedTuple):
queue: "mp.Queue[CSI]"
def start_processing(csi_callback: CSICallback):
def start_processing(csi_callback: CSICallback) -> None:
receivers = [
Receiver(ip, FeitReceiver(ip), mp.Queue(config.SAMPLE_RATE))
for ip in config.RECEIVE_HOSTS

View File

@ -1,22 +1,23 @@
import numpy as np
import numpy.typing as npt
from .. import config
import logging
from datetime import datetime
import logging
import numpy as np
import numpy.typing as npt
from .. import config
logger = logging.getLogger(__name__)
class AoA:
def __init__(self):
def __init__(self) -> None:
self.historical_autocorr = np.array([])
self.N_subcarriers = -1
self.N_rx = -1
self.timestamp = datetime.now()
pass
def smooth(self, data: npt.NDArray[np.complex128]):
def smooth(self, data: npt.NDArray[np.complex128]) -> npt.NDArray[np.complex128]:
assert len(data.shape) == 3
M = data.shape[0] # Number of subcarriers
@ -44,7 +45,7 @@ class AoA:
return H_sm
def update(self, data: npt.NDArray[np.complex128]):
def update(self, data: npt.NDArray[np.complex128]) -> None:
self.timestamp = datetime.now()
H_sm = self.smooth(data)
@ -76,9 +77,11 @@ class AoA:
2j * np.pi * config.CENTRAL_FREQUENCY_HZ * config.ANTENNA_SPACING / config.C
)
def steering_vector(self, theta: float, tof: float):
omega_t = np.exp(-2j * np.pi * config.DELTA_F * tof)
phi_theta = np.exp(
def steering_vector(
self, theta: float, tof: float
) -> npt.NDArray[np.complexfloating]:
omega_t: npt.NDArray[np.complex128] = np.exp(-2j * np.pi * config.DELTA_F * tof)
phi_theta: npt.NDArray[np.complex128] = np.exp(
2j
* np.pi
* config.CENTRAL_FREQUENCY_HZ
@ -96,7 +99,7 @@ class AoA:
steering = antenna_v * phis
return steering.T.reshape(-1)
def evaluate(self, theta: float, tof: float):
def evaluate(self, theta: float, tof: float) -> float:
try:
steering = self.steering_vector(theta, tof)
steering_h = np.conj(steering).T
@ -109,7 +112,7 @@ class AoA:
return np.abs(c.real)
def test_smoothing():
def test_smoothing() -> None:
row, col = np.indices((4, 2))
data = row + 1j * col
aoa = AoA()
@ -120,10 +123,9 @@ def test_smoothing():
expected = np.hstack([H_01, H_12])
print(expected)
assert np.allclose(smoothed, expected)
pass
def test_steering_vector():
def test_steering_vector() -> None:
aoa = AoA()
aoa.N_subcarriers = 10
aoa.N_rx = 2

View File

@ -1,11 +1,11 @@
import numpy as np
import logging
from queue import Queue
from .. import config
import numpy.typing as npt
from scipy.signal import correlate
from scipy.signal import butter, sosfilt_zi, sosfilt
import numpy as np
import numpy.typing as npt
from scipy.signal import butter, correlate, sosfilt, sosfilt_zi
from .. import config
logger = logging.getLogger(__name__)
logger.setLevel(logging.DEBUG)
@ -14,7 +14,7 @@ np.seterr(invalid="ignore")
class Preprocessor:
def __init__(self):
def __init__(self) -> None:
self.prev_entries: Queue[npt.NDArray[np.complex128]] = Queue(maxsize=100)
self.short_term_avg = np.zeros((1,), dtype=np.complex128)
self.long_term_avg = np.zeros((1,), dtype=np.complex128)