Add heatmap visualisation

This commit is contained in:
Christos Falas 2025-02-24 14:55:22 +00:00
parent a94a9b4ec4
commit 61be734752
No known key found for this signature in database
5 changed files with 56 additions and 22 deletions

View File

@ -52,7 +52,7 @@ 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}")
visualise_data(antenna_data, visualise.DataType.RAW_CSI) visualise_data(antenna_data, visualise.DataType.RAW_CSI)
processed = preprocessor.preprocess(antenna_data) processed = preprocessor.preprocess(antenna_data, visualiser=visualise_data)
visualise_data(processed, visualise.DataType.PROCESSED_CSI) visualise_data(processed, visualise.DataType.PROCESSED_CSI)
logger.info(f"Processed CSI data with shape {processed.shape}") logger.info(f"Processed CSI data with shape {processed.shape}")
processed_tensor = torch.tensor(processed, device=device) processed_tensor = torch.tensor(processed, device=device)

View File

@ -6,4 +6,5 @@ server/generated: protos/*.proto
find protos/ -type f -name "*.proto" | xargs uv run protol --create-package --in-place --python-out server/generated/ protoc --proto-path=protos/ find protos/ -type f -name "*.proto" | xargs uv run protol --create-package --in-place --python-out server/generated/ protoc --proto-path=protos/
frontend/src/grpc: protos/*.proto frontend/src/grpc: protos/*.proto
find protos/ -name "*.proto" | xargs npm exec --prefix frontend/ protoc --ts_out frontend/src/grpc -I protos/ mkdir -p frontend/src/grpc
cd frontend && find ../protos/ -name "*.proto" | xargs npx protoc --ts_out=src/grpc -I../protos/

View File

@ -11,6 +11,18 @@ import { computed } from 'vue'
const { figure, paused = false } = defineProps<{ figure: Figure; paused?: boolean }>() const { figure, paused = false } = defineProps<{ figure: Figure; paused?: boolean }>()
const cancel = ref<boolean>(false) const cancel = ref<boolean>(false)
function reshape(data: number[], width: number) {
if (data.length % width != 0) {
throw new Error('Data length is not divisible by width')
}
const height = data.length / width
const result: number[][] = new Array(height)
for (let i = 0; i < height; i++) {
result[i] = data.slice(i * width, (i + 1) * width)
}
return result
}
const data = ref<FigureData | null>(null) const data = ref<FigureData | null>(null)
const plotData = computed(() => { const plotData = computed(() => {
if (data.value) { if (data.value) {
@ -24,16 +36,12 @@ const plotData = computed(() => {
color: line.color ? line.color : undefined, color: line.color ? line.color : undefined,
})) }))
case 'heatmap': case 'heatmap':
return [] return [
/* data.value.figure.heatmap.lines.map((line) => { {
return { z: reshape(data.value.figure.heatmap.data, data.value.figure.heatmap.width),
x: line.x, type: 'heatmap' as const,
y: line.y, },
type: 'scatter', ]
name: line.label,
color: line.color,
}
})*/
} }
} }
return [] return []
@ -43,6 +51,7 @@ const layout = {
title: { text: figure.title }, title: { text: figure.title },
xaxis: { title: { text: figure.xLabel } }, xaxis: { title: { text: figure.xLabel } },
yaxis: { title: { text: figure.yLabel } }, yaxis: { title: { text: figure.yLabel } },
height: 700,
} }
function updateGraph() { function updateGraph() {

View File

@ -2,9 +2,8 @@ syntax = "proto3";
message HeatmapData { message HeatmapData {
string uuid = 1; string uuid = 1;
repeated float x = 2; repeated float data = 2;
repeated float y = 3; uint32 width = 3;
uint32 width = 4; uint32 height = 4;
uint32 height = 5; string cmap = 5;
string cmap = 6;
} }

View File

@ -23,8 +23,9 @@ clients_lock = threading.Lock()
class DataType(Enum): class DataType(Enum):
RAW_CSI = 1 RAW_CSI = 1
PROCESSED_CSI = 2 UNWRAPPED_PHASE = 2
HEATMAP = 3 PROCESSED_CSI = 3
HEATMAP = 4
@dataclass @dataclass
@ -40,6 +41,12 @@ figures = {
x_label="Subcarrier", x_label="Subcarrier",
y_label="Phase", y_label="Phase",
), ),
"unwrapped_phase": figure_pb2.Figure(
uuid=str(uuid.uuid4()),
title="Unwrapped CSI Phase",
x_label="Subcarrier",
y_label="Unwrapped phase",
),
"processed_phase": figure_pb2.Figure( "processed_phase": figure_pb2.Figure(
uuid=str(uuid.uuid4()), uuid=str(uuid.uuid4()),
title="Preprocessed CSI Phase", title="Preprocessed CSI Phase",
@ -48,9 +55,9 @@ figures = {
), ),
"aoa_heatmap": figure_pb2.Figure( "aoa_heatmap": figure_pb2.Figure(
uuid=str(uuid.uuid4()), uuid=str(uuid.uuid4()),
title="Preprocessed CSI Phase", title="AoA Heatmap",
x_label="Subcarrier", x_label="ToF",
y_label="Phase", y_label="AoA",
), ),
} }
@ -104,7 +111,25 @@ def add_data(dtype: DataType, new_data: npt.NDArray[np.complex128]) -> None:
for q in clients.get(uuid, []): for q in clients.get(uuid, []):
q.put(figure_pb2.FigureData(uuid=uuid, line=linechart)) q.put(figure_pb2.FigureData(uuid=uuid, line=linechart))
case DataType.HEATMAP: case DataType.HEATMAP:
uuid = figures["aoa_heatmap"].uuid
heatmap = heatmap_pb2.HeatmapData(
uuid=uuid,
data=new_data.flatten(),
width=new_data.shape[1],
height=new_data.shape[0],
)
for q in clients.get(uuid, []):
q.put(figure_pb2.FigureData(uuid=uuid, heatmap=heatmap))
pass pass
case DataType.UNWRAPPED_PHASE:
uuid = figures["unwrapped_phase"].uuid
lines = [
line_pb2.LineChartData.Line(y=new_data[:, i, 0], label=f"Antenna {i}")
for i in range(new_data.shape[1])
]
linechart = line_pb2.LineChartData(lines=lines)
for q in clients.get(uuid, []):
q.put(figure_pb2.FigureData(uuid=uuid, line=linechart))
def listen_for_data(data_queue: "mp.Queue[VisualiserData]") -> None: def listen_for_data(data_queue: "mp.Queue[VisualiserData]") -> None: