# 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:
- 
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.

### 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)