mirror of
https://github.com/Genaker/LoraSA.git
synced 2026-03-28 17:42:59 +01:00
Plot multiple foxes
This commit is contained in:
@@ -175,24 +175,62 @@
|
|||||||
}
|
}
|
||||||
|
|
||||||
let lineCoef = 2.5;
|
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
|
// 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 rad = (angle * Math.PI) / 180;
|
||||||
//const length = (120 + rssi) / (radius / 2) * radius;
|
//const length = (120 + rssi) / (radius / 2) * radius;
|
||||||
var length = ((120 - 90) + (rssi + 90)) * lineCoef; // Scale RSSI to fit within radar
|
if (minf == maxf) {
|
||||||
if (length > radius) {
|
const length = Math.max(radius - 10, ((120 - 90) + (rssi + 90)) * lineCoef); // Scale RSSI to fit within radar
|
||||||
length = radius;
|
|
||||||
}
|
|
||||||
//console.log("Length: " + length);
|
|
||||||
const x = centerX + length * Math.sin(rad + angleOffset);
|
|
||||||
const y = centerY - length * Math.cos(rad + angleOffset);
|
|
||||||
|
|
||||||
ctx.beginPath();
|
//console.log("Length: " + length);
|
||||||
ctx.moveTo(centerX, centerY);
|
const x = centerX + length * Math.sin(rad + angleOffset);
|
||||||
ctx.lineTo(x, y);
|
const y = centerY - length * Math.cos(rad + angleOffset);
|
||||||
ctx.strokeStyle = "red";
|
|
||||||
ctx.lineWidth = 2;
|
ctx.beginPath();
|
||||||
ctx.stroke();
|
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 });
|
const maxPoint = dataPoints.reduce((max, point) => (point.rssi > max.rssi ? point : max), { angle: 0, rssi: -120 });
|
||||||
@@ -351,12 +389,40 @@
|
|||||||
document.body.appendChild(promptDiv);
|
document.body.appendChild(promptDiv);
|
||||||
}
|
}
|
||||||
|
|
||||||
function simulateRssi(fox) {
|
function angleDiff(a, b) {
|
||||||
if (fox > 35) {
|
a = (a + 360) % 360;
|
||||||
return -90;
|
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
|
// Parse Bluetooth data
|
||||||
@@ -392,8 +458,9 @@
|
|||||||
const heading = ((headingMax + headingMin + 720 + (headingMax - headingMin > 180 ? 360 : 0)) / 2) % 360;
|
const heading = ((headingMax + headingMin + 720 + (headingMax - headingMin > 180 ? 360 : 0)) / 2) % 360;
|
||||||
const rssi = spectrum[0]["R"];
|
const rssi = spectrum[0]["R"];
|
||||||
|
|
||||||
dataPoints[Math.trunc(heading)] = { angle: heading, rssi: rssi };
|
const t0 = Date.now();
|
||||||
currentPoint = { angle: heading, rssi: rssi };
|
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
|
//if (dataPoints.length > 50) dataPoints.shift(); // Keep only the last 50 points
|
||||||
headingDisplay.textContent = `${heading.toFixed(1)}°`;
|
headingDisplay.textContent = `${heading.toFixed(1)}°`;
|
||||||
rssiDisplay.textContent = `${rssi.toFixed(1)} dBm`;
|
rssiDisplay.textContent = `${rssi.toFixed(1)} dBm`;
|
||||||
@@ -446,15 +513,27 @@
|
|||||||
dataPoints[i] = { angle: i, rssi: -120 };
|
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;
|
if (!isSimulating) return;
|
||||||
const angle = (prevAngle - 3 + Math.random() * 7.5) % 360; // bias slightly to scan on
|
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
|
parseBTData(data); // test actual BT data processing
|
||||||
setTimeout(simulate, 100, fox, angle, rssi);
|
setTimeout(simulate, 100, foxes, angle, rssi);
|
||||||
})(Math.random() * 360, Math.random() * 360, -70 + Math.random() * 30);
|
})(foxes, Math.random() * 360, -70 + Math.random() * 30);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user