Matching Pickup Tones with Cross-Correlation
You’ve spent hours winding copper wire around bobbins, adjusting the turns per layer, trying to recreate that elusive 1957 PAF humbucker tone. But how do you know when you’re close? Seth Lover didn’t have digital analysis tools—he relied on his ears and intuition. We have cross-correlation.
Cross-correlation measures how similar two signals are by sliding one past the other and computing their overlap at each position. In pickup analysis, you can correlate your wound pickup’s frequency response against a reference signal from a vintage PAF recording.
float cross_correlate(float* signal_a, float* signal_b, int n, int lag) {
float sum = 0.0f;
for (int i = 0; i < n - abs(lag); i++) {
int idx = (lag >= 0) ? i : i - lag;
sum += signal_a[idx] * signal_b[i + ((lag >= 0) ? lag : 0)];
}
return sum / (n - abs(lag));
}
The C version prioritises raw speed—essential when processing thousands of frequency bins from an oscilloscope capture. But sometimes clarity trumps performance:
function correlate(sig_a, sig_b, lag)
local sum, count = 0, 0
for i = 1, math.min(#sig_a, #sig_b) do
local a_idx = i
local b_idx = i + lag
if a_idx >= 1 and a_idx <= #sig_a and b_idx >= 1 and b_idx <= #sig_b then
sum = sum + sig_a[a_idx] * sig_b[b_idx]
count = count + 1
end
end
return count > 0 and sum / count or 0
end
The beauty lies in the lag parameter—it lets you find the best match even when signals are slightly out of phase. A high correlation coefficient means your pickup’s voice matches the reference. Low correlation? Time to adjust your wire gauge or magnet strength.
Cross-correlation revolutionised radar and communications in the 1970s, but its principles apply wherever you need to match one pattern against another. Whether you’re winding pickups or analyzing radio signals, you’re asking the same fundamental question: how similar are these two things?