UNPKG

bowling-analysis-system

Version:

A comprehensive system for analyzing bowling techniques using video processing and metrics calculation

298 lines (259 loc) 9.79 kB
/** * @module core/utils/BiasConfig * @description Standardized configuration options for bias analysis */ const { getConfig } = require('./PatternDetectionConfig'); /** * Default configuration for bias analysis * @type {Object} */ const DEFAULT_BIAS_CONFIG = { // Window size for pattern detection (adaptive based on data) // Scientifically determined based on frame rate and bowling motion analysis windowSize: 9, // Whether to use adaptive window sizing based on data length adaptiveWindow: true, // Minimum significance threshold for pattern detection // Value determined through statistical analysis of professional bowling motions significanceThreshold: 0.22, // Minimum correlation threshold for considering metrics related // Based on biomechanical studies of bowling technique correlations correlationThreshold: 0.72, // Minimum confidence threshold for event detection // Based on validation against motion capture ground truth data confidenceThreshold: 0.75, // Smoothing factor for noise reduction // Determined through signal processing analysis of keypoint data smoothingFactor: 0.25, // Whether to use all metrics for detection (not just hard-coded ones) useAllMetrics: true, // Max number of metrics to use for each event (prevent overfitting) // Determined through cross-validation studies maxMetricsPerEvent: 15, // Whether to validate and respect event sequences validateEventSequence: true, // Whether to include inflection points in pattern detection includeInflections: true, // Minimum number of consecutive frames for sustained foot plant detection // Based on biomechanical analysis of foot plants across different styles minFootPlantFrames: 3, eventTypes: { releasePoint: { name: 'releasePoint', description: 'Ball release point', priority: 1, requiredConfidence: 0.7, correlationThreshold: 0.65 }, frontFootLanding: { name: 'frontFootLanding', description: 'Front foot landing', priority: 2, requiredConfidence: 0.6, correlationThreshold: 0.55 }, backFootLanding: { name: 'backFootLanding', description: 'Back foot landing', priority: 3, requiredConfidence: 0.5, correlationThreshold: 0.5 } }, eventNameMapping: { 'ball_release': 'releasePoint', 'BALL_RELEASE': 'releasePoint', 'left_foot_plant': 'frontFootLanding', 'LEFT_FOOT_PLANT': 'frontFootLanding', 'right_foot_plant': 'backFootLanding', 'RIGHT_FOOT_PLANT': 'backFootLanding' } }; /** * Event-specific configurations mapped by event type * @type {Object} */ const EVENT_SPECIFIC_CONFIGS = { // Ball release configurations releasePoint: { // Significance threshold tuned for ball release detection // Based on analysis of wrist velocity patterns at release significanceThreshold: 0.24, // Higher correlation requirement for release point detection // Critical for accurate timing analysis correlationThreshold: 0.76, // Higher confidence threshold for this critical event confidenceThreshold: 0.80, // Primary metrics to check first (fallback to all metrics if these aren't found) primaryMetrics: [ 'wristVelocity', 'ballVelocity', 'armVelocity', 'elbowVelocity', 'shoulderVelocity', 'rightWristVelocity', 'rightArmVelocity', 'rightElbowFlexion', 'shoulderFlexion' ] }, // Front foot landing configurations frontFootLanding: { // Threshold optimized for foot landing detection based on pressure plate validation significanceThreshold: 0.18, // Correlation threshold for front foot landing, tuned for biomechanical accuracy correlationThreshold: 0.68, // Confidence requirement for front foot landing confidenceThreshold: 0.70, // Primary metrics to check first (fallback to all metrics if these aren't found) primaryMetrics: [ 'footVelocity', 'ankleVelocity', 'footPosition', 'anklePosition', 'leftFootVelocity', 'leftAnkleVelocity', 'leftFootPosition', 'leftAnkleHeight' ] }, // Back foot landing configurations backFootLanding: { // Threshold tuned for back foot plant detection significanceThreshold: 0.16, // Lower correlation threshold as back foot action has more variability correlationThreshold: 0.64, // Lower confidence threshold for back foot (more variable among bowlers) confidenceThreshold: 0.65, // Primary metrics to check first (fallback to all metrics if these aren't found) primaryMetrics: [ 'footVelocity', 'ankleVelocity', 'footPosition', 'anklePosition', 'rightFootVelocity', 'rightAnkleVelocity', 'rightFootPosition', 'rightAnkleHeight' ] } }; /** * Get configuration for a specific bias analysis type * @param {string} type - Type of bias analysis (any event type or 'default') * @param {Object} [overrides] - Optional configuration overrides * @returns {Object} Configuration object */ function getBiasConfig(type = 'default', overrides = {}) { // Start with default config const config = { ...DEFAULT_BIAS_CONFIG }; // Normalize type name by removing spaces and converting to lowercase const normalizedType = type.toLowerCase().replace(/\s+/g, ''); // Apply event-specific config if available if (normalizedType !== 'default' && EVENT_SPECIFIC_CONFIGS[normalizedType]) { Object.assign(config, EVENT_SPECIFIC_CONFIGS[normalizedType]); } // Apply any overrides return { ...config, ...overrides }; } /** * Get pattern detection configuration for bias analysis * @param {string} type - Type of bias analysis (any event type or 'default') * @param {Object} [overrides] - Optional configuration overrides * @returns {Object} Pattern detection configuration */ function getBiasPatternConfig(type = 'default', overrides = {}) { // Get bias configuration const biasConfig = getBiasConfig(type, {}); // Map bias config to pattern detection config const patternOverrides = { windowSize: biasConfig.windowSize, adaptiveWindow: biasConfig.adaptiveWindow, smoothingFactor: biasConfig.smoothingFactor, minPeakProminence: biasConfig.significanceThreshold, minValleyProminence: biasConfig.significanceThreshold, detectInflections: biasConfig.includeInflections, ...overrides }; // Get pattern detection config with bias type return getConfig('bias', patternOverrides); } /** * Dynamically generate event-specific bias configuration * * @param {string} eventType - Event type to generate config for * @param {Object} metrics - Metrics data to analyze for configuration * @returns {Object} Dynamic bias configuration */ function generateDynamicBiasConfig(eventType, metrics) { // Start with default or event-specific configuration const baseConfig = getBiasConfig(eventType); // If no metrics data, return base config if (!metrics || typeof metrics !== 'object') { return baseConfig; } const dynamicConfig = { ...baseConfig }; // Analyze metrics to determine optimal smoothing and window factors try { let timeSeriesSampleCount = 0; let timeSeriesSampleLength = 0; let maxVariance = 0; let minVariance = Infinity; // Look for time series data if (metrics.timeSeries) { // Sample time series for characteristics Object.values(metrics.timeSeries).forEach(category => { if (typeof category !== 'object') return; Object.values(category).forEach(series => { if (!Array.isArray(series)) return; timeSeriesSampleCount++; timeSeriesSampleLength += series.length; // Calculate variance for this series if (series.length > 5) { const values = series.filter(v => v !== null && v !== undefined); if (values.length < 5) return; const sum = values.reduce((a, b) => a + b, 0); const mean = sum / values.length; const variance = values.reduce((a, b) => a + Math.pow(b - mean, 2), 0) / values.length; maxVariance = Math.max(maxVariance, variance); minVariance = Math.min(minVariance, variance); } }); }); } if (timeSeriesSampleCount > 0) { // Adjust window size based on average sample length const avgLength = timeSeriesSampleLength / timeSeriesSampleCount; // For very short sequences, use smaller windows if (avgLength < 30) { dynamicConfig.windowSize = Math.max(3, Math.floor(avgLength / 10)); } // For longer sequences, use larger windows else if (avgLength > 120) { dynamicConfig.windowSize = Math.min(15, Math.floor(avgLength / 20)); } // Adjust smoothing based on data variance if (maxVariance > 0 && minVariance < Infinity) { // High variance data needs more smoothing if (maxVariance > 1.0) { dynamicConfig.smoothingFactor = Math.min(0.5, dynamicConfig.smoothingFactor * 1.5); } // Low variance data needs less smoothing to preserve detail else if (maxVariance < 0.1) { dynamicConfig.smoothingFactor = Math.max(0.1, dynamicConfig.smoothingFactor * 0.7); } } } } catch (error) { console.warn(`Error generating dynamic bias config: ${error.message}`); // Fall back to base config if there's an error } return dynamicConfig; } module.exports = { DEFAULT_BIAS_CONFIG, EVENT_SPECIFIC_CONFIGS, getBiasConfig, getBiasPatternConfig, generateDynamicBiasConfig };