Array signal processing

Direction of arrival, on hardware that has no room for a BLAS.

MUSIC and ESPRIT are eigendecomposition in a latency budget. The array covariance matrix has to be decomposed, the signal and noise subspaces split, and the spectrum scanned — inside a frame, on a board that has to fit and draw the power it is allowed, producing a result that will later have to be qualified. This is the one workload that needs all four VVE advantages at the same time.

Wilkinson, N=16,383

89.6×


vs single-threaded reference netlib LAPACK dsyev (the default dense path) — wilkinson, N = 16,383

Wilkinson, N = 45,056

5.16×


vs LAPACK's own expert O(N²) routine, single-threaded dstemr (MRRR)

libvve.so

1.4MB


libvve.so, zero external dependencies

x86_64 ≡ aarch64


identical bits, same source

Where the eigensolver sits.

Signal-processing pipelineThe signal chain from array snapshots to a direction estimate. Every stage but one is cheap and predictable. The symmetric eigendecomposition of the covariance matrix is the stage that sets the latency, the memory footprint and the qualification cost of the whole chain.Array snapshotsCovariance REigendecomposition of RSignal / noise subspace splitMUSIC / ESPRIT spectrum
The signal chain from array snapshots to a direction estimate. Every stage but one is cheap and predictable.

Snapshot averaging, spatial smoothing and the spectral scan are all well-behaved. The eigendecomposition is the block that grows with the array, pulls in a numerical library, and produces the number that has to be identical next year on next year's board.

Four requirements. Four advantages.

Array signal-processing requirements and the corresponding VVE advantage.
The workload requiresVVE answers with
A frame-rate latency budget.Structure-aware O(N²) routing — 89.6× vs single-threaded reference netlib dsyev at N = 16,383, and up to 5.16× vs single-threaded LAPACK dstemr on clustered spectra; both comparisons are single-threaded on both sides.
A board with no room for a tuned BLAS.1.4 MB, zero external dependencies. Runtime dependencies are libc, libm and libpthread. x86_64 and aarch64 from the same source.
Evidence that survives qualification.Bit-identical output across machine, architecture, compiler and hardware generation — 96 SHA-256 records across 12 groups, zero mismatches, 541 / 541 across CPU generations.
Correlated sources.Clustered spectra are where VVE's margin is largest and where it holds at every size measured — the wilkinson and schrödinger families in the campaign.

Why correlated sources favour this solver.

Subspace methods need a clean split between the signal eigenvalues and the noise floor. Correlated and coherent arrivals collapse that separation — the signal eigenvalues bunch, and the classical response is to spend more work resolving them. MRRR resolves a cluster by refining its representation tree, and that refinement is exactly where its cost goes up. VVE's routing does not pay that penalty, which is why the two clustered families in the campaign are the two where it wins at every size measured.

Well separated and clustered eigenvalue laddersTwo eigenvalue ladders on the same axis. The left is evenly spaced. The right has several near-coincident values, the pattern correlated arrivals produce.well separatedclustered — correlated sources
Two eigenvalue ladders on the same axis. The left is evenly spaced. The right has several near-coincident values, the pattern correlated arrivals produce.

Scoped to this workload.

Wilkinson, N=16,383

89.6×


vs single-threaded reference netlib LAPACK dsyev (the default dense path) — wilkinson, N = 16,383, full decomposition

Full decomposition, N=45,056, Wilkinson spectrum

5.16×


vs LAPACK's own expert O(N²) routine, single-threaded dstemr (MRRR) — wilkinson, N = 45,056, accuracy gated on both sides

Wilkinson, N=45,056, wall clock

171.1s


dstemr vs VVE, wilkinson, N = 45,056, both single-threaded

96 / 96


SHA-256 records identical across x86_64 ≡ aarch64 and GCC ≡ Clang

The full measured record →

Two ways in.

Drop in

Zero code changes. Preload the library and the covered routines are served by VVE: dsyev · dsyevd · dsyevr · dgesdd · dgesvd · dstev. Python through vvepy. This is the speed path.

LD_PRELOAD=libvve.so ./your_doa_pipeline

Bands-native

One small code change, and the dense buffer never exists. You pass the diagonal and the off-diagonal directly. This is the memory path, and it is what makes large arrays fit in a board's memory budget rather than a server's.

/* pass D and E — no dense N×N is ever allocated */
vve_eigen_values_tridiag(D, E, N, W);

Send us your array geometry.

Array size, snapshot count, source correlation, target board and instruction set. We will run your case on the harness and send the numbers back with the build, so the first result you see comes from your problem rather than ours.