FDA Estimator
NOTE
Web SDKs Only Realtime estimation is currently available for web-based SDKs only (JavaScript, React, Vue). It is not available for mobile SDKs (iOS, Android, Flutter, React Native).
Overview
The FDA Estimator is a medical-grade heart rate measurement system that uses advanced signal processing to analyze photoplethysmography (PPG) signals from facial video. It provides FDA-level accuracy without requiring external AI models, making it ideal for medical applications and instant initialization.
IMPORTANT
Proprietary Technology The FDA Estimator is proprietary software developed by PanopticAI. The core algorithm runs in WebAssembly for intellectual property protection.
Key Features
- ✅ Medical-Grade: FDA-level accuracy
- ✅ Instant Init: No model loading required
- ✅ Zero Dependencies: No external files needed
- ✅ Deterministic: Same input → same output
- ✅ Lightweight: < 200 KB memory footprint
- ✅ Adaptive: Early results in 5 seconds, optimal in 10
Basic Usage
import { createVitalSignCamera, RealtimeEstimatorType } from 'ts-vital-sign-camera';
const camera = createVitalSignCamera({
realtimeEstimationConfig: {
estimatorType: RealtimeEstimatorType.Fda,
earlyEstimation: true,
minDuration: 10,
minConfidence: 0.6
}
});
camera.onVideoFrameProcessed = (event) => {
const estimation = event.realtimeEstimation;
if (!estimation) return;
console.log(`HR: ${estimation.heartRate} BPM`);
console.log(`Confidence: ${estimation.confidence}`);
console.log(`SNR: ${estimation.snr}`);
});Configuration
For Consumer Applications
{
estimatorType: RealtimeEstimatorType.Fda,
earlyEstimation: true, // Show early results
minDuration: 5, // Faster feedback
minConfidence: 0.4, // Lower threshold
debug: false
}For Medical Applications
{
estimatorType: RealtimeEstimatorType.Fda,
earlyEstimation: false, // Wait for full accuracy
minDuration: 10, // Full 10 seconds
minConfidence: 0.7, // High confidence threshold
debug: false
}SDK Behavior
Initialization
// FDA estimator initializes instantly (no async loading)
const camera = createVitalSignCamera({
realtimeEstimationConfig: {
estimatorType: RealtimeEstimatorType.Fda
}
});
// Ready immediately - no waiting required
camera.startScan();Processing Timeline
0s ────► 5s ────► 10s ────► 30s
│ │ │ │
│ │ │ └─ Scan complete
│ │ └─ Optimal accuracy (10s window)
│ └─ First estimate (5s window)
└─ Scan starts (instant init)Adaptive Time Window
The FDA estimator uses an adaptive time window that grows as more data arrives:
| Time Elapsed | Window Size | Accuracy | Status |
|---|---|---|---|
| 5 seconds | 5s | ±5-8 BPM | Early estimate |
| 7 seconds | 7s | ±3-5 BPM | Improving |
| 10+ seconds | 10s | ±2-3 BPM | Optimal ✓ |
camera.onVideoFrameProcessed = (event) => {
const elapsed = getCurrentScanTime();
if (elapsed < 7) {
showHeartRate(estimation.heartRate, 'Early estimate');
} else if (elapsed < 10) {
showHeartRate(estimation.heartRate, 'Refining...');
} else {
showHeartRate(estimation.heartRate, 'Stable ✓');
}
});Performance Characteristics
| Metric | Value |
|---|---|
| Initialization | Instant (< 10ms) |
| First Result | ~5 seconds |
| Optimal Accuracy | ~10 seconds |
| Processing Speed | 5-10ms per frame |
| Memory Usage | < 200 KB |
| Bundle Size | ~100 KB (WASM) |
| Typical Error | ±2-3 BPM |
| Heart Rate Range | 50-140 BPM |
Quality Metrics
Signal-to-Noise Ratio (SNR)
The FDA estimator provides SNR values to indicate signal quality:
| SNR | Confidence | Quality | Interpretation |
|---|---|---|---|
| 10+ | 1.0 | Excellent | Trust completely ✓ |
| 8-10 | 0.8-1.0 | Very Good | Highly reliable ✓ |
| 6-8 | 0.6-0.8 | Good | Reliable |
| 4-6 | 0.4-0.6 | Fair | Acceptable |
| 2-4 | 0.2-0.4 | Poor | Consider retrying |
| < 2 | 0.0-0.2 | Very Poor | Retry required |
camera.onVideoFrameProcessed = (event) => {
const estimation = event.realtimeEstimation;
if (!estimation) return;
if (estimation.snr && estimation.snr > 6) {
showQualityIndicator('excellent');
} else if (estimation.snr && estimation.snr > 4) {
showQualityIndicator('good');
} else {
showQualityIndicator('poor');
showTip('Improve lighting or reduce movement');
}
});Advantages
🏥 Medical-Grade Quality
- FDA-level accuracy
- Matches validated server implementation
- Suitable for medical applications
- Regulatory compliance friendly
📦 Zero Dependencies
- No model files to download
- Instant initialization
- Works offline immediately
- Smaller bundle size
⚡ Fast Initialization
- No async loading required
- Ready to use immediately
- No waiting for models
- Simpler error handling
🔒 IP Protection
- Core algorithm in WebAssembly
- Proprietary implementation protected
- Binary format prevents reverse engineering
🎯 Deterministic
- Same input → same output
- No AI randomness
- Reproducible results
- Easier to debug
When to Use
✅ Best For
- Medical and healthcare applications
- Regulatory compliance requirements
- Instant initialization needed
- Minimal bundle size required
- Offline-first applications
- Embedded systems and IoT devices
❌ Avoid If
- Users will be moving significantly
- Lighting conditions are uncontrolled
- Maximum motion tolerance needed
- Open-source licensing required
- AI-powered features preferred
Troubleshooting
Low Confidence Scores
Symptoms: Confidence < 0.6, unstable readings
Solutions:
// 1. Improve environmental conditions
const instructions = [
"Use natural daylight",
"Avoid backlighting",
"Ensure even illumination",
"Remove shadows from face"
];
// 2. Reduce motion
const motionTips = [
"Stay completely still",
"Don't talk during measurement",
"Use phone stand if possible",
"Maintain steady distance"
];
// 3. Wait longer
{
minDuration: 10, // Allow full 10-second window
minConfidence: 0.6
}
// 4. Check face detection - note: face detection events vary by SDK
// For web SDKs, check scanConditions in VideoFrameProcessedEvent
camera.onVideoFrameProcessed = (event) => {
if (event.scanConditions && !event.scanConditions.centered) {
showWarning('Keep face centered and stable');
}
});Unstable Readings
Symptoms: Heart rate jumps around
Solutions:
// Increase minimum confidence threshold
{
minConfidence: 0.7 // Higher threshold for stability
}
// Wait for full window
{
earlyEstimation: false, // Disable early results
minDuration: 10
}
// Guide user
camera.onVideoFrameProcessed = (event) => {
const estimation = event.realtimeEstimation;
if (!estimation) return;
if (estimation.confidence < 0.6) {
showTip('Please stay still and improve lighting');
}
});Best Practices
1. Progressive Feedback
camera.onVideoFrameProcessed = (event) => {
const estimation = event.realtimeEstimation;
if (!estimation) return;
const elapsed = getCurrentScanTime();
if (elapsed < 5) {
showMessage("Analyzing... Please stay still");
} else if (elapsed < 10) {
if (estimation.confidence > 0.4) {
showHeartRate(estimation.heartRate, "Refining...");
} else {
showMessage("Adjusting... Improve lighting if possible");
}
} else {
if (estimation.isStable) {
showHeartRate(estimation.heartRate, "Stable ✓");
} else {
showMessage("Low confidence. Try again with better conditions.");
}
}
});2. Quality Indicators
function getQualityIndicator(estimation: RealtimeEstimation): string {
if (estimation.confidence >= 0.8) return "Excellent ⭐⭐⭐⭐⭐";
if (estimation.confidence >= 0.6) return "Very Good ⭐⭐⭐⭐";
if (estimation.confidence >= 0.4) return "Good ⭐⭐⭐";
if (estimation.confidence >= 0.2) return "Fair ⭐⭐";
return "Poor ⭐";
}
camera.onVideoFrameProcessed = (event) => {
const estimation = event.realtimeEstimation;
if (!estimation) return;
updateQualityDisplay(getQualityIndicator(estimation));
});3. Retry Logic
let retryCount = 0;
const MAX_RETRIES = 3;
camera.onVideoFrameProcessed = (event) => {
const result = event.healthResult;
if (!result) return;
if (result.confidence < 0.6 && retryCount < MAX_RETRIES) {
retryCount++;
showMessage(`Low confidence. Retrying (${retryCount}/${MAX_RETRIES})...`);
camera.reset();
camera.startScan();
} else {
retryCount = 0;
displayFinalResult(result);
}
});4. User Guidance
const guidanceMessages = {
lowConfidence: "Improve lighting or stay still",
noFace: "Position your face in the center",
unstable: "Keep your face steady",
success: "Measurement complete ✓"
};
camera.onVideoFrameProcessed = (event) => {
const estimation = event.realtimeEstimation;
if (!estimation) return;
if (estimation.confidence < 0.4) {
showGuidance(guidanceMessages.lowConfidence);
} else if (estimation.isStable) {
showGuidance(guidanceMessages.success);
}
});Comparison with ME-rPPG Estimator
| Feature | FDA | ME-rPPG |
|---|---|---|
| Accuracy | ⭐⭐⭐⭐⭐ Medical-grade | ⭐⭐⭐⭐⭐ State-of-the-art |
| Motion Tolerance | ⭐⭐⭐⭐ Good | ⭐⭐⭐⭐⭐ Excellent |
| Lighting Tolerance | ⭐⭐⭐⭐ Good | ⭐⭐⭐⭐⭐ Excellent |
| Initialization | ⭐⭐⭐⭐⭐ Instant | ⭐⭐⭐ (1-2s) |
| Bundle Size | ⭐⭐⭐⭐⭐ ~100 KB | ⭐⭐⭐ ~10 MB |
| Memory Usage | ⭐⭐⭐⭐⭐ < 200 KB | ⭐⭐⭐ ~4 MB |
| Licensing | Proprietary | Open-source |
| First Result | ~5 seconds | ~3 seconds |
| Best For | Medical apps, embedded | Consumer apps, challenging conditions |
Example: Complete Implementation
import { createVitalSignCamera, RealtimeEstimatorType } from 'ts-vital-sign-camera';
// Create camera with FDA estimator
const camera = createVitalSignCamera({
realtimeEstimationConfig: {
estimatorType: RealtimeEstimatorType.Fda,
earlyEstimation: true,
minDuration: 10,
minConfidence: 0.6,
debug: false
}
});
// FDA is ready immediately (no async loading)
document.getElementById('start-btn').disabled = false;
// Handle realtime updates
camera.onVideoFrameProcessed = (event) => {
const estimation = event.realtimeEstimation;
if (!estimation) return;
updateHeartRateDisplay(estimation.heartRate);
updateConfidenceBar(estimation.confidence);
// Show SNR if available
if (estimation.snr) {
updateSNRDisplay(estimation.snr);
}
// Quality indicator
if (estimation.isStable && estimation.confidence > 0.7) {
showQualityIndicator('excellent');
} else if (estimation.confidence > 0.5) {
showQualityIndicator('good');
} else {
showQualityIndicator('poor');
showTip('Improve lighting or reduce movement');
}
});
// Handle scan completion
// Check for final results
let scanCompleted = false;
camera.onVideoFrameProcessed = (event) => {
const results = event.healthResult;
if (results && !scanCompleted) {
scanCompleted = true;
if (results.confidence > 0.7) {
displayFinalResults(results);
} else {
showRetryOption();
}
}
});
// Start scan
document.getElementById('start-btn').onclick = () => {
camera.startScan();
};Example: Medical Application
// Medical-grade configuration
const camera = createVitalSignCamera({
realtimeEstimationConfig: {
estimatorType: RealtimeEstimatorType.Fda,
earlyEstimation: false, // Wait for full accuracy
minDuration: 10, // Full 10 seconds
minConfidence: 0.7, // High threshold
debug: false
}
});
// Only record high-confidence measurements
camera.onVideoFrameProcessed = (event) => {
const estimation = event.realtimeEstimation;
if (!estimation) return;
if (estimation.isStable && estimation.confidence > 0.7) {
recordMeasurement({
heartRate: estimation.heartRate,
confidence: estimation.confidence,
snr: estimation.snr,
timestamp: new Date()
});
}
});
// Validate before saving
// Validate before saving
let validationCompleted = false;
camera.onVideoFrameProcessed = (event) => {
const results = event.healthResult;
if (results && !validationCompleted) {
validationCompleted = true;
if (results.confidence > 0.7 && results.snr > 5) {
saveMedicalRecord(results);
} else {
requestRetry('Measurement quality below medical threshold');
}
}
});Next Steps
- ME-rPPG Estimator - Compare with AI approach
- Selection Guide - Choose the right estimator
- Signal Visualizer - Visualize PPG signal
- API Reference - Complete API docs