Add WiFi DensePose implementation and results
- Implemented the WiFi DensePose model in PyTorch, including CSI phase processing, modality translation, and DensePose prediction heads. - Added a comprehensive training utility for the model, including loss functions and training steps. - Created a CSV file to document hardware specifications, architecture details, training parameters, performance metrics, and advantages of the model.
This commit is contained in:
384
references/app.js
Normal file
384
references/app.js
Normal file
@@ -0,0 +1,384 @@
|
||||
// WiFi DensePose Application JavaScript
|
||||
|
||||
document.addEventListener('DOMContentLoaded', function() {
|
||||
// Initialize tabs
|
||||
initTabs();
|
||||
|
||||
// Initialize hardware visualization
|
||||
initHardware();
|
||||
|
||||
// Initialize demo simulation
|
||||
initDemo();
|
||||
|
||||
// Initialize architecture interaction
|
||||
initArchitecture();
|
||||
});
|
||||
|
||||
// Tab switching functionality
|
||||
function initTabs() {
|
||||
const tabs = document.querySelectorAll('.nav-tab');
|
||||
const tabContents = document.querySelectorAll('.tab-content');
|
||||
|
||||
tabs.forEach(tab => {
|
||||
tab.addEventListener('click', () => {
|
||||
// Get the tab id
|
||||
const tabId = tab.getAttribute('data-tab');
|
||||
|
||||
// Remove active class from all tabs and contents
|
||||
tabs.forEach(t => t.classList.remove('active'));
|
||||
tabContents.forEach(c => c.classList.remove('active'));
|
||||
|
||||
// Add active class to current tab and content
|
||||
tab.classList.add('active');
|
||||
document.getElementById(tabId).classList.add('active');
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
// Hardware panel functionality
|
||||
function initHardware() {
|
||||
// Antenna interaction
|
||||
const antennas = document.querySelectorAll('.antenna');
|
||||
|
||||
antennas.forEach(antenna => {
|
||||
antenna.addEventListener('click', () => {
|
||||
antenna.classList.toggle('active');
|
||||
updateCSIDisplay();
|
||||
});
|
||||
});
|
||||
|
||||
// Start CSI simulation
|
||||
updateCSIDisplay();
|
||||
setInterval(updateCSIDisplay, 1000);
|
||||
}
|
||||
|
||||
// Update CSI display with random values
|
||||
function updateCSIDisplay() {
|
||||
const activeAntennas = document.querySelectorAll('.antenna.active');
|
||||
const isActive = activeAntennas.length > 0;
|
||||
|
||||
// Only update if at least one antenna is active
|
||||
if (isActive) {
|
||||
const amplitudeFill = document.querySelector('.csi-fill.amplitude');
|
||||
const phaseFill = document.querySelector('.csi-fill.phase');
|
||||
const amplitudeValue = document.querySelector('.csi-row:first-child .csi-value');
|
||||
const phaseValue = document.querySelector('.csi-row:last-child .csi-value');
|
||||
|
||||
// Generate random values
|
||||
const amplitude = (Math.random() * 0.4 + 0.5).toFixed(2); // Between 0.5 and 0.9
|
||||
const phase = (Math.random() * 1.5 + 0.5).toFixed(1); // Between 0.5 and 2.0
|
||||
|
||||
// Update the display
|
||||
amplitudeFill.style.width = `${amplitude * 100}%`;
|
||||
phaseFill.style.width = `${phase * 50}%`;
|
||||
amplitudeValue.textContent = amplitude;
|
||||
phaseValue.textContent = `${phase}π`;
|
||||
}
|
||||
}
|
||||
|
||||
// Demo functionality
|
||||
function initDemo() {
|
||||
const startButton = document.getElementById('startDemo');
|
||||
const stopButton = document.getElementById('stopDemo');
|
||||
const demoStatus = document.getElementById('demoStatus');
|
||||
const signalCanvas = document.getElementById('signalCanvas');
|
||||
const poseCanvas = document.getElementById('poseCanvas');
|
||||
const signalStrength = document.getElementById('signalStrength');
|
||||
const latency = document.getElementById('latency');
|
||||
const personCount = document.getElementById('personCount');
|
||||
const confidence = document.getElementById('confidence');
|
||||
const keypoints = document.getElementById('keypoints');
|
||||
|
||||
let demoRunning = false;
|
||||
let animationFrameId = null;
|
||||
let signalCtx = signalCanvas.getContext('2d');
|
||||
let poseCtx = poseCanvas.getContext('2d');
|
||||
|
||||
// Initialize canvas contexts
|
||||
signalCtx.fillStyle = 'rgba(0, 0, 0, 0.2)';
|
||||
signalCtx.fillRect(0, 0, signalCanvas.width, signalCanvas.height);
|
||||
|
||||
poseCtx.fillStyle = 'rgba(0, 0, 0, 0.2)';
|
||||
poseCtx.fillRect(0, 0, poseCanvas.width, poseCanvas.height);
|
||||
|
||||
// Start demo button
|
||||
startButton.addEventListener('click', () => {
|
||||
if (!demoRunning) {
|
||||
demoRunning = true;
|
||||
startButton.disabled = true;
|
||||
stopButton.disabled = false;
|
||||
demoStatus.textContent = 'Running';
|
||||
demoStatus.className = 'status status--success';
|
||||
|
||||
// Start the animations
|
||||
startSignalAnimation();
|
||||
startPoseAnimation();
|
||||
|
||||
// Update metrics with random values
|
||||
updateDemoMetrics();
|
||||
}
|
||||
});
|
||||
|
||||
// Stop demo button
|
||||
stopButton.addEventListener('click', () => {
|
||||
if (demoRunning) {
|
||||
demoRunning = false;
|
||||
startButton.disabled = false;
|
||||
stopButton.disabled = true;
|
||||
demoStatus.textContent = 'Stopped';
|
||||
demoStatus.className = 'status status--info';
|
||||
|
||||
// Stop the animations
|
||||
if (animationFrameId) {
|
||||
cancelAnimationFrame(animationFrameId);
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
// Signal animation
|
||||
function startSignalAnimation() {
|
||||
let time = 0;
|
||||
const fps = 30;
|
||||
const interval = 1000 / fps;
|
||||
let then = Date.now();
|
||||
|
||||
function animate() {
|
||||
if (!demoRunning) return;
|
||||
|
||||
const now = Date.now();
|
||||
const elapsed = now - then;
|
||||
|
||||
if (elapsed > interval) {
|
||||
then = now - (elapsed % interval);
|
||||
|
||||
// Clear canvas
|
||||
signalCtx.clearRect(0, 0, signalCanvas.width, signalCanvas.height);
|
||||
signalCtx.fillStyle = 'rgba(0, 0, 0, 0.2)';
|
||||
signalCtx.fillRect(0, 0, signalCanvas.width, signalCanvas.height);
|
||||
|
||||
// Draw amplitude signal
|
||||
signalCtx.beginPath();
|
||||
signalCtx.strokeStyle = '#1FB8CD';
|
||||
signalCtx.lineWidth = 2;
|
||||
|
||||
for (let x = 0; x < signalCanvas.width; x++) {
|
||||
const y = signalCanvas.height / 2 +
|
||||
Math.sin(x * 0.05 + time) * 30 +
|
||||
Math.sin(x * 0.02 + time * 1.5) * 15;
|
||||
|
||||
if (x === 0) {
|
||||
signalCtx.moveTo(x, y);
|
||||
} else {
|
||||
signalCtx.lineTo(x, y);
|
||||
}
|
||||
}
|
||||
|
||||
signalCtx.stroke();
|
||||
|
||||
// Draw phase signal
|
||||
signalCtx.beginPath();
|
||||
signalCtx.strokeStyle = '#FFC185';
|
||||
signalCtx.lineWidth = 2;
|
||||
|
||||
for (let x = 0; x < signalCanvas.width; x++) {
|
||||
const y = signalCanvas.height / 2 +
|
||||
Math.cos(x * 0.03 + time * 0.8) * 20 +
|
||||
Math.cos(x * 0.01 + time * 0.5) * 25;
|
||||
|
||||
if (x === 0) {
|
||||
signalCtx.moveTo(x, y);
|
||||
} else {
|
||||
signalCtx.lineTo(x, y);
|
||||
}
|
||||
}
|
||||
|
||||
signalCtx.stroke();
|
||||
|
||||
time += 0.05;
|
||||
}
|
||||
|
||||
animationFrameId = requestAnimationFrame(animate);
|
||||
}
|
||||
|
||||
animate();
|
||||
}
|
||||
|
||||
// Human pose animation
|
||||
function startPoseAnimation() {
|
||||
// Create a human wireframe model with keypoints
|
||||
const keyPoints = [
|
||||
{ x: 200, y: 70 }, // Head
|
||||
{ x: 200, y: 100 }, // Neck
|
||||
{ x: 200, y: 150 }, // Torso
|
||||
{ x: 160, y: 100 }, // Left shoulder
|
||||
{ x: 120, y: 130 }, // Left elbow
|
||||
{ x: 100, y: 160 }, // Left hand
|
||||
{ x: 240, y: 100 }, // Right shoulder
|
||||
{ x: 280, y: 130 }, // Right elbow
|
||||
{ x: 300, y: 160 }, // Right hand
|
||||
{ x: 180, y: 200 }, // Left hip
|
||||
{ x: 170, y: 250 }, // Left knee
|
||||
{ x: 160, y: 290 }, // Left foot
|
||||
{ x: 220, y: 200 }, // Right hip
|
||||
{ x: 230, y: 250 }, // Right knee
|
||||
{ x: 240, y: 290 }, // Right foot
|
||||
];
|
||||
|
||||
// Connections between points
|
||||
const connections = [
|
||||
[0, 1], // Head to neck
|
||||
[1, 2], // Neck to torso
|
||||
[1, 3], // Neck to left shoulder
|
||||
[3, 4], // Left shoulder to left elbow
|
||||
[4, 5], // Left elbow to left hand
|
||||
[1, 6], // Neck to right shoulder
|
||||
[6, 7], // Right shoulder to right elbow
|
||||
[7, 8], // Right elbow to right hand
|
||||
[2, 9], // Torso to left hip
|
||||
[9, 10], // Left hip to left knee
|
||||
[10, 11], // Left knee to left foot
|
||||
[2, 12], // Torso to right hip
|
||||
[12, 13], // Right hip to right knee
|
||||
[13, 14], // Right knee to right foot
|
||||
[9, 12] // Left hip to right hip
|
||||
];
|
||||
|
||||
let time = 0;
|
||||
const fps = 30;
|
||||
const interval = 1000 / fps;
|
||||
let then = Date.now();
|
||||
|
||||
function animate() {
|
||||
if (!demoRunning) return;
|
||||
|
||||
const now = Date.now();
|
||||
const elapsed = now - then;
|
||||
|
||||
if (elapsed > interval) {
|
||||
then = now - (elapsed % interval);
|
||||
|
||||
// Clear canvas
|
||||
poseCtx.clearRect(0, 0, poseCanvas.width, poseCanvas.height);
|
||||
poseCtx.fillStyle = 'rgba(0, 0, 0, 0.2)';
|
||||
poseCtx.fillRect(0, 0, poseCanvas.width, poseCanvas.height);
|
||||
|
||||
// Animate keypoints with subtle movement
|
||||
const animatedPoints = keyPoints.map((point, index) => {
|
||||
// Add subtle movement based on position
|
||||
const xOffset = Math.sin(time + index * 0.2) * 2;
|
||||
const yOffset = Math.cos(time + index * 0.2) * 2;
|
||||
|
||||
return {
|
||||
x: point.x + xOffset,
|
||||
y: point.y + yOffset
|
||||
};
|
||||
});
|
||||
|
||||
// Draw connections (skeleton)
|
||||
poseCtx.strokeStyle = '#1FB8CD';
|
||||
poseCtx.lineWidth = 3;
|
||||
|
||||
connections.forEach(([i, j]) => {
|
||||
poseCtx.beginPath();
|
||||
poseCtx.moveTo(animatedPoints[i].x, animatedPoints[i].y);
|
||||
poseCtx.lineTo(animatedPoints[j].x, animatedPoints[j].y);
|
||||
poseCtx.stroke();
|
||||
});
|
||||
|
||||
// Draw keypoints
|
||||
poseCtx.fillStyle = '#FFC185';
|
||||
|
||||
animatedPoints.forEach(point => {
|
||||
poseCtx.beginPath();
|
||||
poseCtx.arc(point.x, point.y, 5, 0, Math.PI * 2);
|
||||
poseCtx.fill();
|
||||
});
|
||||
|
||||
// Draw body segments (simplified DensePose representation)
|
||||
drawBodySegments(poseCtx, animatedPoints);
|
||||
|
||||
time += 0.05;
|
||||
}
|
||||
|
||||
animationFrameId = requestAnimationFrame(animate);
|
||||
}
|
||||
|
||||
animate();
|
||||
}
|
||||
|
||||
// Draw body segments for DensePose visualization
|
||||
function drawBodySegments(ctx, points) {
|
||||
// Define simplified body segments
|
||||
const segments = [
|
||||
[0, 1, 6, 3], // Head and shoulders
|
||||
[1, 2, 12, 9], // Torso
|
||||
[3, 4, 5, 3], // Left arm
|
||||
[6, 7, 8, 6], // Right arm
|
||||
[9, 10, 11, 9], // Left leg
|
||||
[12, 13, 14, 12] // Right leg
|
||||
];
|
||||
|
||||
ctx.globalAlpha = 0.2;
|
||||
|
||||
segments.forEach((segment, index) => {
|
||||
const gradient = ctx.createLinearGradient(
|
||||
points[segment[0]].x, points[segment[0]].y,
|
||||
points[segment[2]].x, points[segment[2]].y
|
||||
);
|
||||
|
||||
gradient.addColorStop(0, '#1FB8CD');
|
||||
gradient.addColorStop(1, '#FFC185');
|
||||
|
||||
ctx.fillStyle = gradient;
|
||||
ctx.beginPath();
|
||||
ctx.moveTo(points[segment[0]].x, points[segment[0]].y);
|
||||
|
||||
// Connect the points in the segment
|
||||
for (let i = 1; i < segment.length; i++) {
|
||||
ctx.lineTo(points[segment[i]].x, points[segment[i]].y);
|
||||
}
|
||||
|
||||
ctx.closePath();
|
||||
ctx.fill();
|
||||
});
|
||||
|
||||
ctx.globalAlpha = 1.0;
|
||||
}
|
||||
|
||||
// Update demo metrics
|
||||
function updateDemoMetrics() {
|
||||
if (!demoRunning) return;
|
||||
|
||||
// Update with random values
|
||||
const strength = Math.floor(Math.random() * 10) - 50;
|
||||
const lat = Math.floor(Math.random() * 8) + 8;
|
||||
const persons = Math.floor(Math.random() * 2) + 1;
|
||||
const conf = (Math.random() * 10 + 80).toFixed(1);
|
||||
|
||||
signalStrength.textContent = `${strength} dBm`;
|
||||
latency.textContent = `${lat} ms`;
|
||||
personCount.textContent = persons;
|
||||
confidence.textContent = `${conf}%`;
|
||||
|
||||
// Schedule next update
|
||||
setTimeout(updateDemoMetrics, 2000);
|
||||
}
|
||||
}
|
||||
|
||||
// Architecture interaction
|
||||
function initArchitecture() {
|
||||
const stepCards = document.querySelectorAll('.step-card');
|
||||
|
||||
stepCards.forEach(card => {
|
||||
card.addEventListener('click', () => {
|
||||
// Get step number
|
||||
const step = card.getAttribute('data-step');
|
||||
|
||||
// Remove active class from all steps
|
||||
stepCards.forEach(s => s.classList.remove('highlight'));
|
||||
|
||||
// Add active class to current step
|
||||
card.classList.add('highlight');
|
||||
});
|
||||
});
|
||||
}
|
||||
Reference in New Issue
Block a user