bowling-analysis-system
Version:
A comprehensive system for analyzing bowling techniques using video processing and metrics calculation
220 lines (182 loc) • 6.99 kB
JavaScript
/**
* @module bowling_analysis/metrics/BiasProcessorUtils
* @description Utility functions for bias processing and analysis
*/
/**
* Analyzes bias data structure and returns key patterns
* @param {Object} biasData - The bias data to analyze
* @returns {Object} Analysis of the bias patterns
*/
function analyzeBiasStructure(biasData) {
const patterns = biasData.correlationPatterns || {};
const eventTypes = Object.keys(patterns);
const metricsByEvent = {};
for (const event of eventTypes) {
const eventPatterns = patterns[event] || [];
metricsByEvent[event] = {
count: eventPatterns.length,
topMetrics: eventPatterns
.sort((a, b) => b.weight - a.weight)
.slice(0, 3)
.map(p => ({
path: p.metric,
weight: p.weight
}))
};
}
return {
totalPatterns: Object.values(patterns).reduce((sum, arr) => sum + arr.length, 0),
events: metricsByEvent
};
}
/**
* Calculate variability from metrics
* @param {Object} metricsSection - The metrics section to calculate variability from
* @returns {number} The calculated variability
*/
function calculateVariabilityFromMetrics(metricsSection) {
// Default variability if no calculation is possible
const defaultVariability = 0.2;
if (!metricsSection || typeof metricsSection !== 'object') {
return defaultVariability;
}
// Find time series data if available
const timeSeriesKeys = Object.keys(metricsSection).filter(key =>
metricsSection[key] &&
metricsSection[key].series &&
Array.isArray(metricsSection[key].series)
);
if (timeSeriesKeys.length === 0) {
return defaultVariability;
}
// Calculate average variability across available time series
let totalVariability = 0;
let seriesCount = 0;
timeSeriesKeys.forEach(key => {
const series = metricsSection[key].series;
if (series.length < 2) return;
// Calculate standard deviation of the series
const values = series.map(point => point.value).filter(val => typeof val === 'number');
if (values.length < 2) return;
const mean = values.reduce((sum, val) => sum + val, 0) / values.length;
const squaredDiffs = values.map(val => Math.pow(val - mean, 2));
const variance = squaredDiffs.reduce((sum, val) => sum + val, 0) / values.length;
const stdDev = Math.sqrt(variance);
// Use raw standard deviation directly as variability measure
totalVariability += stdDev;
seriesCount++;
});
return seriesCount > 0 ? (totalVariability / seriesCount) : defaultVariability;
}
/**
* Calculate consistency from metrics
* @param {Object} metricsSection - The metrics section to calculate consistency from
* @returns {number} The calculated consistency
*/
function calculateConsistencyFromMetrics(metricsSection) {
// Default consistency if no calculation is possible
const defaultConsistency = 0.7;
if (!metricsSection || typeof metricsSection !== 'object') {
return defaultConsistency;
}
// Consistency is inversely related to variability
const variability = calculateVariabilityFromMetrics(metricsSection);
// Return raw inverse of variability without scaling
return 1 / (variability + 1);
}
/**
* Calculate event detection score from events
* @param {Object} events - The events object
* @returns {number} The calculated event detection score
*/
function calculateEventDetectionScore(events) {
// Default detection score if no calculation is possible
const defaultScore = 0.7;
if (!events || typeof events !== 'object') {
return defaultScore;
}
// Get primary event types we expect to find
const primaryEvents = ['releasePoint', 'frontFootLanding', 'backFootLanding'];
// Count how many of the primary events we detected
const detectedCount = primaryEvents.filter(eventType =>
events[eventType] &&
typeof events[eventType] === 'object' &&
events[eventType].frame !== undefined
).length;
// Calculate a score based on the proportion of detected events
// Scale it to be between 0.5 (no events) and 1.0 (all events)
return 0.5 + (detectedCount / primaryEvents.length) * 0.5;
}
/**
* Calculate event confidence from events
* @param {Object} events - The events object
* @returns {number} The calculated event confidence
*/
function calculateEventConfidence(events) {
// Default confidence if no calculation is possible
const defaultConfidence = 0.7;
if (!events || typeof events !== 'object') {
return defaultConfidence;
}
// Get primary event types we expect to find
const primaryEvents = ['releasePoint', 'frontFootLanding', 'backFootLanding'];
// Calculate average confidence across detected events
let totalConfidence = 0;
let eventCount = 0;
primaryEvents.forEach(eventType => {
if (
events[eventType] &&
typeof events[eventType] === 'object' &&
typeof events[eventType].confidence === 'number'
) {
totalConfidence += events[eventType].confidence;
eventCount++;
}
});
return eventCount > 0 ? (totalConfidence / eventCount) : defaultConfidence;
}
/**
* Calculate event consistency from events
* @param {Object} events - The events object
* @returns {number} The calculated event consistency
*/
function calculateEventConsistency(events) {
// Default consistency if no calculation is possible
const defaultConsistency = 0.7;
if (!events || typeof events !== 'object') {
return defaultConsistency;
}
// For consistency, we need multiple samples, but we usually only have
// one set of events per analysis. So we estimate consistency based on
// the confidence of the events and their relative timing
// Get confidence as a base
const confidence = calculateEventConfidence(events);
// Adjust consistency based on the confidence
// Higher confidence typically correlates with higher consistency
return 0.4 + (confidence * 0.6);
}
/**
* Calculate event variability from events
* @param {Object} events - The events object
* @returns {number} The calculated event variability
*/
function calculateEventVariability(events) {
// Default variability if no calculation is possible
const defaultVariability = 0.2;
if (!events || typeof events !== 'object') {
return defaultVariability;
}
// Variability is inversely related to consistency
const consistency = calculateEventConsistency(events);
// Return raw inverse value without scaling
return 1 - consistency;
}
module.exports = {
analyzeBiasStructure,
calculateVariabilityFromMetrics,
calculateConsistencyFromMetrics,
calculateEventDetectionScore,
calculateEventConfidence,
calculateEventConsistency,
calculateEventVariability
};