Plot multiple foxes

This commit is contained in:
Sassa NF
2025-04-18 19:58:37 +01:00
parent 7f6423bab6
commit 19505d794c

View File

@@ -175,24 +175,62 @@
}
let lineCoef = 2.5;
var minf = -1, maxf = -1;
dataPoints.forEach(({ spectrum }) => {
if (!spectrum) return;
spectrum.forEach(({ F }) => {
if (minf < 0 || minf > F) minf = F;
maxf = Math.max(maxf, F);
});
});
// Draw data points
dataPoints.forEach(({ angle, rssi }) => {
dataPoints.forEach(({ angle, rssi, t0, spectrum }) => {
if (!currentPoint.spectrum || !spectrum) return;
const rad = (angle * Math.PI) / 180;
//const length = (120 + rssi) / (radius / 2) * radius;
var length = ((120 - 90) + (rssi + 90)) * lineCoef; // Scale RSSI to fit within radar
if (length > radius) {
length = radius;
}
//console.log("Length: " + length);
const x = centerX + length * Math.sin(rad + angleOffset);
const y = centerY - length * Math.cos(rad + angleOffset);
if (minf == maxf) {
const length = Math.max(radius - 10, ((120 - 90) + (rssi + 90)) * lineCoef); // Scale RSSI to fit within radar
ctx.beginPath();
ctx.moveTo(centerX, centerY);
ctx.lineTo(x, y);
ctx.strokeStyle = "red";
ctx.lineWidth = 2;
ctx.stroke();
//console.log("Length: " + length);
const x = centerX + length * Math.sin(rad + angleOffset);
const y = centerY - length * Math.cos(rad + angleOffset);
ctx.beginPath();
ctx.moveTo(centerX, centerY);
ctx.lineTo(x, y);
// calculating linear decay factor:
// for 5000 < dt < 45000 - linear decay from 1.0 to 0.5
// for dt outside those - flat 1.0, or flat 0.5
const colorDecay = 1 - Math.min(Math.max((currentPoint.t0 - t0 - 5000) / (2 * 40000), 0), 0.5);
ctx.strokeStyle = `rgba(${Math.trunc(255 * colorDecay)}, ${Math.trunc((1 - colorDecay) * 255)}, ${Math.trunc((1 - colorDecay) * 255)}, 1)`;
ctx.lineWidth = 2;
ctx.stroke();
} else {
// now, here's radical new view:
// colour: the redder it is, the more recent the reading is
// intensity: the more intense it is, the higher the RSSI
// radius: the distance from centre represents frequency for which the reading was made
// angle: direction
spectrum.forEach(({ F, R }) => {
const length = (F - minf) / (maxf - minf) * (radius - 20 - 10) + 20;
ctx.beginPath();
ctx.arc(centerX, centerY, length, rad + angleOffset - 0.5 * Math.PI / 180 - Math.PI / 2, rad + angleOffset + 0.5 * Math.PI / 180 - Math.PI / 2, false);
// calculating linear decay factor:
// for 5000 < dt < 45000 - linear decay from 1.0 to 0.5
// for dt outside those - flat 1.0, or flat 0.5
const colorDecay = 1 - Math.min(Math.max((currentPoint.t0 - t0 - 5000) / (2 * 40000), 0), 0.5);
const colorIntensity = 1 + Math.max(-1, Math.min(0, R + 20) / (70 - 20));
ctx.strokeStyle = `rgba(${Math.trunc(255 * colorDecay)}, ${Math.trunc((1 - colorDecay) * 255)}, ${Math.trunc((1 - colorDecay) * 255)}, ${colorIntensity})`;
ctx.lineWidth = 5;
ctx.stroke();
});
}
});
const maxPoint = dataPoints.reduce((max, point) => (point.rssi > max.rssi ? point : max), { angle: 0, rssi: -120 });
@@ -351,12 +389,40 @@
document.body.appendChild(promptDiv);
}
function simulateRssi(fox) {
if (fox > 35) {
return -90;
function angleDiff(a, b) {
a = (a + 360) % 360;
b = (b + 360) % 360;
if (b < a) {
a += b;
b = a - b;
a -= b;
}
return Math.cos((Math.PI / 2) * fox / 35) * 40 - Math.random() * 3 - 90;
return b - a > 180 ? a + 360 - b : b - a;
}
function simulateRssi(foxes, h_angle) {
const rssis = foxes.map(({ angle, f_mhz, rssi }, i) => {
const fox = angleDiff(angle, h_angle);
return {
f_mhz: f_mhz,
rssi: Math.max(-90, (fox > 35 ? 0 : Math.cos((Math.PI / 2) * fox / 35) * (rssi + 90)) - Math.random() * 3 - 90)
};
});
rssis.sort((a, b) => a.f_mhz - b.f_mhz);
return rssis.reduce((v, fox) => {
if (v.length == 0 || v[v.length - 1].f_mhz != fox.f_mhz) {
v.push(fox);
return v;
}
const prev = v[v.length - 1];
prev.rssi = Math.log(Math.exp(prev.rssi) + Math.exp(fox.rssi));
return v;
}, []);
}
// Parse Bluetooth data
@@ -392,8 +458,9 @@
const heading = ((headingMax + headingMin + 720 + (headingMax - headingMin > 180 ? 360 : 0)) / 2) % 360;
const rssi = spectrum[0]["R"];
dataPoints[Math.trunc(heading)] = { angle: heading, rssi: rssi };
currentPoint = { angle: heading, rssi: rssi };
const t0 = Date.now();
dataPoints[Math.trunc(heading)] = { angle: heading, rssi: rssi, t0: t0, spectrum: spectrum };
currentPoint = { angle: heading, rssi: rssi, t0: t0, spectrum: spectrum };
//if (dataPoints.length > 50) dataPoints.shift(); // Keep only the last 50 points
headingDisplay.textContent = `${heading.toFixed(1)}°`;
rssiDisplay.textContent = `${rssi.toFixed(1)} dBm`;
@@ -446,15 +513,27 @@
dataPoints[i] = { angle: i, rssi: -120 };
}
(function simulate(fox, prevAngle, prevRssi) {
const foxes = [
{ angle: Math.random() * 360, f_mhz: 240, rssi: -60 },
{ angle: Math.random() * 360, f_mhz: 320, rssi: -45 },
{ angle: Math.random() * 360, f_mhz: 120, rssi: -20 },
{ angle: Math.random() * 360, f_mhz: 120, rssi: -35 }
];
(function simulate(foxes, prevAngle, prevRssi) {
if (!isSimulating) return;
const angle = (prevAngle - 3 + Math.random() * 7.5) % 360; // bias slightly to scan on
const rssi = simulateRssi(Math.abs(angle - fox));
const spectrum = simulateRssi(foxes, angle);
const data = "RSSI_HEADING: '{H:" + angle + ",RSSI:" + rssi + "}'"
const data = spectrum.length == 1 ? "RSSI_HEADING: '{H:" + angle + ",RSSI:" + spectrum[0].rssi + "}'" : JSON.stringify({
SCAN_RESULT: {
Hmin: Math.min(prevAngle, angle),
Hmax: Math.max(prevAngle, angle),
Spectrum: spectrum.map(({ f_mhz, rssi }) => ({ F: f_mhz, R: rssi }))
}
});
parseBTData(data); // test actual BT data processing
setTimeout(simulate, 100, fox, angle, rssi);
})(Math.random() * 360, Math.random() * 360, -70 + Math.random() * 30);
setTimeout(simulate, 100, foxes, angle, rssi);
})(foxes, Math.random() * 360, -70 + Math.random() * 30);
}
});