# MATH310S26 Day 22 - Cross-Correlation and Signal Detection Related notes: - [[MATH310S26-Day21-Notes]] - Convolution theory and filtering - [[MATH310S26-Day20-Notes]] - Convolution theorem introduction - [[MATH310S26-Day19-WorkdayMaterials (Convolution theorem and RC filtering)]] - Convolution implementation - [[MATH310S26-Day16-WorkdayMaterials (FFT and frequency discovery)]] - FFT fundamentals ## Overview Today we explore **cross-correlation**, a fundamental tool in signal processing for detecting patterns, measuring time delays, and quantifying signal similarity. We'll work through concrete examples to build intuition before applying these concepts to real-world problems. **Video Resource**: https://youtu.be/0yFdKsv5L-U?si=svwww0Sb9PCKi3j7 ## The Mathematical Connection Recall from Day 21 that convolution is: $(f * g)(t) = \int_{-\infty}^{\infty} f(p) \cdot g(t-p) \, dp$ Key operation: **flip** $g(-p)$, then **shift** by $t$ [Cross-correlation](https://en.wikipedia.org/wiki/Cross-correlation) is almost identical: $(f \star g)(t) = \int_{-\infty}^{\infty} f(p) \cdot g(p+t) \, dp$ Key difference: **NO flip**, just **shift** In discrete form for computational work: - Convolution: $(f * g)[n] = \sum_m f[m] \cdot g[n-m]$ - Correlation: $(f \star g)[n] = \sum_m f[m] \cdot g[m+n]$ ### Correlation vs Cross-correlation **Standard Correlation** (no time shift): $R_{xy} = \sum_{n=0}^{N-1} x[n] \cdot y[n]$ **Cross-correlation** (with time shift $k$): $R_{xy}[k] = \sum_{n=0}^{N-1} x[n] \cdot y[n+k]$ Key difference from convolution: - Convolution: flip then shift - Cross-correlation: just shift (no flip) ### Physical Interpretation - **Positive correlation**: Signals align and reinforce - **Zero correlation**: Signals are orthogonal/independent - **Negative correlation**: Signals oppose each other # Part 1: Discrete Cross-Correlation ## Mathematical Foundation For discrete signals $x[n]$ and $y[n]$, the cross-correlation at lag $k$ is: $R_{xy}[k] = \sum_{n} x[n] \cdot y[n-k]$ This measures similarity between $x$ and a shifted version of $y$. The process: 1. **Shift** $y$ by $k$ samples 2. **Multiply** corresponding values 3. **Sum** all products ## Visual Understanding Watch the discrete cross-correlation animation: - ![Cross Correlation Animation](https://youtu.be/A6fpX5l20Ic) This shows how we slide one signal past another, computing correlation at each position. In the following we will replicate and visualize the quick tutorial by computing the relevant quantities in our languages. The code blocks are simple, but the end of one grand visualization will be provided so that you can see the results without the coding overhead. ![](https://youtu.be/0yFdKsv5L-U?si=I8GVq0CGMvgckrkA) ### Cross-Correlation Algorithm Before implementing in specific languages, let's understand the algorithm for computing cross-correlation between two discrete signals. #### Pseudocode ``` FUNCTION compute_cross_correlation(x, y): max_lag = length(x) - 1 lags = [-max_lag, ..., 0, ..., max_lag] correlation = empty array of size length(lags) FOR each lag k in lags: IF k >= 0: x_padded = [x, zeros(k)] y_padded = [zeros(k), y] ELSE: x_padded = [zeros(|k|), x] y_padded = [y, zeros(|k|)] # Ensure equal lengths max_length = max(length(x_padded), length(y_padded)) x_padded = pad_to_length(x_padded, max_length) y_padded = pad_to_length(y_padded, max_length) correlation[k] = sum(x_padded * y_padded) RETURN lags, correlation ``` #### Key Points • **Lag Range**: We compute correlation for lags from -(N-1) to (N-1) where N is the length of signal x • **Padding Strategy**: Add zeros to align signals at different lags • **Positive Lag**: y is delayed relative to x (shift y right) • **Negative Lag**: y is advanced relative to x (shift y left) • **Element-wise Product**: Multiply aligned samples and sum for correlation value • **Peak Location**: Maximum correlation indicates best alignment lag • **Computational Complexity**: O(N²) for N-length signals #### Built-in Functions If you prefer to use built-in functions instead of implementing from scratch: • **Python (NumPy)**: `np.correlate(x, y, mode='full')` - returns correlation for all lags • **R**: `ccf(x, y, lag.max, plot=FALSE)` - returns correlation and lags with statistical normalization • **MATLAB/Octave**: `xcorr(x, y)` - returns correlation values and lag vector **Note**: Built-in functions may have different normalization, lag conventions, or output formats. Our custom implementation ensures consistency across all languages and matches the mathematical definition exactly. ## Implementation in Python, R, and MATLAB We'll explore three examples from the video, each demonstrating different aspects of cross-correlation. Choose your preferred language and work through the complete implementation in that section. ## Python Implementation ### Setup and Import ```python import numpy as np import matplotlib.pyplot as plt ``` Purpose: Import required libraries for numerical computation and visualization. ### Define Cross-Correlation Function ```python def compute_cross_correlation(x, y): max_lag = len(x) - 1 lags = np.arange(-max_lag, max_lag + 1) correlation = np.zeros(len(lags)) for i, k in enumerate(lags): if k >= 0: x_padded = np.concatenate([x, np.zeros(k)]) y_padded = np.concatenate([np.zeros(k), y]) else: x_padded = np.concatenate([np.zeros(abs(k)), x]) y_padded = np.concatenate([y, np.zeros(abs(k))]) # Ensure same length and compute max_len = max(len(x_padded), len(y_padded)) if len(x_padded) < max_len: x_padded = np.concatenate([x_padded, np.zeros(max_len - len(x_padded))]) if len(y_padded) < max_len: y_padded = np.concatenate([y_padded, np.zeros(max_len - len(y_padded))]) correlation[i] = np.sum(x_padded * y_padded) return lags, correlation ``` Purpose: Function to compute cross-correlation at all possible lags. ### Example 1: Dissimilar Signals ```python # Create signals x1 = np.array([1, 2, -4, -6, 0, 1]) y1 = np.array([2, 3, -2, 4, 5, 0]) ``` Purpose: Create the first example signals showing dissimilar patterns. ```python # Manual calculation at lag 0 products = x1 * y1 # array([2, 6, 8, -24, 0, 0]) corr_value = np.sum(products) # -8 print(f"Correlation at lag 0: {corr_value}") ``` Purpose: Show element-wise multiplication and sum. ```python # Compute full correlation lags1, corr1 = compute_cross_correlation(x1, y1) max_idx = np.argmin(corr1) print(f"Maximum absolute correlation: {corr1[max_idx]} at lag {lags1[max_idx]}") ``` Purpose: Find the peak correlation value. ### Example 2: Similar Shaped Signals ```python # Create signals with similar shapes x2 = np.array([1, 2, -4, -6, 0, 1]) z2 = np.array([1, 3, -3, -4, 0, 2]) ``` Purpose: Signals with peaks and valleys that align. ```python # Compute correlation lags2, corr2 = compute_cross_correlation(x2, z2) max_idx = np.argmax(corr2) print(f"Maximum correlation: {corr2[max_idx]} at lag {lags2[max_idx]}") ``` Purpose: Find peak showing signals are most similar when aligned. ### Example 3: Pattern Detection with Time Shift ```python # Create signals where y pattern appears shifted within x x3 = np.array([0, 1, 3, -1, 2, -3, 5, -2]) y3 = np.array([2, -4, 4, -2]) ``` Purpose: Create signals where y pattern appears shifted within x. ```python # Compute cross-correlation lags3, corr3 = compute_cross_correlation(x3, y3) ``` Purpose: Calculate correlation at all lags. ```python # Display correlation table print("Cross-correlation table:") print("Lag: ", " ".join([f"{l:3d}" for l in lags3])) print("Corr:", " ".join([f"{c:4.0f}" for c in corr3])) ``` Purpose: Show correlation values at each lag. ```python # Find maximum correlations max_pos_idx = np.argmax(corr3) max_neg_idx = np.argmin(corr3) print(f"Maximum positive: {corr3[max_pos_idx]} at lag {lags3[max_pos_idx]}") print(f"Maximum negative: {corr3[max_neg_idx]} at lag {lags3[max_neg_idx]}") ``` Purpose: Identify peaks showing where patterns best align. ### Visualization ```python # Create comprehensive visualization fig, axes = plt.subplots(1, 3, figsize=(12, 4)) axes[0].plot(lags1, corr1, 'o-', color='green') axes[0].set_title("Example 1: Dissimilar") axes[0].set_xlabel("Lag") axes[0].set_ylabel("Correlation") axes[0].axhline(y=0, color='black', linestyle='--', alpha=0.5) axes[0].grid(True, alpha=0.3) axes[1].plot(lags2, corr2, 'o-', color='blue') axes[1].set_title("Example 2: Similar") axes[1].set_xlabel("Lag") axes[1].set_ylabel("Correlation") axes[1].axhline(y=0, color='black', linestyle='--', alpha=0.5) axes[1].grid(True, alpha=0.3) axes[2].plot(lags3, corr3, 'o-', color='purple') axes[2].set_title("Example 3: Pattern shift") axes[2].set_xlabel("Lag") axes[2].set_ylabel("Correlation") axes[2].axhline(y=0, color='black', linestyle='--', alpha=0.5) axes[2].grid(True, alpha=0.3) plt.tight_layout() plt.show() ``` Purpose: Create correlation plots to visualize patterns. *Note: A comprehensive 2×3 visualization showing both signals and correlations is provided in the Comprehensive Visualization section below.* ## R Implementation ### Define Cross-Correlation Function ```r compute_cross_correlation <- function(x, y) { max_lag <- length(x) - 1 lags <- seq(-max_lag, max_lag) correlation <- numeric(length(lags)) for (i in 1:length(lags)) { k <- lags[i] if (k >= 0) { x_padded <- c(x, rep(0, k)) y_padded <- c(rep(0, k), y) } else { x_padded <- c(rep(0, abs(k)), x) y_padded <- c(y, rep(0, abs(k))) } # Ensure same length and compute max_len <- max(length(x_padded), length(y_padded)) x_padded <- c(x_padded, rep(0, max_len - length(x_padded))) y_padded <- c(y_padded, rep(0, max_len - length(y_padded))) correlation[i] <- sum(x_padded * y_padded) } return(list(lags = lags, correlation = correlation)) } ``` Purpose: Function to compute cross-correlation at all possible lags. ### Example 3: Pattern Detection with Time Shift ```r # Create signals x1 <- c(1, 2, -4, -6, 0, 1) y1 <- c(2, 3, -2, 4, 5, 0) ``` Purpose: Create the first example signals showing dissimilar patterns. ```r # Manual calculation at lag 0 products <- x1 * y1 # [2, 6, 8, -24, 0, 0] corr_value <- sum(products) # -8 cat("Correlation at lag 0:", corr_value, "\n") ``` Purpose: Show element-wise multiplication and sum. ```r # Compute full correlation result1 <- compute_cross_correlation(x1, y1) max_idx <- which.min(result1$correlation) cat("Maximum absolute correlation:", result1$correlation[max_idx], "at lag", result1$lags[max_idx], "\n") ``` Purpose: Find the peak correlation value. ### Example 2: Similar Shaped Signals ```r # Create signals with similar shapes x2 <- c(1, 2, -4, -6, 0, 1) z2 <- c(1, 3, -3, -4, 0, 2) ``` Purpose: Signals with peaks and valleys that align. ```r # Compute correlation result2 <- compute_cross_correlation(x2, z2) max_idx <- which.max(result2$correlation) cat("Maximum correlation:", result2$correlation[max_idx], "at lag", result2$lags[max_idx], "\n") ``` Purpose: Find peak showing signals are most similar when aligned. ### Example 3: Pattern Detection with Time Shift ```r # Create signals where y pattern appears shifted within x x3 <- c(0, 1, 3, -1, 2, -3, 5, -2) y3 <- c(2, -4, 4, -2) ``` Purpose: Create signals where y pattern appears shifted within x. ```r # Compute cross-correlation result3 <- compute_cross_correlation(x3, y3) ``` Purpose: Calculate correlation at all lags. ```r # Display correlation table cat("Cross-correlation table:\n") cat("Lag: ", sprintf("%3d", result3$lags), "\n") cat("Corr:", sprintf("%4.0f", result3$correlation), "\n") ``` Purpose: Show correlation values at each lag. ```r # Find maximum correlations max_pos_idx <- which.max(result3$correlation) max_neg_idx <- which.min(result3$correlation) cat("Maximum positive:", result3$correlation[max_pos_idx], "at lag", result3$lags[max_pos_idx], "\n") cat("Maximum negative:", result3$correlation[max_neg_idx], "at lag", result3$lags[max_neg_idx], "\n") ``` Purpose: Identify peaks showing where patterns best align. ### Visualization ```r # Create comprehensive visualization par(mfrow = c(1, 3)) plot(result1$lags, result1$correlation, type = "b", col = "green", main = "Example 1: Dissimilar", xlab = "Lag", ylab = "Correlation") abline(h = 0) plot(result2$lags, result2$correlation, type = "b", col = "blue", main = "Example 2: Similar", xlab = "Lag", ylab = "Correlation") abline(h = 0) plot(result3$lags, result3$correlation, type = "b", col = "purple", main = "Example 3: Pattern shift", xlab = "Lag", ylab = "Correlation") abline(h = 0) ``` Purpose: Create correlation plots to visualize patterns. *Note: A comprehensive 2×3 visualization showing both signals and correlations is provided in the Comprehensive Visualization section below.* ## MATLAB Implementation ### Define Cross-Correlation Function ```matlab function [lags, correlation] = compute_cross_correlation(x, y) max_lag = length(x) - 1; lags = -max_lag:max_lag; correlation = zeros(size(lags)); for i = 1:length(lags) k = lags(i); if k >= 0 x_padded = [x, zeros(1, k)]; y_padded = [zeros(1, k), y]; else x_padded = [zeros(1, abs(k)), x]; y_padded = [y, zeros(1, abs(k))]; end % Ensure same length and compute max_len = max(length(x_padded), length(y_padded)); if length(x_padded) < max_len x_padded = [x_padded, zeros(1, max_len - length(x_padded))]; end if length(y_padded) < max_len y_padded = [y_padded, zeros(1, max_len - length(y_padded))]; end correlation(i) = sum(x_padded .* y_padded); end end ``` Purpose: Function to compute cross-correlation at all possible lags. ### Example 1: Dissimilar Signals ```matlab % Create signals x1 = [1, 2, -4, -6, 0, 1]; y1 = [2, 3, -2, 4, 5, 0]; ``` Purpose: Create the first example signals showing dissimilar patterns. ```matlab % Manual calculation at lag 0 products = x1 .* y1; % [2, 6, 8, -24, 0, 0] corr_value = sum(products); % -8 fprintf('Correlation at lag 0: %d\n', corr_value); ``` Purpose: Show element-wise multiplication and sum. ```matlab % Compute full correlation [lags1, corr1] = compute_cross_correlation(x1, y1); [min_val, min_idx] = min(corr1); fprintf('Maximum absolute correlation: %d at lag %d\n', min_val, lags1(min_idx)); ``` Purpose: Find the peak correlation value. ### Example 2: Similar Shaped Signals ```matlab % Create signals with similar shapes x2 = [1, 2, -4, -6, 0, 1]; z2 = [1, 3, -3, -4, 0, 2]; ``` Purpose: Signals with peaks and valleys that align. ```matlab % Compute correlation [lags2, corr2] = compute_cross_correlation(x2, z2); [max_val, max_idx] = max(corr2); fprintf('Maximum correlation: %d at lag %d\n', max_val, lags2(max_idx)); ``` Purpose: Find peak showing signals are most similar when aligned. ### Example 3: Pattern Detection with Time Shift ```matlab % Create signals where y pattern appears shifted within x x3 = [0, 1, 3, -1, 2, -3, 5, -2]; y3 = [2, -4, 4, -2]; ``` Purpose: Create signals where y pattern appears shifted within x. ```matlab % Compute cross-correlation [lags3, corr3] = compute_cross_correlation(x3, y3); ``` Purpose: Calculate correlation at all lags. ```matlab % Display correlation table fprintf('Cross-correlation table:\n'); fprintf('Lag: '); fprintf('%3d ', lags3); fprintf('\n'); fprintf('Corr:'); fprintf('%4.0f ', corr3); fprintf('\n'); ``` Purpose: Show correlation values at each lag. ```matlab % Find maximum correlations [max_pos_corr, max_pos_idx] = max(corr3); [max_neg_corr, max_neg_idx] = min(corr3); fprintf('Maximum positive: %.0f at lag %d\n', max_pos_corr, lags3(max_pos_idx)); fprintf('Maximum negative: %.0f at lag %d\n', max_neg_corr, lags3(max_neg_idx)); ``` Purpose: Identify peaks showing where patterns best align. ### Visualization ```matlab % Create comprehensive visualization figure; subplot(1, 3, 1); plot(lags1, corr1, 'o-', 'Color', [0 0.5 0], 'LineWidth', 2); title('Example 1: Dissimilar'); xlabel('Lag'); ylabel('Correlation'); grid on; hold on; yline(0, '--'); hold off; subplot(1, 3, 2); plot(lags2, corr2, 'o-', 'Color', [0 0 0.5], 'LineWidth', 2); title('Example 2: Similar'); xlabel('Lag'); ylabel('Correlation'); grid on; hold on; yline(0, '--'); hold off; subplot(1, 3, 3); plot(lags3, corr3, 'o-', 'Color', [0.5 0 0.5], 'LineWidth', 2); title('Example 3: Pattern shift'); xlabel('Lag'); ylabel('Correlation'); grid on; hold on; yline(0, '--'); hold off; ``` Purpose: Create correlation plots to visualize patterns. *Note: A comprehensive 2×3 visualization showing both signals and correlations is provided in the Comprehensive Visualization section below.* ## Summary and Key Insights ### ✅ Check Your Understanding: (Think about these questions before you engage with the complete visualization.) - In Example 1, where is the minimum value? What does this negative peak mean? - In Example 2, where is the maximum value? Why is it at lag 0? - In Example 3, identify both the maximum positive and maximum negative peaks. What do these two peaks tell you about the relationship between x and y? ### Results Across All Examples: - **Example 1**: Maximum negative correlation of -47 at lag -1 (signals are most dissimilar when y is advanced by 1 sample) - **Example 2**: Maximum positive correlation at lag 0 (signals are most similar without any shift) - **Example 3**: Maximum positive correlation of 40 at lag 4, maximum negative of -34 at lag 5 (pattern appears 4 samples later) ### Comprehensive Visualization ```r # Set working directory to script location for saving files if (exists("rstudioapi") && rstudioapi::isAvailable()) { script_dir <- dirname(rstudioapi::getActiveDocumentContext()$path) setwd(script_dir) cat("Working directory set to (RStudio):", script_dir, "\n") } else if (!interactive()) { # For non-interactive mode (sourcing) script_dir <- dirname(sys.frame(1)$ofile) setwd(script_dir) cat("Working directory set to (sourced):", script_dir, "\n") } else { # Fallback: just use current directory script_dir <- getwd() cat("Using current working directory:", script_dir, "\n") } # Create comprehensive visualization with all three examples output_file <- file.path(script_dir, "discrete_correlation_all_examples.png") cat("Creating PNG file at:", output_file, "\n") png(output_file, width = 1200, height = 800, res = 150) par(mfrow = c(2, 3), mar = c(4, 4, 3, 2)) # Find max positive and negative correlations for each example max_pos_idx1 <- which.max(result1$correlation) max_pos_lag1 <- result1$lags[max_pos_idx1] max_pos_corr1 <- result1$correlation[max_pos_idx1] max_neg_idx1 <- which.min(result1$correlation) max_neg_lag1 <- result1$lags[max_neg_idx1] max_neg_corr1 <- result1$correlation[max_neg_idx1] max_pos_idx2 <- which.max(result2$correlation) max_pos_lag2 <- result2$lags[max_pos_idx2] max_pos_corr2 <- result2$correlation[max_pos_idx2] max_neg_idx2 <- which.min(result2$correlation) max_neg_lag2 <- result2$lags[max_neg_idx2] max_neg_corr2 <- result2$correlation[max_neg_idx2] max_pos_idx3 <- which.max(result3$correlation) max_pos_lag3 <- result3$lags[max_pos_idx3] max_pos_corr3 <- result3$correlation[max_pos_idx3] max_neg_idx3 <- which.min(result3$correlation) max_neg_lag3 <- result3$lags[max_neg_idx3] max_neg_corr3 <- result3$correlation[max_neg_idx3] # First row: Signal plots with shifted overlays # Example 1 signals plot_range1 <- c(min(0, min(max_pos_lag1, max_neg_lag1)), max(length(x1)-1, length(y1)-1 + max(abs(max_pos_lag1), abs(max_neg_lag1)))) plot(0:(length(x1)-1), x1, type = "b", pch = 19, col = "darkgreen", lwd = 2, xlab = "Index n", ylab = "Amplitude", ylim = range(c(x1, y1)), xlim = plot_range1, main = sprintf("Example 1: Max+ lag %d (r=%.1f), Max- lag %d (r=%.1f)", max_pos_lag1, max_pos_corr1, max_neg_lag1, max_neg_corr1)) lines(0:(length(y1)-1), y1, type = "b", pch = 17, col = "darkred", lwd = 2) # Add y shifted at max positive correlation y1_pos_shifted <- (0:(length(y1)-1)) + max_pos_lag1 valid_pos <- which(y1_pos_shifted >= plot_range1[1] & y1_pos_shifted <= plot_range1[2]) if(length(valid_pos) > 0) { lines(y1_pos_shifted[valid_pos], y1[valid_pos], type = "b", pch = 17, col = rgb(0, 0.5, 0, 0.5), lwd = 2, lty = 2) } # Add y shifted at max negative correlation y1_neg_shifted <- (0:(length(y1)-1)) + max_neg_lag1 valid_neg <- which(y1_neg_shifted >= plot_range1[1] & y1_neg_shifted <= plot_range1[2]) if(length(valid_neg) > 0) { lines(y1_neg_shifted[valid_neg], y1[valid_neg], type = "b", pch = 17, col = rgb(1, 0, 0, 0.5), lwd = 2, lty = 3) } grid(col = "gray80") abline(h = 0, col = "black", lty = 2) legend("topright", legend = c("x", "y", "y at max+", "y at max-"), col = c("darkgreen", "darkred", rgb(0, 0.5, 0, 0.5), rgb(1, 0, 0, 0.5)), pch = c(19, 17, 17, 17), lty = c(1, 1, 2, 3), lwd = 2, cex = 0.7) # Example 2 signals plot(0:(length(x2)-1), x2, type = "b", pch = 19, col = "darkgreen", lwd = 2, xlab = "Index n", ylab = "Amplitude", ylim = range(c(x2, z2)), main = paste("Example 2: Signals (max at lag", max_pos_lag2, ")")) lines(0:(length(z2)-1), z2, type = "b", pch = 17, col = "darkblue", lwd = 2) # Add shifted z at maximum correlation lag z2_shifted_indices <- (0:(length(z2)-1)) + max_pos_lag2 valid_indices <- which(z2_shifted_indices >= 0 & z2_shifted_indices <= max(0:(length(x2)-1))) if(length(valid_indices) > 0) { lines(z2_shifted_indices[valid_indices], z2[valid_indices], type = "b", pch = 17, col = rgb(0, 0, 1, 0.3), lwd = 2, lty = 2) } grid(col = "gray80") abline(h = 0, col = "black", lty = 2) legend("topright", legend = c("x", "z", "z shifted"), col = c("darkgreen", "darkblue", rgb(0, 0, 1, 0.3)), pch = c(19, 17, 17), lty = c(1, 1, 2), lwd = 2, cex = 0.8) # Example 3 signals plot_range3 <- c(min(0, min(max_pos_lag3, max_neg_lag3)), max(length(x3)-1, length(y3)-1 + max(abs(max_pos_lag3), abs(max_neg_lag3)))) plot(0:(length(x3)-1), x3, type = "b", pch = 19, col = "darkgreen", lwd = 2, xlab = "Index n", ylab = "Amplitude", ylim = range(c(x3, y3)), xlim = plot_range3, main = sprintf("Example 3: Max+ lag %d (r=%.0f), Max- lag %d (r=%.0f)", max_pos_lag3, max_pos_corr3, max_neg_lag3, max_neg_corr3)) lines(0:(length(y3)-1), y3, type = "b", pch = 17, col = "darkorange", lwd = 2) # Add y shifted at max positive correlation y3_pos_shifted <- (0:(length(y3)-1)) + max_pos_lag3 lines(y3_pos_shifted, y3, type = "b", pch = 17, col = rgb(0, 0.5, 0, 0.5), lwd = 2, lty = 2) # Add y shifted at max negative correlation y3_neg_shifted <- (0:(length(y3)-1)) + max_neg_lag3 lines(y3_neg_shifted, y3, type = "b", pch = 17, col = rgb(1, 0, 0, 0.5), lwd = 2, lty = 3) grid(col = "gray80") abline(h = 0, col = "black", lty = 2) legend("topright", legend = c("x", "y", "y at max+", "y at max-"), col = c("darkgreen", "darkorange", rgb(0, 0.5, 0, 0.5), rgb(1, 0, 0, 0.5)), pch = c(19, 17, 17, 17), lty = c(1, 1, 2, 3), lwd = 2, cex = 0.7) # Second row: Cross-correlation plots # Example 1 correlation plot(result1$lags, result1$correlation, type = "b", pch = 19, col = "green", lwd = 2, xlab = "Lag k", ylab = "Cross-Correlation R_xy[k]", main = "Cross-Correlation: Dissimilar") grid(col = "gray80") abline(h = 0, col = "black") points(max_neg_lag1, max_neg_corr1, col = "red", pch = 19, cex = 2) text(max_neg_lag1 + 0.5, max_neg_corr1, paste("Max:", max_neg_corr1, "\nat lag", max_neg_lag1), col = "red", font = 2, adj = 0, cex = 0.8) # Example 2 correlation plot(result2$lags, result2$correlation, type = "b", pch = 19, col = "blue", lwd = 2, xlab = "Lag k", ylab = "Cross-Correlation R_xz[k]", main = "Cross-Correlation: Similar shapes") grid(col = "gray80") abline(h = 0, col = "black") points(max_pos_lag2, max_pos_corr2, col = "red", pch = 19, cex = 2) text(max_pos_lag2 + 0.5, max_pos_corr2, paste("Max:", max_pos_corr2, "\nat lag", max_pos_lag2), col = "red", font = 2, adj = 0, cex = 0.8) # Example 3 correlation plot(result3$lags, result3$correlation, type = "b", pch = 19, col = "purple", lwd = 2, xlab = "Lag k", ylab = "Cross-Correlation R_xy[k]", main = "Cross-Correlation: Pattern shift") grid(col = "gray80") abline(h = 0, col = "black") # Mark max positive correlation points(max_pos_lag3, max_pos_corr3, col = "green", pch = 19, cex = 2) text(max_pos_lag3 - 0.5, max_pos_corr3 - 5, paste("Max+:", max_pos_corr3, "\nat lag", max_pos_lag3), col = "green", font = 2, adj = 1, cex = 0.8) # Mark max negative correlation points(max_neg_lag3, max_neg_corr3, col = "red", pch = 19, cex = 2) text(max_neg_lag3 + 0.5, max_neg_corr3 + 5, paste("Max-:", max_neg_corr3, "\nat lag", max_neg_lag3), col = "red", font = 2, adj = 0, cex = 0.8) dev.off() cat("Visualization completed and saved!\n") cat("File saved to:", output_file, "\n") cat("File exists:", file.exists(output_file), "\n") if (file.exists(output_file)) { cat("File size:", file.info(output_file)$size, "bytes\n") } ``` Purpose: Create comprehensive visualization showing both signals and their correlations, with shifted overlays demonstrating how signals align at maximum correlation lags. Includes diagnostic output to confirm file creation. ### Interpretation of Results 1. **Example 1 (Dissimilar)**: Negative correlation peak indicates signals are opposites 2. **Example 2 (Similar shapes)**: Positive correlation at lag 0 shows signals align without shift 3. **Example 3 (Pattern detection)**: Peak at lag 4 reveals time delay between patterns Key insight: Cross-correlation reveals both **similarity** (correlation value) and **timing** (lag position)