setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION); } catch (PDOException $e) { if (isset($_POST['action'])) { header('Content-Type: application/json'); echo json_encode(['success' => false, 'error' => 'Database connection failed: ' . $e->getMessage()]); exit; } die("Connection failed: " . $e->getMessage()); } // Handle AJAX requests if (isset($_POST['action'])) { while (ob_get_level()) { ob_end_clean(); } ob_start(); header('Content-Type: application/json'); try { switch ($_POST['action']) { case 'get_available_tags': $stmt = $pdo->prepare(" SELECT DISTINCT n.name, COUNT(*) as record_count, MIN(h.TimeStamp) as earliest_date, MAX(h.TimeStamp) as latest_date FROM id_names n INNER JOIN historicaldata h ON n.idnumber = h.ID WHERE n.name IS NOT NULL AND n.name != '' AND h.Value IS NOT NULL AND h.TimeStamp >= DATE_SUB(NOW(), INTERVAL 30 DAY) GROUP BY n.name HAVING record_count >= 100 ORDER BY record_count DESC, n.name ASC "); $stmt->execute(); $tags = $stmt->fetchAll(PDO::FETCH_ASSOC); echo json_encode([ 'success' => true, 'tags' => $tags, 'total_count' => count($tags) ]); break; case 'calculate_correlation_matrix': $selectedTags = json_decode($_POST['tags'] ?? '[]', true); $timeRange = (int)($_POST['time_range'] ?? 24); $samplingInterval = (int)($_POST['sampling_interval'] ?? 10); $correlationMethod = $_POST['correlation_method'] ?? 'pearson'; $lagAnalysis = (bool)($_POST['lag_analysis'] ?? false); $maxLag = (int)($_POST['max_lag'] ?? 60); if (empty($selectedTags) || !is_array($selectedTags) || count($selectedTags) < 2) { throw new Exception('Please select at least 2 tags for correlation analysis'); } if (count($selectedTags) > 20) { throw new Exception('Maximum 20 tags allowed for performance reasons'); } // Get synchronized data for all selected tags $correlationData = getSynchronizedData($pdo, $selectedTags, $timeRange, $samplingInterval); if (empty($correlationData)) { throw new Exception('No synchronized data found for the selected tags and time period'); } // Calculate correlation matrix $correlationMatrix = calculateCorrelationMatrix($correlationData, $correlationMethod); // Calculate lag correlations if requested $lagCorrelations = []; if ($lagAnalysis) { $lagCorrelations = calculateLagCorrelations($correlationData, $maxLag, $correlationMethod); } // Calculate statistical significance $significanceMatrix = calculateSignificanceMatrix($correlationData, $correlationMatrix); // Generate insights $insights = generateCorrelationInsights($correlationMatrix, $selectedTags, $significanceMatrix); echo json_encode([ 'success' => true, 'correlation_matrix' => $correlationMatrix, 'lag_correlations' => $lagCorrelations, 'significance_matrix' => $significanceMatrix, 'insights' => $insights, 'data_points' => count($correlationData), 'tags' => $selectedTags, 'time_range' => $timeRange, 'method' => $correlationMethod ]); break; case 'get_scatter_plot_data': $tagX = $_POST['tag_x'] ?? ''; $tagY = $_POST['tag_y'] ?? ''; $timeRange = (int)($_POST['time_range'] ?? 24); $maxPoints = (int)($_POST['max_points'] ?? 1000); if (empty($tagX) || empty($tagY)) { throw new Exception('Both X and Y tags must be specified'); } $scatterData = getScatterPlotData($pdo, $tagX, $tagY, $timeRange, $maxPoints); echo json_encode([ 'success' => true, 'scatter_data' => $scatterData, 'tag_x' => $tagX, 'tag_y' => $tagY ]); break; case 'export_correlation_data': $selectedTags = json_decode($_POST['tags'] ?? '[]', true); $timeRange = (int)($_POST['time_range'] ?? 24); $format = $_POST['format'] ?? 'csv'; if (empty($selectedTags)) { throw new Exception('No tags selected for export'); } $exportData = getSynchronizedData($pdo, $selectedTags, $timeRange, 5); // 5-minute intervals for export if ($format === 'csv') { $csv = exportToCSV($exportData, $selectedTags); header('Content-Type: text/csv'); header('Content-Disposition: attachment; filename="correlation_data_' . date('Y-m-d_H-i-s') . '.csv"'); echo $csv; exit; } echo json_encode([ 'success' => true, 'message' => 'Export format not supported' ]); break; default: throw new Exception('Invalid action specified'); } } catch (Exception $e) { echo json_encode(['success' => false, 'error' => $e->getMessage()]); } catch (Error $e) { echo json_encode(['success' => false, 'error' => 'PHP Error: ' . $e->getMessage()]); } ob_end_flush(); exit; } // Helper function to get synchronized data for correlation analysis function getSynchronizedData($pdo, $tags, $timeRange, $samplingInterval) { $placeholders = str_repeat('?,', count($tags) - 1) . '?'; // Create time buckets for synchronization $sql = " SELECT FLOOR(UNIX_TIMESTAMP(h.TimeStamp) / (? * 60)) * (? * 60) as time_bucket, n.name as tag_name, AVG(h.Value) as avg_value FROM historicaldata h INNER JOIN id_names n ON h.ID = n.idnumber WHERE n.name IN ($placeholders) AND h.TimeStamp >= DATE_SUB(NOW(), INTERVAL ? HOUR) AND h.Value IS NOT NULL GROUP BY time_bucket, n.name HAVING COUNT(*) >= 1 ORDER BY time_bucket ASC "; $params = array_merge([$samplingInterval, $samplingInterval], $tags, [$timeRange]); $stmt = $pdo->prepare($sql); $stmt->execute($params); $rawData = $stmt->fetchAll(PDO::FETCH_ASSOC); // Organize data by time bucket $bucketData = []; foreach ($rawData as $row) { $bucket = $row['time_bucket']; $tag = $row['tag_name']; $value = (float)$row['avg_value']; if (!isset($bucketData[$bucket])) { $bucketData[$bucket] = []; } $bucketData[$bucket][$tag] = $value; } // Filter buckets that have data for all tags $synchronizedData = []; foreach ($bucketData as $bucket => $data) { if (count($data) === count($tags)) { $row = ['timestamp' => $bucket]; foreach ($tags as $tag) { $row[$tag] = $data[$tag]; } $synchronizedData[] = $row; } } return $synchronizedData; } // Calculate correlation matrix function calculateCorrelationMatrix($data, $method = 'pearson') { if (empty($data)) return []; $tags = array_keys($data[0]); $tags = array_filter($tags, function($tag) { return $tag !== 'timestamp'; }); $matrix = []; foreach ($tags as $tagX) { $matrix[$tagX] = []; foreach ($tags as $tagY) { if ($tagX === $tagY) { $matrix[$tagX][$tagY] = 1.0; } else { $valuesX = array_column($data, $tagX); $valuesY = array_column($data, $tagY); switch ($method) { case 'spearman': $correlation = calculateSpearmanCorrelation($valuesX, $valuesY); break; case 'kendall': $correlation = calculateKendallCorrelation($valuesX, $valuesY); break; default: // pearson $correlation = calculatePearsonCorrelation($valuesX, $valuesY); break; } $matrix[$tagX][$tagY] = $correlation; } } } return $matrix; } // Calculate Pearson correlation coefficient function calculatePearsonCorrelation($x, $y) { $n = count($x); if ($n < 2) return 0; $sumX = array_sum($x); $sumY = array_sum($y); $sumXY = 0; $sumX2 = 0; $sumY2 = 0; for ($i = 0; $i < $n; $i++) { $sumXY += $x[$i] * $y[$i]; $sumX2 += $x[$i] * $x[$i]; $sumY2 += $y[$i] * $y[$i]; } $numerator = $n * $sumXY - $sumX * $sumY; $denominator = sqrt(($n * $sumX2 - $sumX * $sumX) * ($n * $sumY2 - $sumY * $sumY)); if ($denominator == 0) return 0; return $numerator / $denominator; } // Calculate Spearman rank correlation function calculateSpearmanCorrelation($x, $y) { $rankX = array_values(calculateRanks($x)); $rankY = array_values(calculateRanks($y)); return calculatePearsonCorrelation($rankX, $rankY); } // Calculate ranks for Spearman correlation function calculateRanks($values) { $indexed = []; foreach ($values as $index => $value) { $indexed[] = ['value' => $value, 'index' => $index]; } usort($indexed, function($a, $b) { return $a['value'] <=> $b['value']; }); $ranks = []; for ($i = 0; $i < count($indexed); $i++) { $ranks[$indexed[$i]['index']] = $i + 1; } return $ranks; } // Calculate Kendall's tau correlation (simplified version) function calculateKendallCorrelation($x, $y) { $n = count($x); if ($n < 2) return 0; $concordant = 0; $discordant = 0; for ($i = 0; $i < $n - 1; $i++) { for ($j = $i + 1; $j < $n; $j++) { $signX = ($x[$j] - $x[$i]) <=> 0; $signY = ($y[$j] - $y[$i]) <=> 0; if ($signX * $signY > 0) { $concordant++; } elseif ($signX * $signY < 0) { $discordant++; } } } $totalPairs = $n * ($n - 1) / 2; if ($totalPairs == 0) return 0; return ($concordant - $discordant) / $totalPairs; } // Calculate lag correlations function calculateLagCorrelations($data, $maxLag, $method = 'pearson') { if (empty($data) || $maxLag <= 0) return []; $tags = array_keys($data[0]); $tags = array_filter($tags, function($tag) { return $tag !== 'timestamp'; }); $lagCorrelations = []; foreach ($tags as $tagX) { foreach ($tags as $tagY) { if ($tagX === $tagY) continue; $valuesX = array_column($data, $tagX); $valuesY = array_column($data, $tagY); $bestCorrelation = 0; $bestLag = 0; for ($lag = 0; $lag <= min($maxLag, count($valuesX) - 10); $lag++) { $laggedX = array_slice($valuesX, $lag); $laggedY = array_slice($valuesY, 0, count($laggedX)); if (count($laggedX) < 10) break; $correlation = calculatePearsonCorrelation($laggedX, $laggedY); if (abs($correlation) > abs($bestCorrelation)) { $bestCorrelation = $correlation; $bestLag = $lag; } } $lagCorrelations[] = [ 'tag_x' => $tagX, 'tag_y' => $tagY, 'correlation' => $bestCorrelation, 'lag' => $bestLag, 'lag_minutes' => $bestLag * 10 // Assuming 10-minute intervals ]; } } // Sort by absolute correlation strength usort($lagCorrelations, function($a, $b) { return abs($b['correlation']) <=> abs($a['correlation']); }); return array_slice($lagCorrelations, 0, 20); // Return top 20 } // Calculate statistical significance function calculateSignificanceMatrix($data, $correlationMatrix) { $n = count($data); $significanceMatrix = []; foreach ($correlationMatrix as $tagX => $row) { $significanceMatrix[$tagX] = []; foreach ($row as $tagY => $correlation) { if ($tagX === $tagY) { $significanceMatrix[$tagX][$tagY] = 0; // Perfect correlation, no p-value } else { // Calculate t-statistic and p-value if (abs($correlation) >= 1.0) { $pValue = 0; } else { $tStat = $correlation * sqrt(($n - 2) / (1 - $correlation * $correlation)); $pValue = 2 * (1 - getTDistributionCDF(abs($tStat), $n - 2)); } $significanceMatrix[$tagX][$tagY] = $pValue; } } } return $significanceMatrix; } // Simplified t-distribution CDF approximation function getTDistributionCDF($t, $df) { if ($df <= 0) return 0.5; // Simple approximation for large degrees of freedom if ($df >= 30) { return 0.5 * (1 + erf($t / sqrt(2))); } // Very simplified approximation for smaller df $x = $df / ($df + $t * $t); return 1 - 0.5 * pow($x, $df / 2); } // Error function approximation function erf($x) { $sign = ($x >= 0) ? 1 : -1; $x = abs($x); $a1 = 0.254829592; $a2 = -0.284496736; $a3 = 1.421413741; $a4 = -1.453152027; $a5 = 1.061405429; $p = 0.3275911; $t = 1.0 / (1.0 + $p * $x); $y = 1.0 - (((($a5 * $t + $a4) * $t) + $a3) * $t + $a2) * $t + $a1) * $t * exp(-$x * $x); return $sign * $y; } // Generate correlation insights function generateCorrelationInsights($correlationMatrix, $tags, $significanceMatrix) { $insights = []; // Find strongest positive correlations $strongPositive = []; $strongNegative = []; $weakCorrelations = []; foreach ($correlationMatrix as $tagX => $row) { foreach ($row as $tagY => $correlation) { if ($tagX === $tagY) continue; $pValue = $significanceMatrix[$tagX][$tagY]; $significant = $pValue < 0.05; $pair = [$tagX, $tagY]; sort($pair); // Avoid duplicates $pairKey = implode(' - ', $pair); if ($correlation > 0.7 && $significant) { $strongPositive[$pairKey] = [ 'correlation' => $correlation, 'p_value' => $pValue, 'tags' => $pair ]; } elseif ($correlation < -0.7 && $significant) { $strongNegative[$pairKey] = [ 'correlation' => $correlation, 'p_value' => $pValue, 'tags' => $pair ]; } elseif (abs($correlation) < 0.1) { $weakCorrelations[$pairKey] = [ 'correlation' => $correlation, 'p_value' => $pValue, 'tags' => $pair ]; } } } // Sort by correlation strength uasort($strongPositive, function($a, $b) { return $b['correlation'] <=> $a['correlation']; }); uasort($strongNegative, function($a, $b) { return $a['correlation'] <=> $b['correlation']; }); $insights['strong_positive'] = array_slice($strongPositive, 0, 5, true); $insights['strong_negative'] = array_slice($strongNegative, 0, 5, true); $insights['weak_correlations'] = array_slice($weakCorrelations, 0, 5, true); // Summary statistics $allCorrelations = []; foreach ($correlationMatrix as $tagX => $row) { foreach ($row as $tagY => $correlation) { if ($tagX !== $tagY) { $allCorrelations[] = abs($correlation); } } } $insights['summary'] = [ 'total_pairs' => count($allCorrelations) / 2, // Divide by 2 to avoid counting each pair twice 'average_correlation' => array_sum($allCorrelations) / count($allCorrelations), 'max_correlation' => max($allCorrelations), 'highly_correlated_pairs' => count($strongPositive) + count($strongNegative) ]; return $insights; } // Get scatter plot data for two specific tags function getScatterPlotData($pdo, $tagX, $tagY, $timeRange, $maxPoints) { $stmt = $pdo->prepare(" SELECT hx.Value as x_value, hy.Value as y_value, hx.TimeStamp FROM historicaldata hx INNER JOIN id_names nx ON hx.ID = nx.idnumber INNER JOIN historicaldata hy ON hx.TimeStamp = hy.TimeStamp INNER JOIN id_names ny ON hy.ID = ny.idnumber WHERE nx.name = ? AND ny.name = ? AND hx.TimeStamp >= DATE_SUB(NOW(), INTERVAL ? HOUR) AND hx.Value IS NOT NULL AND hy.Value IS NOT NULL ORDER BY hx.TimeStamp DESC LIMIT ? "); $stmt->execute([$tagX, $tagY, $timeRange, $maxPoints]); return $stmt->fetchAll(PDO::FETCH_ASSOC); } // Export correlation data to CSV function exportToCSV($data, $tags) { if (empty($data)) return ''; $csv = 'Timestamp,' . implode(',', $tags) . "\n"; foreach ($data as $row) { $csvRow = [date('Y-m-d H:i:s', $row['timestamp'])]; foreach ($tags as $tag) { $csvRow[] = $row[$tag] ?? ''; } $csv .= implode(',', $csvRow) . "\n"; } return $csv; } ?>
Discover Hidden Relationships Between Process Variables
Discover Hidden Relationships Between Process Variables