Delay-and-Sum Beamforming, End to End
A single microphone hears everything in a room equally — the talker you want, the air-conditioning you don't, and every reflection in between. Put several microphones together as an array, and you gain something a single sensor can never have: a sense of direction. Delay-and-sum (DAS) beamforming is the simplest way to exploit it, and it's the foundation almost every more advanced spatial filter builds on.
The intuition
A sound arriving from an angle reaches the microphones at slightly different times. A wavefront coming from broadside (straight ahead) hits every element at once; one arriving from the side reaches the nearest microphone first and the farthest last. That tiny time difference is the entire signal a beamformer works with.
Delay-and-sum does exactly what its name says: it delays each microphone signal so the wavefront from the direction you care about lines up, then sums. Signals from the target direction add constructively; everything else partially cancels.
The geometry
For a uniform linear array with spacing d between elements and a far-field source at angle θ (measured from broadside), the extra distance the wave travels between adjacent microphones is d·sin θ. Dividing by the speed of sound c ≈ 343 m/s gives the inter-element delay:
In the frequency domain a delay is a phase shift, so the response of microphone n to a plane wave at frequency f is captured by the steering vector:
The steering vector is the whole game. To steer the array toward an angle, you weight each channel by the conjugate of its steering vector and average — that is delay-and-sum, written in the frequency domain.
Forty lines of NumPy
Here is a complete, runnable beamformer: build the steering vector, then sweep angles to compute the array's spatial response (its beampattern).
import numpy as np c = 343.0 # speed of sound (m/s) N = 8 # number of microphones d = 0.04 # spacing (m) ~ λ/2 at ~4.3 kHz f = 2000.0 # analysis frequency (Hz) mics = np.arange(N) * d def steering_vector(theta_deg): theta = np.deg2rad(theta_deg) delays = mics * np.sin(theta) / c return np.exp(-1j * 2 * np.pi * f * delays) def beampattern(steer_deg, angles): w = steering_vector(steer_deg) / N # DAS weights return np.array([np.abs(np.vdot(w, steering_vector(a))) for a in angles]) angles = np.linspace(-90, 90, 361) gain = beampattern(steer_deg=35, angles=angles) # gain peaks at 35° — the array is now "listening" that way
That gain array is the same curve the live demo on our homepage animates: a tall main lobe pointed at the steer angle, flanked by smaller side lobes. The main lobe is the directions you amplify; the side lobes are the leakage you'd rather not have.
Resolution, spacing, and aliasing
Two design numbers dominate everything:
- Beamwidth ∝ λ / (N·d). A bigger aperture — more elements, or wider spacing — gives a narrower main lobe and sharper directional resolution. Low frequencies (long λ) are inherently harder to resolve, which is why small arrays struggle with bass.
- Spacing must satisfy d ≤ λ/2. Go wider and the array can no longer tell certain angles apart: a second full-height main lobe — a grating lobe — appears at the wrong direction. This is spatial aliasing, the exact analogue of Nyquist in time.
Rule of thumb: pick element spacing at half a wavelength of the highest frequency you need to steer cleanly. At 4.3 kHz that's about 4 cm; above it, expect grating lobes unless you compensate in software.
Where delay-and-sum stops
DAS is robust, cheap, and never does anything surprising — but it's data-independent. It places the same fixed beam regardless of where the noise actually is. If an interferer sits squarely in a side lobe, DAS has no way to null it.
That's the point where adaptive beamformers earn their keep. MVDR (minimum-variance distortionless response) uses the measured spatial covariance to steer nulls toward interference while keeping unit gain on the target. It can dramatically outperform DAS — at the cost of needing a reliable covariance estimate and careful regularisation, which is where real engineering effort goes.
In practice we usually start a project with DAS as a baseline that is guaranteed to work, then move to MVDR or superdirective designs only where the measured improvement justifies the added fragility. The published research behind this studio — including multichannel TOA/DOA estimation and acoustic-echo work — lives in exactly that territory: getting reliable direction and timing estimates out of arrays in noisy, reverberant rooms.
Takeaway
Delay-and-sum is fifty lines of code and a single idea — align, then sum — yet it already exposes every tension in array processing: aperture versus resolution, spacing versus aliasing, robustness versus adaptivity. Get comfortable here and the advanced methods stop looking like magic and start looking like principled trade-offs.