add run command to CLI

This commit is contained in:
Christos Falas 2025-05-15 09:50:27 +01:00
parent 57fadd245a
commit 02eed8bf76
No known key found for this signature in database
3 changed files with 56 additions and 47 deletions

View File

@ -97,4 +97,6 @@ def _(proc: CSIMatrix) -> None:
cnt += 1 cnt += 1
if __name__ == "__main__":
print("Starting app")
app.start() app.start()

View File

@ -166,9 +166,11 @@ class CSIApplication:
self.raw_csi_callback(sample.matrix) self.raw_csi_callback(sample.matrix)
if self.pre_merge_callback is not None: if self.pre_merge_callback is not None:
self.pre_merge_callback(sample.frames) self.pre_merge_callback(sample.frames)
processed = self.preprocessor.preprocess(sample.matrix, sample.frames) processed = self.preprocessor.preprocess(
if self.visualise_raw: sample.matrix, sample.frames, visualiser=self.visualise_data
self.visualise_data(processed, visualise.figures.Figure.PROCESSED_CSI) )
# if self.visualise_raw:
# self.visualise_data(processed, visualise.figures.Figure.PROCESSED_CSI)
if self.preprocessed_csi_callback is not None: if self.preprocessed_csi_callback is not None:
self.preprocessed_csi_callback(processed) self.preprocessed_csi_callback(processed)
@ -197,10 +199,13 @@ class CSIApplication:
self.buffer_thread.start() self.buffer_thread.start()
self.webapp_thread.start() self.webapp_thread.start()
if self.processing_callback is not None:
def get_proc_sample() -> None: def get_proc_sample() -> None:
sample = self.preprocessor.last_sample sample = self.preprocessor.last_sample
if self.visualise_raw and sample is not None:
self.visualise_data(
sample,
visualise.figures.Figure.PROCESSED_CSI,
)
if sample is not None and self.processing_callback is not None: if sample is not None and self.processing_callback is not None:
self.processing_callback(sample) self.processing_callback(sample)
else: else:
@ -208,6 +213,7 @@ class CSIApplication:
self.scheduler = Scheduler(config.processing_sample_rate, get_proc_sample) self.scheduler = Scheduler(config.processing_sample_rate, get_proc_sample)
self.scheduler.start() self.scheduler.start()
try: try:
self.webapp_thread.join() self.webapp_thread.join()
except KeyboardInterrupt: except KeyboardInterrupt:

View File

@ -1,4 +1,6 @@
import importlib.util
import logging import logging
from pathlib import Path
from queue import Queue from queue import Queue
from typing import cast from typing import cast
@ -7,11 +9,11 @@ import numpy.typing as npt
import torch import torch
import typer import typer
from where_fi.application import CSIApplication
from where_fi.collection import CSIMatrix from where_fi.collection import CSIMatrix
from where_fi.config import config
from where_fi.processing.aoa import AoA
from ..application import CSIApplication
from ..config import config
from ..processing.aoa import AoA
from ..visualise import server as visualise from ..visualise import server as visualise
from . import file, globals from . import file, globals
@ -53,44 +55,43 @@ def heatmap() -> None:
@cli.command() @cli.command()
def phase_analysis( def run(file: Path, app_name: str = "app") -> None:
subcarriers: list[int] = [0], rx_antenna: int = 0, tx_antenna: int = 0
) -> None:
""" """
Visualise the phase information in the CSI data received from the antennas. Run the application with the given file.
The data goes through the same preprocessing steps as the heatmap command, but Can be used for running arbitrary CSI applications with non-default data streams
instead of going through the AoA estimation, we simply analyse the phase of the (e.g. from file or environment simulation).
selected subcarrier and antenna.
""" """
print(file.absolute())
if not file.exists():
print(f"Error: File '{file}' does not exist.")
raise typer.Exit(1)
module_name = file.stem
app = CSIApplication(globals.csi_producer) spec = importlib.util.spec_from_file_location(module_name, str(file))
if spec is None:
print(f"Could not load spec from {file}")
raise typer.Exit(1)
if isinstance(subcarriers, int): module = importlib.util.module_from_spec(spec)
subcarriers = [subcarriers] if spec.loader is None:
print("Starting phase analysis on subcarriers: ", subcarriers) print(f"Could not load module from {file}")
raise typer.Exit(1)
try:
spec.loader.exec_module(module)
except Exception as e:
print(f"Failed to execute {file}: {e}")
raise typer.Exit(1) from e
subcarrier_phase: dict[int, Queue[float]] = { if not hasattr(module, app_name):
x: Queue(config.collection_sample_rate) for x in subcarriers print(f"Error: '{app_name}' not defined in the module.")
} raise typer.Exit(1)
if not isinstance(module.app, CSIApplication):
print(f"Error: '{app_name}' is not a CSIApplication.")
raise typer.Exit(1)
@app.on_sample module.app.producer = globals.csi_producer
def _(sample: CSIMatrix) -> None: module.app.start()
for subcarrier in subcarriers:
phase = cast(float, np.angle(sample[subcarrier, rx_antenna, tx_antenna]))
if subcarrier_phase[subcarrier].full():
subcarrier_phase[subcarrier].get()
subcarrier_phase[subcarrier].put(phase)
@app.on_process
def _(_: CSIMatrix) -> None:
logger.info("Updating phase visualisation")
app.visualise_data(
np.array([x.queue for x in subcarrier_phase.values()]),
visualise.figures.Figure.PHASE_ANALYSIS,
)
app.start()
cli.add_typer(file.app, name="file", help="Commands for working with CSI files") cli.add_typer(file.app, name="file", help="Commands for working with CSI files")