Compare commits
No commits in common. "1bc44ae43a34b52b099599e169b83b673e879df0" and "15557bc6716551c051293ed97cc68999c39dd19a" have entirely different histories.
1bc44ae43a
...
15557bc671
@ -50,8 +50,8 @@ def heatmap() -> None:
|
|||||||
def callback(antenna_data: npt.NDArray[np.complex64]) -> None:
|
def callback(antenna_data: npt.NDArray[np.complex64]) -> None:
|
||||||
logger.info(f"Got final CSI data with shape {antenna_data.shape}")
|
logger.info(f"Got final CSI data with shape {antenna_data.shape}")
|
||||||
processed = preprocessor.preprocess(antenna_data)
|
processed = preprocessor.preprocess(antenna_data)
|
||||||
logger.info(f"Processed CSI data with shape {processed.shape}")
|
|
||||||
processed_tensor = torch.tensor(processed, device=device)
|
processed_tensor = torch.tensor(processed, device=device)
|
||||||
|
# visualise.add_data(all_data, processed)
|
||||||
aoa.update(processed_tensor)
|
aoa.update(processed_tensor)
|
||||||
|
|
||||||
if not webapp_queue.full():
|
if not webapp_queue.full():
|
||||||
|
|||||||
@ -52,7 +52,6 @@ class AoA:
|
|||||||
def update(self, data: torch.Tensor) -> None:
|
def update(self, data: torch.Tensor) -> None:
|
||||||
self.timestamp = datetime.now()
|
self.timestamp = datetime.now()
|
||||||
H_sm = self.smooth(data)
|
H_sm = self.smooth(data)
|
||||||
logger.debug(f"Calculated smoothed CSI matrix: {H_sm.shape}")
|
|
||||||
|
|
||||||
auto_corr = H_sm @ torch.conj(H_sm).T
|
auto_corr = H_sm @ torch.conj(H_sm).T
|
||||||
# This matrix is by definition Hermitian.
|
# This matrix is by definition Hermitian.
|
||||||
@ -69,8 +68,6 @@ class AoA:
|
|||||||
if self.historical_autocorr.shape[0] > WINDOW_SIZE:
|
if self.historical_autocorr.shape[0] > WINDOW_SIZE:
|
||||||
self.historical_autocorr = self.historical_autocorr[-WINDOW_SIZE:]
|
self.historical_autocorr = self.historical_autocorr[-WINDOW_SIZE:]
|
||||||
|
|
||||||
logger.debug("Finished updating autocorrelation matrix")
|
|
||||||
|
|
||||||
def steering_vector(self, theta: torch.Tensor, tof: torch.Tensor) -> torch.Tensor:
|
def steering_vector(self, theta: torch.Tensor, tof: torch.Tensor) -> torch.Tensor:
|
||||||
assert theta.shape == tof.shape
|
assert theta.shape == tof.shape
|
||||||
assert len(theta.shape) == 1
|
assert len(theta.shape) == 1
|
||||||
@ -86,6 +83,7 @@ class AoA:
|
|||||||
/ 299_792_458
|
/ 299_792_458
|
||||||
)
|
)
|
||||||
assert omega_t.shape == phi_theta.shape == (N,)
|
assert omega_t.shape == phi_theta.shape == (N,)
|
||||||
|
print(omega_t, phi_theta)
|
||||||
|
|
||||||
omega_t = torch.unsqueeze(omega_t, dim=-1)
|
omega_t = torch.unsqueeze(omega_t, dim=-1)
|
||||||
phi_theta = torch.unsqueeze(phi_theta, dim=-1)
|
phi_theta = torch.unsqueeze(phi_theta, dim=-1)
|
||||||
@ -113,29 +111,26 @@ class AoA:
|
|||||||
|
|
||||||
def evaluate(self, theta: torch.Tensor, tof: torch.Tensor) -> torch.Tensor:
|
def evaluate(self, theta: torch.Tensor, tof: torch.Tensor) -> torch.Tensor:
|
||||||
R = torch.mean(self.historical_autocorr, dim=0)
|
R = torch.mean(self.historical_autocorr, dim=0)
|
||||||
assert (R == torch.conj(R).T).all()
|
|
||||||
|
|
||||||
# The smallest eigenvectors span the noise subspace,
|
# The smallest eigenvectors span the noise subspace,
|
||||||
# and the largest span the signal subspace.
|
# and the largest span the signal subspace.
|
||||||
logger.debug(f"Calculating eigenvectors of R: {R.shape}")
|
eigvals, eigvecs = torch.linalg.eig(R)
|
||||||
eigvals, eigvecs = torch.linalg.eigh(R)
|
|
||||||
assert isinstance(eigvals, torch.Tensor)
|
assert isinstance(eigvals, torch.Tensor)
|
||||||
assert isinstance(eigvecs, torch.Tensor)
|
assert isinstance(eigvecs, torch.Tensor)
|
||||||
logger.info(f"Eigenvalues: {eigvals}")
|
logger.info(f"Eigenvalues: {eigvals}")
|
||||||
E_n = eigvecs[:, torch.abs(eigvals) < config.music.eigval_threshold]
|
E_n = eigvecs[:, torch.abs(eigvals) < config.music.eigval_threshold]
|
||||||
|
|
||||||
logger.debug(f"Signal subspace: {E_n.shape}")
|
logger.info(f"Signal subspace: {E_n.shape}")
|
||||||
steering = torch.unsqueeze(self.steering_vector(theta, tof), dim=-1)
|
steering = torch.unsqueeze(self.steering_vector(theta, tof), dim=-1)
|
||||||
steering_h = torch.conj(steering).permute(0, 2, 1)
|
steering_h = torch.conj(steering).permute(0, 2, 1)
|
||||||
|
|
||||||
E_n = E_n.unsqueeze(0)
|
E_n = E_n.unsqueeze(0)
|
||||||
E_n_H = torch.conj(E_n).permute(0, 2, 1)
|
E_n_H = torch.conj(E_n).permute(0, 2, 1)
|
||||||
logger.debug(
|
logger.info(
|
||||||
f"Heatmap multiplication: {steering_h.shape}, {E_n.shape}, "
|
f"Heatmap multiplication: {steering_h.shape}, {E_n.shape}, {E_n_H.shape}, {steering.shape}"
|
||||||
f"{E_n_H.shape}, {steering.shape}"
|
|
||||||
)
|
)
|
||||||
c: torch.Tensor = 1 / (steering_h @ E_n @ E_n_H @ steering)
|
c: torch.Tensor = 1 / (0.001 + (steering_h @ E_n @ E_n_H @ steering))
|
||||||
return torch.abs(c)[:, 0, 0]
|
return torch.abs(c.real)
|
||||||
|
|
||||||
def heatmap(self) -> npt.NDArray[np.float32]:
|
def heatmap(self) -> npt.NDArray[np.float32]:
|
||||||
thetas = np.linspace(
|
thetas = np.linspace(
|
||||||
@ -148,18 +143,17 @@ class AoA:
|
|||||||
dtype=np.float32,
|
dtype=np.float32,
|
||||||
)
|
)
|
||||||
thetas_mesh, tofs_mesh = np.meshgrid(thetas, tofs)
|
thetas_mesh, tofs_mesh = np.meshgrid(thetas, tofs)
|
||||||
logger.debug(
|
heatmap: npt.NDArray[np.float32] = (
|
||||||
f"Calculating heatmap with {thetas_mesh.shape} and {tofs_mesh.shape}"
|
self.evaluate(
|
||||||
|
torch.tensor(thetas_mesh.reshape(-1)),
|
||||||
|
torch.tensor(tofs_mesh.reshape(-1)),
|
||||||
|
)
|
||||||
|
.reshape(
|
||||||
|
config.music.heatmap.theta_resolution,
|
||||||
|
config.music.heatmap.tof_resolution,
|
||||||
|
)
|
||||||
|
.numpy(force=True)
|
||||||
)
|
)
|
||||||
evaluated = self.evaluate(
|
|
||||||
torch.tensor(thetas_mesh.reshape(-1)),
|
|
||||||
torch.tensor(tofs_mesh.reshape(-1)),
|
|
||||||
)
|
|
||||||
logger.debug(f"Evaluated heatmap: {evaluated.shape}")
|
|
||||||
heatmap: npt.NDArray[np.float32] = evaluated.reshape(
|
|
||||||
config.music.heatmap.tof_resolution,
|
|
||||||
config.music.heatmap.theta_resolution,
|
|
||||||
).numpy(force=True)
|
|
||||||
return heatmap
|
return heatmap
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@ -95,15 +95,14 @@ def add_data(
|
|||||||
def plot_heatmap(heatmap: npt.NDArray[np.float32]) -> io.BytesIO:
|
def plot_heatmap(heatmap: npt.NDArray[np.float32]) -> io.BytesIO:
|
||||||
logger.info(f"Making heatmap with aoa of {aoa.timestamp}")
|
logger.info(f"Making heatmap with aoa of {aoa.timestamp}")
|
||||||
fig = plt.figure()
|
fig = plt.figure()
|
||||||
ax = fig.add_axes([0.1, 0.1, 0.9, 0.9]) # , polar=True)
|
ax = fig.add_axes([0, 0, 1, 1], polar=True)
|
||||||
r = np.linspace(
|
r = np.linspace(
|
||||||
0, config.music.heatmap.tof_max, config.music.heatmap.tof_resolution
|
0, config.music.heatmap.tof_max, config.music.heatmap.tof_resolution
|
||||||
)
|
)
|
||||||
theta = np.linspace(0, np.pi, config.music.heatmap.theta_resolution) # Angle values
|
theta = np.linspace(0, np.pi, config.music.heatmap.theta_resolution) # Angle values
|
||||||
|
X, Y = np.meshgrid(r, theta) # Create a 2D grid of r and theta
|
||||||
|
|
||||||
mesh = ax.pcolormesh(theta, r, heatmap, edgecolors="face", vmin=0, vmax=50)
|
ax.pcolormesh(Y, X, heatmap, edgecolors="face")
|
||||||
|
|
||||||
fig.colorbar(mesh, ax=ax)
|
|
||||||
buf = io.BytesIO()
|
buf = io.BytesIO()
|
||||||
fig.savefig(buf, format="jpeg")
|
fig.savefig(buf, format="jpeg")
|
||||||
plt.close(fig)
|
plt.close(fig)
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user