add data denoising

This commit is contained in:
Christos Falas 2025-05-14 16:54:18 +01:00
parent af9faa3d07
commit d15b82f031
No known key found for this signature in database
3 changed files with 48 additions and 4 deletions

View File

@ -43,8 +43,8 @@ class CSIHeader:
self.num_rx = data[46] self.num_rx = data[46]
self.num_tx = data[47] self.num_tx = data[47]
self.num_subcarriers = struct.unpack("I", data[52:56])[0] self.num_subcarriers = struct.unpack("I", data[52:56])[0]
self.rssi1 = struct.unpack("I", data[60:64])[0] self.rssi1: int = struct.unpack("I", data[60:64])[0]
self.rssi2 = struct.unpack("I", data[64:68])[0] self.rssi2: int = struct.unpack("I", data[64:68])[0]
self.source_mac = struct.unpack("BBBBBB", data[68:74]) self.source_mac = struct.unpack("BBBBBB", data[68:74])
self.source_mac_string = "%02x:%02x:%02x:%02x:%02x:%02x" % struct.unpack( self.source_mac_string = "%02x:%02x:%02x:%02x:%02x:%02x" % struct.unpack(
"BBBBBB", data[68:74] "BBBBBB", data[68:74]

View File

@ -18,6 +18,8 @@ class Preprocessing(BaseModel):
bandpass: Bandpass bandpass: Bandpass
subcarrier_step: int subcarrier_step: int
denoising: Literal["none", "median", "mean"] = "median"
denoising_period: float = 1
class MUSIC(BaseModel): class MUSIC(BaseModel):
@ -36,6 +38,10 @@ class Antennas(BaseModel):
spacing: float spacing: float
order: list[tuple[Host, int]] order: list[tuple[Host, int]]
@property
def count(self) -> int:
return len(self.order)
class Config(BaseModel): class Config(BaseModel):
receive_hosts: list[Host] receive_hosts: list[Host]
@ -66,6 +72,10 @@ class Config(BaseModel):
return "6" return "6"
raise ValueError(f"{self.central_freq} is not a valid Wi-Fi channel") raise ValueError(f"{self.central_freq} is not a valid Wi-Fi channel")
@property
def subcarriers(self) -> int:
return int((self.channel_width * 1e6) // self.delta_f) - 8
@property @property
def delta_f(self) -> int: def delta_f(self) -> int:
if self.frame_format == "HESU": if self.frame_format == "HESU":

View File

@ -7,8 +7,10 @@ import numpy.typing as npt
from scipy.signal import butter, correlate, sosfilt, sosfilt_zi from scipy.signal import butter, correlate, sosfilt, sosfilt_zi
from where_fi.collection import CSIMatrix from where_fi.collection import CSIMatrix
from where_fi.collection.csi_frame import CSI
from where_fi.collection.protocols import CSIHost
from where_fi.config import config
from ..config import config
from ..visualise import server as visualise from ..visualise import server as visualise
logger = logging.getLogger(__name__) logger = logging.getLogger(__name__)
@ -28,13 +30,41 @@ class Preprocessor:
# output="sos", # output="sos",
# ) # )
self._last_sample = None self._last_sample = None
self.denoising_samples = int(
config.preprocessing.denoising_period * config.collection_sample_rate
)
self.circular_buffer = np.zeros(
(
self.denoising_samples, # Number of samples
config.subcarriers, # Number of subcarriers
config.antennas.count, # Number of RX antennas
1, # Number of TX antennas
),
dtype=np.complex64,
)
self.sample_index = 0
@property @property
def last_sample(self) -> None | CSIMatrix: def last_sample(self) -> None | CSIMatrix:
""" """
The last sample of the preprocessor. This is used for low frequency processing The last sample of the preprocessor. This is used for low frequency processing
""" """
match config.preprocessing.denoising:
case "none":
return self._last_sample return self._last_sample
case "median":
# Return the median of the last samples
median_abs = np.median(np.abs(self.circular_buffer), axis=0)
median_angle = np.median(np.angle(self.circular_buffer), axis=0)
ans = median_abs * np.exp(1j * median_angle)
return ans
case "mean":
# Return the mean of the last samples
return np.mean(self.circular_buffer, axis=0)
case _:
raise ValueError(
f"Invalid denoising method: {config.preprocessing.denoising}"
)
def remove_sto(self, csi: CSIMatrix) -> CSIMatrix: def remove_sto(self, csi: CSIMatrix) -> CSIMatrix:
""" """
@ -134,6 +164,10 @@ class Preprocessor:
# h_hat -= self.long_term_avg # h_hat -= self.long_term_avg
self._last_sample = h_hat self._last_sample = h_hat
if config.preprocessing.denoising != "none":
self.circular_buffer[self.sample_index] = h_hat
self.sample_index = (self.sample_index + 1) % self.denoising_samples
return h_hat return h_hat
# Apply bandpass filter to remove low and high frequency noise # Apply bandpass filter to remove low and high frequency noise