Cross-correlation measures the similarity between two signals as a function of a time lag applied to one of them, producing a sequence (or function) whose peak location indicates the delay at which the signals most closely resemble each other. It is the sliding inner product of two signals (with complex conjugation of one operand for complex-valued signals) and is closely related to convolution, differing only in that one operand is not time-reversed.
In practice
In embedded signal processing, cross-correlation is most commonly used for time-delay estimation: given two sensor outputs that capture the same physical event (for example, two microphones picking up the same sound, or two accelerometers on a structure), the lag at which the cross-correlation peaks estimates the propagation delay between the sensors. This underpins Time Difference of Arrival (TDOA) positioning and acoustic ranging. The EmbeddedRelated post "Delay estimation by FFT" covers the frequency-domain approach to this computation.
Computing cross-correlation directly in the time domain costs O(N²) multiply-accumulate operations for an N-point signal, which is often prohibitive on constrained MCUs. For block sizes where the FFT overhead is amortized, the standard alternative is to compute it via the FFT: take the FFT of both signals, multiply one spectrum by the complex conjugate of the other, then take the inverse FFT. This reduces the cost to O(N log N) and reuses whatever FFT routine is already present in the system, though for very short blocks a direct time-domain loop may still be faster in practice. On Cortex-M4/M7 parts with a hardware FPU and DSP instructions (SIMD MAC), this approach is practical for moderate block sizes, though the exact crossover point depends on clock speed, FFT library, and data type.
A critical pitfall is that raw cross-correlation conflates true time-delay information with spectral coloring. If both signals share strong narrowband energy (a common hum, a dominant resonance), the cross-correlation will show a large, broad peak or spurious peaks unrelated to the actual delay. The EmbeddedRelated post "Correlation without pre-whitening is often misleading" addresses this directly: pre-whitening or phase-only correlation (the GCC-PHAT method) flattens the spectrum before computing the correlation, making the delay peak sharper and less susceptible to tonal interference.
On memory-limited targets, storing two full N-point buffers plus their FFTs can be a significant constraint. Designers often reduce N to fit in tightly coupled memory (TCM) or SRAM, accepting coarser lag resolution, or use overlap-add/overlap-save streaming approaches when the input is continuous rather than block-based.
Discussed on DSPRelated
Frequently asked
What is the difference between cross-correlation and convolution?
Convolution slides a time-reversed version of one signal over the other; cross-correlation slides the original (non-reversed) signal. In the
frequency domain, convolution multiplies two spectra directly (X(f) * H(f)), while cross-correlation multiplies one spectrum by the complex conjugate of the other (X(f) * conj(Y(f))). For symmetric signals the two operations yield identical results, which is a common source of confusion when using library functions.
How do I compute cross-correlation efficiently on an MCU?
The
FFT-based method is the standard approach for block sizes above roughly 32 to 64 samples: zero-pad both input blocks to at least 2N-1 points to achieve a linear (non-circular) cross-correlation, compute their FFTs, multiply one by the complex conjugate of the other pointwise, then inverse-FFT the result. Cortex-M4 and M7 parts with the CMSIS-DSP library (arm_cfft_f32, arm_cmplx_mult_cmplx_f32) make this straightforward. For very short lags on small MCUs, a direct time-domain loop may be simpler and fast enough.
Why does my cross-correlation peak look broad or have multiple peaks?
Broadening and spurious peaks are usually caused by shared narrowband energy in the two signals. A single strong tone produces a sinusoidal ripple across the entire correlation output rather than a clean impulse. Pre-whitening both signals (flattening their spectra before correlating) or using the GCC-PHAT method (dividing the cross-spectrum by its magnitude before inverse-FFT) typically produces a much sharper peak. See the EmbeddedRelated post 'Correlation without pre-whitening is often misleading' for a detailed treatment.
What is the relationship between cross-correlation and autocorrelation?
Autocorrelation is the special case of cross-correlation where both input signals are the same signal. It measures how a signal resembles a delayed copy of itself. The zero-lag autocorrelation value equals the signal's total energy. Cross-correlation generalizes this to two distinct signals. The EmbeddedRelated post 'Autocorrelation and the case of the missing fundamental' shows a practical example of what autocorrelation reveals about periodic structure in a signal.
How does lag resolution relate to sample rate, and can I achieve sub-sample delay estimates?
The base grid spacing of a discrete cross-correlation is one sample period (1/
fs), so a 16 kHz system resolves delays to about 62.5 µs on the integer-lag grid. Sub-sample resolution is achievable by interpolating around the correlation peak, for example by fitting a parabola to the three samples nearest the peak and solving for the fractional maximum.
Phase-based methods (GCC-PHAT) can also yield sub-sample estimates from the slope of the unwrapped cross-spectrum phase.
Differentiators vs similar concepts
Cross-correlation is frequently confused with
convolution. The operations are nearly identical in implementation but differ in sign convention: convolution folds (time-reverses) one signal before sliding, while cross-correlation does not. In the
frequency domain this means convolution uses X(f) * H(f) and cross-correlation uses X(f) * conj(Y(f)). Cross-correlation is also distinct from coherence: coherence is the normalized cross-spectral density (bounded 0 to 1) and indicates how linearly related two signals are at each frequency, whereas cross-correlation operates in the time/lag domain and is not normalized unless explicitly divided by the geometric mean of the two autocorrelations (yielding the cross-correlation coefficient).