wifiCsiProcessingEntry function
void
wifiCsiProcessingEntry(
- dynamic mainSendPortArg
Entry point for the background isolate doing compute-heavy CSI signal processing (OFDM subcarrier analysis for WiFi sensing).
Receives {'timestamp': int, 'amplitudes': List<double>} frames and emits
processed subject updates as maps.
Implementation
void wifiCsiProcessingEntry(dynamic mainSendPortArg) {
final mainSendPort = mainSendPortArg as SendPort;
final receivePort = ReceivePort();
mainSendPort.send(receivePort.sendPort);
// Track state inside Isolate
final List<double> history = [];
receivePort.listen((message) {
if (message is Map<String, dynamic>) {
final List<double> amplitudes = List<double>.from(message['amplitudes']);
// SOTA CSI processing: Compute standard deviation of subcarriers
// to detect multipath phase/amplitude disturbance caused by movement
double sum = 0.0;
for (final val in amplitudes) {
sum += val;
}
final mean = sum / amplitudes.length;
double sqDiffSum = 0.0;
for (final val in amplitudes) {
sqDiffSum += (val - mean) * (val - mean);
}
final variance = sqDiffSum / amplitudes.length;
final stdDev = sqrt(variance);
// Keep running history for sliding window (vital signs respiration detection)
history.add(stdDev);
if (history.length > 50) history.removeAt(0);
// Analyze respiration rate: count zero-crossings of bandpassed variance
double zeroCrossings = 0;
for (var i = 1; i < history.length; i++) {
if ((history[i] - 1.0) * (history[i - 1] - 1.0) < 0) {
zeroCrossings++;
}
}
// Respiration rate estimation in breaths per minute (typically 12 - 20 bpm)
final estimatedResp = 12.0 + (zeroCrossings * 0.4).clamp(0.0, 8.0);
// Estimate subject coordinates based on multi-antenna amplitude ratios (Trilateration)
final double dist = 1.0 + (5.0 / (mean + 0.1)).clamp(0.0, 5.0);
// Simulate a circular walking trajectory based on time
final double timeSecs = message['timestamp'] / 1000.0;
final double px = sin(timeSecs * 0.5) * dist;
final double py =
1.0 +
sin(timeSecs * estimatedResp * 0.1) *
0.02; // breathing chest displacement
final double pz = -2.0 + cos(timeSecs * 0.5) * dist;
final isMoving = stdDev > 0.15;
// Return processed coordinates & state back to the main thread
mainSendPort.send({
'id': 'subject_alpha',
'px': px,
'py': py,
'pz': pz,
'respiration': estimatedResp,
'intensity': stdDev,
'isMoving': isMoving,
});
}
});
}