Eigendecomposition & SVD
The singular value decomposition splits any matrix into orthogonal input directions, gains and orthogonal output directions. That one factorization gives you the best low-rank approximation, the stable pseudo-inverse, PCA, and the spatiotemporal clutter filter that is the first stage of most ULM pipelines. The same tool, applied to a distortion matrix, gives the aberration phase law.
You will be able to
- Find eigenvalues and eigenvectors, and say when they are real and orthogonal (spectral theorem)
- Read the SVD geometrically and relate \(\sigma_{i}\) to \(\operatorname{eig} (\mathbf{A}^{H}\mathbf{A})\), rank, \(\lVert \cdot \rVert_{2}, \lVert \cdot \rVert_{F}\) and κ
- Build and bound the best rank-k approximation (Eckart–Young)
- Build a Casorati matrix from an IQ ensemble, choose SVD cutoffs and explain why the filter survives tissue motion when a temporal high-pass fails
06.1Eigenvectors: the directions a matrix does not turn
A square matrix \(\mathbf{A}\) maps most vectors to a new direction. An eigenvector is a non-zero vector whose direction survives: the matrix only scales it, by the eigenvalue λ.
- \(\mathbf{A}\)
- square \(n \times n\) matrix (e.g. a covariance or a linear map)
- \(\mathbf{v}\)
- eigenvector (nonzero); direction left unchanged by \(\mathbf{A}\)
- \(\lambda\)
- eigenvalue: the scale factor applied to \(\mathbf{v}\)
- \(\mathbf{I}\)
- identity matrix
- \(\mathbf{0}\)
- zero vector
- \(\Leftrightarrow\)
- if and only if
- \(\det\)
- determinant
- \(a,\ b,\ c,\ d\)
- entries of \(\mathbf{A}\) (rows [a b], [c d])
- \(\tau,\ \delta\)
- trace and determinant
- \(\Delta\)
- discriminant: > 0 two real, = 0 repeated, < 0 complex pair
- \(\mathbf{A}\)
- 2 × 2 matrix, as in (06.1)
- \(\lambda_{1,2}\)
- the two eigenvalues
- \(\operatorname{tr}\)
- trace (sum of the diagonal entries)
- \(\det\)
- determinant
- \(\sqrt{\cdot}\)
- square root (imaginary if the argument is negative)
If \(\mathbf{A}\) has n independent eigenvectors, stack them as columns of \(\mathbf{X}\): \(\mathbf{AX} = \mathbf{X}\Lambda\), so \(\mathbf{A} = \mathbf{X}\Lambda \mathbf{X}^{-1}\). In the eigenvector basis the matrix acts as n independent scalar gains, which is why powers and functions are easy: \(\mathbf{A}^{k} = \mathbf{X}\Lambda^{k}\mathbf{X}^{-1}\).
The Hermitian case: spectral theorem
When \(\mathbf{A} = \mathbf{A}^{H}\) (real symmetric, or complex Hermitian, such as every covariance matrix in Module 07), two short derivations settle everything.
- \(\mathbf{A}\)
- Hermitian matrix, \(\mathbf{A}^{H}=\mathbf{A}\)
- \(\mathbf{v},\ \lambda\)
- eigenvector and eigenvalue, as in (06.1)
- \((\cdot)^{H}\)
- conjugate transpose
- \(\bar{\lambda}\)
- complex conjugate of \(\lambda\)
- \(\lVert\cdot\rVert\)
- 2-norm (length)
- \(\Rightarrow\)
- implies; \(\lambda=\bar\lambda\) means \(\lambda\) is real
- \(\mathbf{A}\)
- Hermitian matrix
- \(\mathbf{v}_1,\ \mathbf{v}_2\)
- eigenvectors with eigenvalues \(\lambda_1 e\lambda_2\)
- \(\lambda_1,\ \lambda_2\)
- distinct real eigenvalues
- \((\cdot)^{H}\)
- conjugate transpose
- \(\mathbf{v}_2^{H}\mathbf{v}_1\)
- inner product; zero means orthogonal
- \(\mathbf{A} = \mathbf{A}^{H}\)
- Hermitian n × n matrix (e.g. a channel covariance)
- \(\mathbf{q}_i\)
- orthonormal eigenvectors (columns of \(\mathbf{Q}\))
- \(\lambda_i\)
- real eigenvalues; variances along \(\mathbf{q}_i\) for a covariance
- \(\Lambda\)
- diagonal matrix of the \(\lambda_i\)
- \(\mathbf{Q}\)
- unitary matrix whose columns are \(\mathbf{q}_i\)
- \(\mathbf{I}\)
- identity matrix
- \(\mathbf{q}_i\mathbf{q}_i^{H}\)
- rank-one projector onto \(\mathbf{q}_i\)
- \((\cdot)^{H}\)
- conjugate transpose
- \(\mathbb{R}\)
- the real numbers
For a non-symmetric matrix none of this is guaranteed: eigenvectors can be oblique (the angle between them can approach 0°, making \(\mathbf{X}\) ill-conditioned), eigenvalues can be complex, and the matrix can be defective (fewer than n eigenvectors). Shears and propagation operators with loss are typical examples. That fragility is why the SVD, which always exists with orthonormal bases on both sides, is the workhorse.
Invariant directions of a 2×2 matrix
Exact formulaPower iteration: how eigenvectors are found
Repeatedly applying \(\mathbf{A}\) amplifies the component along the dominant eigenvector. Write \(\mathbf{x}_{0} = \sum c_{i}\mathbf{q}_{i}\); then
- \(\mathbf{x}_0 = \sum c_i\mathbf{q}_i\)
- start vector expanded in the eigenvectors
- \(\mathbf{x}_k\)
- normalized iterate after k products
- \(\lvert\lambda_2/\lambda_1\rvert\)
- gap ratio, sets the convergence rate
- \(\mathbf{A}\)
- Hermitian matrix with dominant eigenpair \((\lambda_1,\mathbf{q}_1)\)
- \(k\)
- number of matrix products (iteration count)
- \(c_i\)
- expansion coefficients of \(\mathbf{x}_0\)
- \(\lambda_i,\ \mathbf{q}_i\)
- eigenvalues (ordered \(\lvert\lambda_1 vert>\lvert\lambda_2 vert\ge\dots\)) and eigenvectors, as in (06.5)
- \(\angle(\mathbf{x}_k,\mathbf{q}_1)\)
- angle between the iterate and \(\mathbf{q}_1\), rad
- \(O(\cdot)\)
- decays at the order of the argument
- \(\tan\)
- tangent
Power iteration convergence on an 8×8 symmetric matrix
SimulationPower iteration on an 8×8 symmetric matrix with prescribed eigenvalues and a seeded random start vector (JS).The eigenvectors of the channel covariance matrix \(\mathbf{R} = E[\mathbf{x} \mathbf{x}^{H}]\) (Hermitian, Module 07) split the aperture data into a coherent signal subspace and an incoherent noise subspace. Eigenspace-based beamformers project the minimum-variance weights onto the dominant eigenvectors, and the fraction \(\lambda_{1}/\sum \lambda_{i}\) is a coherence measure (the eigenvalue analogue of the coherence factor). Because \(\mathbf{R}\) is Hermitian, those eigenvalues are real powers and the eigenvectors are orthogonal aperture patterns.
Eigenvalues of a non-symmetric matrix can be hypersensitive. The shear [[1, ε],[0, 1]] has a double eigenvalue 1 for every ε, but [[1, ε],[δ, 1]] has \(\lambda = 1 \pm \sqrt{\varepsilon \delta}\): a perturbation \(\delta = 10^{-10}\) with ε = 1 moves λ by \(10^{-5}\). Singular values never do this: \(\lvert \sigma_{i}(\mathbf{A}+\mathbf{E}) - \sigma_{i}(\mathbf{A})\rvert \le \lVert \mathbf{E}\rVert_{2}\) (Weyl).
06.2The SVD: rotate, stretch, rotate
Every matrix \(\mathbf{A} \in \mathbb{C}^{m\times n}\), square or not, full rank or not, factors as
- \(\mathbf{A} \in \mathbb{C}^{m\times n}\)
- any matrix, r = rank A
- \(\mathbf{U},\ \mathbf{V}\)
- unitary, m × m and n × n; columns \(\mathbf{u}_i\) (output) and \(\mathbf{v}_i\) (input) singular vectors
- \(\Sigma\)
- m × n diagonal, singular values \(\sigma_i \ge 0\)
- \(\mathbf{A}\mathbf{v}_i = \sigma_i\mathbf{u}_i\)
- the defining relation
- \(\sigma_i\)
- singular values, ordered, \(\sigma_i\ge 0\)
- \(\mathbf{u}_i,\ \mathbf{v}_i\)
- left and right singular vectors (columns of \(\mathbf{U}\), \(\mathbf{V}\))
- \(r\)
- rank of \(\mathbf{A}\), number of nonzero \(\sigma_i\)
- \((\cdot)^{H}\)
- conjugate transpose
Existence in three lines. \(\mathbf{A}^{H}\mathbf{A}\) is Hermitian and positive semidefinite, so the spectral theorem gives \(\mathbf{A}^{H}\mathbf{A} = \mathbf{V}\Lambda \mathbf{V}^{H}\) with \(\lambda_{i} \ge 0\). Define \(\sigma_{i} = \sqrt{\lambda_{i}}\) and, for \(\sigma_{i} > 0, \mathbf{u}_{i} = \mathbf{Av}_{i}/\sigma_{i}\). These \(\mathbf{u}_{i}\) are orthonormal:
- \(\mathbf{u}_i,\ \mathbf{v}_i,\ \sigma_i\)
- singular vectors and values, as in (06.7)
- \(\mathbf{A}^{H}\mathbf{A}\)
- Gram matrix with \(\mathbf{A}^{H}\mathbf{A}\mathbf{v}_j=\lambda_j\mathbf{v}_j\), \(\lambda_j=\sigma_j^{2}\)
- \(\lambda_j\)
- eigenvalue of \(\mathbf{A}^{H}\mathbf{A}\)
- \(\delta_{ij}\)
- Kronecker delta: 1 if \(i=j\), else 0
- \((\cdot)^{H}\)
- conjugate transpose
Geometrically, \(\mathbf{V}^{H}\) rotates the input so the right singular vectors \(\mathbf{v}_{i}\) land on the coordinate axes, \(\Sigma\) stretches axis i by \(\sigma_{i}\), and \(\mathbf{U}\) rotates the result into the output space. The unit sphere becomes an ellipsoid with semi-axes \(\sigma_{i}\mathbf{u}_{i}\), and \(\mathbf{Av}_{i} = \sigma_{i}\mathbf{u}_{i}\) is the defining relation.
Circle → VH → Σ → U → ellipse
Exact formulaWhat the singular values tell you
| Quantity | In terms of the SVD | Why |
|---|---|---|
| \(\sigma_{i}^{2}\) | \(\operatorname{eig} (\mathbf{A}^{H}\mathbf{A})\) = non-zero \(\operatorname{eig} (\mathbf{AA}^{H})\) | \(\mathbf{A}^{H}\mathbf{A}\) \(= \mathbf{V}\Sigma^{H}\Sigma \mathbf{V}^{H}\), \(\mathbf{AA}^{H} = \mathbf{U}\Sigma \Sigma^{H}\mathbf{U}^{H}\) |
| Column / row spaces | \(\operatorname{range} \mathbf{A}\) \(= \operatorname{span} (\mathbf{u}_{1..r})\), \(\operatorname{null} \mathbf{A}\) \(= \operatorname{span} (\mathbf{v}_{r+1..n})\) | the four fundamental subspaces of Module 05, with orthonormal bases |
| rank | number of \(\sigma_{i} > 0\) (numerically: > \(\mathrm{tol} \cdot \sigma_{1}\)) | each term \(\sigma_{i}\mathbf{u}_{i}\mathbf{v}_{i}^{H}\) is rank 1 |
| \(\lVert \mathbf{A}\rVert_{2}\) | \(\sigma_{1}\) | max gain over unit inputs = longest ellipse axis |
| \(\lVert \mathbf{A}\rVert_{F}^{2}\) | \(\sum \sigma_{i}^{2}\) | \(\lVert \cdot \rVert_{F}\) is unitarily invariant: \(\lVert \mathbf{U}\Sigma \mathbf{V}^{H}\rVert_{F}\) \(= \lVert \Sigma \rVert_{F}\) |
| \(\kappa_{2}(\mathbf{A})\) | \(\sigma_{1}/\sigma_{n}\) | ellipse aspect ratio; relative error amplification in least squares (Module 05) |
| \(\lvert \det \mathbf{A}\rvert\) (square) | \(\prod \sigma_{i}\) | area/volume scale; \(\lvert \prod \lambda_{i}\rvert = \prod \sigma_{i}\) |
For a Hermitian positive semidefinite matrix the SVD and the eigendecomposition coincide (\(\sigma_{i} = \lambda_{i}, \mathbf{U} = \mathbf{V} = \mathbf{Q}\)). For a Hermitian indefinite matrix \(\sigma_{i} = \lvert \lambda_{i}\rvert\) and the sign moves into \(\mathbf{U}\). For a non-normal matrix the two are unrelated in general: in Demo 06.1, the shear preset has λ = 1, 1 but σ = 1.62, 0.62.
Think of \(\mathbf{A}\) as a bank of n orthogonal “input beams” \(\mathbf{v}_{i}\), each received on its own orthogonal “output beam” \(\mathbf{u}_{i}\) with gain \(\sigma_{i}\) and no cross-talk. The SVD is the only basis pair that fully decouples the operator. For a transmit-receive matrix this is literally the DORT picture: \(\mathbf{v}_{1}\) is the transmit apodization-and-phase law that delivers the most energy back to the array, and \(\mathbf{u}_{1}\) is its received wavefront.
06.3Low-rank approximation and Eckart–Young
Truncating the dyadic sum after k terms gives \(\mathbf{A}_{k}\) \(= \sum_{i\le k}\sigma_{i}\mathbf{u}_{i}\mathbf{v}_{i}^{H}\). Its error follows directly from unitary invariance:
- \(\mathbf{A}_k = \sum_{i\le k}\sigma_i\mathbf{u}_i\mathbf{v}_i^{H}\)
- truncated SVD, rank k
- \(\lVert\cdot\rVert_F\)
- Frobenius norm, \(\lVert\mathbf{A}\rVert_F^{2} = \sum\sigma_i^{2}\) (total energy)
- \(\lVert\cdot\rVert_2\)
- spectral norm, the largest gain \(\sigma_1\)
- \(\mathbf{A}\)
- matrix with SVD as in (06.7)
- \(\sigma_i,\ \mathbf{u}_i,\ \mathbf{v}_i\)
- singular values and vectors
- \(k\)
- retained rank
- \(\sigma_{k+1}\)
- first discarded singular value
- \(\mathbf{A}\)
- matrix to approximate
- \(\mathbf{B}\)
- any trial matrix
- \(\operatorname{rank}\mathbf{B}\le k\)
- constraint: at most \(k\) independent columns
- \(\min\)
- smallest value over all admissible \(\mathbf{B}\)
- \(\mathbf{A}_k\)
- truncated SVD, as in (06.9)
- \(\lVert\cdot\rVert\)
- matrix norm: spectral \(\lVert\cdot Vert_2\) or Frobenius \(\lVert\cdot Vert_F\)
Energy captured is \(\sum_{i\le k}\sigma_{i}^{2}/\sum \sigma_{i}^{2}\). Storage drops from mn to k(m + n + 1) numbers. A matrix is compressible exactly when its singular values decay fast; a matrix of i.i.d. noise has no dominant singular values (they fill the Marchenko–Pastur bulk \(\sigma (\sqrt{m}- \sqrt{n}) \dots \sigma (\sqrt{m}+ \sqrt{n})\) with no gap) and cannot be compressed. The demo makes that point with speckle.
Rank-k approximation of a 96×96 B-mode-like phantom
SimulationSynthetic 96×96 phantom (layers, cyst, points) with seeded fully developed speckle, log-compressed to 40 dB; SVD computed in the page.A rank-1 term is a separable pattern: spatial map × temporal course, or depth profile × lateral profile. Tissue moving rigidly is close to separable over a short ensemble; that single observation is the basis of the SVD clutter filter in 06.5. Conversely, “rank” is basis-dependent: a slanted layer or a lateral translation spreads energy over many ranks, which is the failure mode you will see when tissue moves fast.
06.4PCA, the pseudo-inverse and truncated SVD
PCA is the SVD of centered data
Stack N observations of a p-dimensional vector as rows of \(\mathbf{X} (N\times p)\) and remove the column means. The sample covariance and its eigendecomposition follow from the SVD of \(\mathbf{X}\):
- \(\mathbf{X}\)
- N × p data matrix, one observation per row, column means removed
- \(\mathbf{C}\)
- p × p sample covariance
- \(\mathbf{U},\ \Sigma,\ \mathbf{V}\)
- SVD factors, as in (06.7)
- \(N\)
- number of observations (rows of \(\mathbf{X}\))
- \(N-1\)
- unbiased-estimator normalization
- \((\cdot)^{H}\)
- conjugate transpose
- \(\Sigma^{2}\)
- diagonal matrix of \(\sigma_i^{2}\); \(\sigma_i^{2}/(N-1)\) are the covariance eigenvalues (variances along the principal axes \(\mathbf{v}_i\))
Pseudo-inverse and the cost of small σ
- \(\mathbf{A}^{+}\)
- Moore–Penrose pseudoinverse
- \(\Sigma^{+}\)
- diagonal matrix with \(1/\sigma_i\) for the nonzero \(\sigma_i\), zeros elsewhere
- \(\mathbf{U},\ \mathbf{V},\ \sigma_i,\ r\)
- SVD factors and rank, as in (06.7)
- \(\operatorname{diag}\)
- diagonal matrix from a list
- \(\mathbf{b}\)
- data vector
- \(\mathbf{x}^{+}\)
- minimum-norm least-squares solution of \(\mathbf{A}\mathbf{x}=\mathbf{b}\)
- \(\mathbf{b}\)
- measured data (signal + noise)
- \(\mathbf{u}_i^{H}\mathbf{b}\)
- data coefficient i (Picard plot)
- \(k\)
- truncation index (0/1 filter)
- \(\alpha\)
- Tikhonov parameter, same units as \(\sigma_i\); filter ½ at \(\sigma_i = \alpha\)
- \(\mathbf{x}_k\)
- truncated-SVD solution (keeps the first \(k\) terms)
- \(\mathbf{x}_\alpha\)
- Tikhonov solution
- \(\sigma_i,\ \mathbf{u}_i,\ \mathbf{v}_i\)
- SVD quantities, as in (06.7)
- \(\sigma_i^{2}/(\sigma_i^{2}+\alpha^{2})\)
- Tikhonov filter factor (smooth 0-to-1 version of truncation)
Truncated-SVD deconvolution of a blurred reflectivity profile
Simulation64-sample Gaussian blur matrix and seeded white noise; SVD, truncation and Picard coefficients computed in the page.Model-based sound-speed tomography and aberration estimation solve \(\mathbf{b} = \mathbf{Ax}\) with an \(\mathbf{A}\) whose singular values decay fast (limited angular aperture, smooth slowness kernels). Truncated SVD and Tikhonov are the baseline regularizers; their spectral-filter form is how you reason about which slowness patterns a given aperture can and cannot recover.
“Rank” in floating point is a threshold decision. MATLAB's rank and pinv default to tol = \(\max (m,n)\cdot \varepsilon \cdot \sigma_{1} \approx 10^{-14}\sigma_{1}\), which suits exact data and is far too small for measured data. Set the threshold from the noise level, not from machine precision.
06.5The SVD clutter filter
An ultrafast ensemble is a stack of n compounded IQ frames s(x, z, t) at frame rate PRF, typically 0.5–5 kHz over 50–400 ms. Reshape each frame into a column of \(N_{x}N_{z}\) pixels: the result is the Casorati matrix
- \(N_xN_z\)
- pixels per frame (rows)
- \(n\)
- frames in the ensemble (columns), at frame rate PRF
- \(s(x,z,t)\)
- compounded IQ sample
- \(\mathbf{u}_k,\ \mathbf{v}_k\)
- spatial and temporal singular vectors
- \(\mathbf{S}\)
- space-time (Casorati) matrix, pixels × frames
- \(S_{pt}\)
- entry for pixel \(p\) at frame \(t\)
- \(p,\ t\)
- pixel index and frame index
- \(x_p,\ z_p\)
- lateral and axial position of pixel \(p\), mm
- \(\sigma_k\)
- singular values of \(\mathbf{S}\) (energy of component \(k\))
- \((\cdot)^{H}\)
- conjugate transpose
- \(\mathbb{C}\)
- the complex numbers (IQ data)
Demené et al. (2015) showed that the three signal classes separate along k because they differ in energy and in spatiotemporal coherence:
| Class | Energy | Coherence | Where in the spectrum |
|---|---|---|---|
| Tissue clutter | 40–60 dB above blood | large region moves together, slowly (mm/s) → nearly separable | first few \(\sigma_{k}\), low-Doppler \(\mathbf{v}_{k}\) |
| Blood / microbubbles | low | small structures, fast (cm/s), decorrelate over a few frames | middle ranks, higher-Doppler \(\mathbf{v}_{k}\) |
| Electronic noise | lowest | i.i.d. in space and time → no coherent structure | tail: a slowly sloping plateau (the Marchenko–Pastur bulk, edge \(\sigma_{n}(\sqrt{m}+ \sqrt{n})\)) |
The filter keeps the band \([k_{\mathrm{lo}}, k_{\mathrm{hi}}]\). With \(\mathbf{V}_{b}\) the band's right singular vectors:
- \(k_{\mathrm{lo}},\ k_{\mathrm{hi}}\)
- first and last kept rank (tissue below, noise above)
- \(\mathbf{V}_b\)
- n × (k_hi − k_lo + 1) matrix of the kept temporal singular vectors
- \(\mathbf{S}_f\)
- filtered ensemble (pixels × frames), input to power Doppler or ULM
- \(\sigma_k,\ \mathbf{u}_k,\ \mathbf{v}_k\)
- singular values and vectors of \(\mathbf{S}\), as in (06.14)
- \(\mathbf{S}\)
- Casorati matrix, as in (06.14)
- \(k\)
- component (rank) index
- \((\cdot)^{H}\)
- conjugate transpose
- \(\mathrm{PD}(p)\)
- power Doppler value at pixel \(p\), power (arbitrary units)
- \(p\)
- pixel index
- \(t\)
- frame index (slow time)
- \(n\)
- number of frames, as in (06.14)
- \(S_f(p,t)\)
- filtered ensemble entry, as in (06.15)
- \(\lvert\cdot\rvert\)
- magnitude of a complex number
- \(\sigma_k,\ u_k(p),\ k_{\mathrm{lo}},\ k_{\mathrm{hi}}\)
- singular values, spatial singular vector entry at \(p\), and kept ranks, as in (06.15)
Why a high-pass fails under motion. Tissue moving at axial velocity \(v_{z}\) produces Doppler \(f_{D} = 2v_{z}/\lambda\): at 5 MHz (λ = 0.308 mm), 6 mm/s gives 39 Hz and 15 mm/s gives 97 Hz, which overlaps slow flow (a 2 mm/s capillary-scale flow gives 13 Hz; a 15 mm/s arteriole along the beam gives 97 Hz). A high-pass with cutoff below the tissue Doppler passes tissue; one above it removes slow blood. The SVD does not rely on frequency alone: tissue at the same Doppler as blood is still captured in the top ranks because it moves coherently over the whole field of view.
SVD clutter filter on a simulated ultrafast IQ ensemble
SimulationOwn IQ ensemble simulation in JS: 2600 tissue scatterers and three parabolic-flow vessels through a Gaussian PSF (σx 0.17 mm, σz 0.10 mm), 5 MHz, PRF 1 kHz; SVD via the frames × frames Gram matrix; high-pass = 2nd-order Butterworth, zero phase. No acoustic propagation or attenuation.The singular value curve rarely shows a clean knee. Failure modes: \((1) k_{\mathrm{lo}}\) too low leaves tissue residue that looks like flow, worst near bright, moving interfaces; \((2) k_{\mathrm{lo}}\) too high removes slow flow and large vessels, whose spatial singular vectors are themselves coherent; (3) tissue motion that is non-rigid (cardiac, breathing over a long ensemble) spreads tissue over many ranks so no single \(k_{\mathrm{lo}}\) works, which is why practice uses short ensembles, blockwise (local) SVD, or motion correction first; \((4) k_{\mathrm{hi}}\) too high adds noise, which also inflates PD at depth where noise dominates. Data-driven rules exist: the knee of the curve, the temporal singular vectors' Doppler content (as in this demo), or the similarity of the spatial singular vectors (Baranger et al. 2018), which groups ranks whose \(\lvert \mathbf{u}_{k}\rvert\) maps look alike.
In ULM the same filter runs on 200–800 frames at 0.5–1 kHz with microbubbles in the middle ranks. The filtered ensemble \(\mathbf{S}_{f}\) (not its power) is what the localization step sees: each frame of \(\mathbf{S}_{f}\) should contain isolated bubble PSFs on a tissue-free background. Residual tissue produces false localizations; an aggressive \(k_{\mathrm{lo}}\) deletes slow bubbles in capillaries, biasing velocity maps toward fast vessels. Computationally, n is small (hundreds) while \(N_{x}N_{z}\) is large (\(10^{5}\)), so implementations take the eigendecomposition of the n×n Gram matrix \(\mathbf{S}^{H}\mathbf{S} = \mathbf{V}\Sigma^{2}\mathbf{V}^{H}\) and then form \(\mathbf{S} \mathbf{V}_{b}\mathbf{V}_{b}^{H}\). This squares κ: in double precision it is harmless (\(\sigma_{k}\) reliable down to \(\sqrt{\varepsilon}\approx -156\) dB re \(\sigma_{1}\)), but in single precision, the default on GPUs, \(\sigma_{k}\) below roughly −65 to −75 dB re \(\sigma_{1}\) is corrupted, which is where the blood/noise boundary of a high-dynamic-range ensemble sits (see the MATLAB lab).
06.6Where this goes next
- Eigenspace beamforming (Module 25). The minimum-variance weights \(\mathbf{w}\) \(= \mathbf{R}^{-1}\mathbf{a}/(\mathbf{a}^{H}\mathbf{R}^{-1}\mathbf{a})\) are projected onto the dominant eigenvectors of the sample covariance \(\mathbf{R}\) (Asl & Mahloojifar 2010), which suppresses the noise-subspace contribution that makes plain MV speckle grainy. The spectral theorem of 06.1 is the entire mechanism.
- Reflection and distortion matrices (aberration correction). Record the full transmit–receive response \(\mathbf{R}\), either element-by-element or in a plane-wave basis. Focusing it in a focused basis and then expressing each focal spot's residual wavefront relative to the ideal (homogeneous-medium) wavefront gives the distortion matrix \(\mathbf{D}\). Over an isoplanatic patch every focal point sees the same aberration, so the rows of \(\mathbf{D}\) are the same phase law times different speckle: \(\mathbf{D}\) is approximately rank 1, and its first singular vector is the aberration phase law to apply in transmit and receive (Lambert, Cobus, Frappart, Fink & Aubry 2020). Speckle averaging across the patch is what makes the estimate robust; patch size against isoplanatic angle is the key trade-off.
- DORT. The SVD of the inter-element response matrix of a few point-like scatterers gives one significant σ per scatterer, and \(\mathbf{v}_{i}\) is the time-reversal focusing law onto scatterer i. It is the ancestor of both points above.
- ULM. SVD clutter filtering (§06.5) → localization of bubble PSFs (Module 11 delay/peak estimation, Batch 2 estimation theory and CRLB) → tracking → rendering.
- Sound-speed estimation. Inversion operators are ill-conditioned; the Picard plot and truncated SVD of 06.4 are how you read their resolving power.
06.7Visual summary
Twelve pictures an expert carries for eigen- and singular-value problems, each with its five-second answer. Every curve is computed: the 2×2 decompositions with Lab.eigSym, the clutter spectrum from a simulated Casorati matrix, the noise spectrum from a random draw. The slider sets the noise level, which moves the noise plateau of the clutter spectrum, the Picard floor and the truncated-SVD optimum together.
06.8How experts think about it
An expert reads every matrix in an ultrasound pipeline as a sum of separable rank-1 patterns \(\sigma_{k}\mathbf{u}_{k}\mathbf{v}_{k}^{H}\) and asks three questions: which physical process produced each pattern, how fast the \(\sigma_{k}\) fall, and where the noise bulk begins. Low rank means coherence (rigid tissue, one scatterer, one aberration law), the tail is noise whose level is predictable, and every filter or inverse is a choice of which terms to keep. Numbers below come from this module's demos and MATLAB scripts unless stated.
\(\sigma_{k}^{2}\) is the energy of a separable component of (06.14). Tissue is bright and moves as one large pattern, so a few terms capture it; blood signals are 40–60 dB weaker and spatially fragmented, so they spread over tens of middle ranks; noise is i.i.d. and fills the Marchenko–Pastur bulk. In m06_svd_clutter_filter.m (2304 pixels × 128 frames, tissue at 8 mm/s) \(\sigma_{k}\) falls 0, −5, −9, −16, −23, −31 dB over k = 1–6, flattens into a blood plateau from −36 to about −45 dB over k ≈ 7–30, then drops to the noise edge at −67.6 dB, k = 46.
A static image repeated n times is \(\mathbf{s}_{0}\mathbf{1}^{T}, \operatorname{rank} 1\). A pure phase rotation \(\mathbf{s}_{0}e^{j2\pi f_{D}t}\) is still one spatial map times one time course: rank 1 at any \(f_{D}\). Rank grows only when the envelope moves relative to the pixel grid. Simulated (40×40 px, 80 frames, PSF \(\sigma_{z} = 0.10\) mm), ranks needed to bring the tissue residual to −50 dB for an axial translation D over the ensemble:
- \(D\)
- axial translation of the tissue over the ensemble, mm
- \(\to\)
- "requires" (number of ranks to reach −50 dB tissue residual)
A temporal high-pass (IIR, FIR, polynomial regression, first difference) projects every pixel onto the same fixed band of slow-time frequencies. Once the tissue Doppler band (swept over ±52 Hz by the 8 mm/s sinusoidal motion and broadened by speckle decorrelation) overlaps the flow Doppler, no cutoff works: tissue is 40–60 dB stronger, and a filter steep enough to remove it also removes the flow next to it. The SVD projects onto a data-derived temporal subspace: tissue at the same \(f_{D}\) as blood still lands in other singular vectors because its spatial map covers the whole field. In the MATLAB sweep the SVD band keeps 16.5, 15.2, 9.1, 6.4 dB contrast at 4, 8, 16, 24 mm/s while the best IIR, best regression and first difference all stay between −1.3 and +1.4 dB.
The best \(k_{\mathrm{lo}}\) tracks the tissue motion of that ensemble: in the MATLAB sweep it is 2, 5, 9, 11, 15 for vt = 0, 4, 8, 16, 24 mm/s, so any fixed rank is wrong most of the time. Practical estimators: the correlation matrix of the spatial maps \(\lvert \mathbf{u}_{k}\rvert\) (Baranger et al. 2018), in which tissue, blood and noise ranks form blocks; the mean or RMS Doppler of each temporal vector, cut where it exceeds the tissue Doppler; the knee of \(\sigma_{k}\) in dB; and for \(k_{\mathrm{hi}}\), the noise edge \(\sigma_{n}(\sqrt{m}+ \sqrt{n})\).
For an M×N matrix of i.i.d. entries with variance \(\sigma^{2}\) (complex: \(E\lvert z\rvert^{2} = \sigma^{2}\)), the singular values fill \([\sigma (\sqrt{M}- \sqrt{N}), \sigma (\sqrt{M}+ \sqrt{N})]\) as M, N grow. A tall Casorati matrix has a narrow bulk (1600×80: measured 31.5–48.5σ vs 31.1–48.9σ predicted), a square one a wide one (96×96: 0–19.6σ, 42 dB spread). A rank-1 signal of strength θ (= its σ without noise) separates from the bulk only when \(\theta > \sigma (MN)^{1/4} = 18.9\sigma\) for 1600×80, well below the edge 48.9σ; then \(\sigma_{1} \approx \sqrt{(\theta^{2}+\sigma^{2}M)(\theta^{2}+\sigma^{2}N)}/\theta\).
Unitary invariance gives the error (06.9) of \(A_{k}\); optimality follows from a dimension count (§06.3) or from Weyl's inequality \(\sigma_{k+i}(A) \le \sigma_{i}(A - B)\) for rank B ≤ k. In m06_svd_cyst.m both identities hold to round-off at every printed k from 1 to 256 (Frobenius relative difference ≤ \(1.1\times 10^{-14}\)), and projecting the image onto its k strongest columns gives 1.55×, 1.85×, 2.24×, 2.13× the SVD error for k = 1, 5, 20, 60. The SVD tissue estimate in a clutter filter is therefore the best rank \((k_{\mathrm{lo}} - 1)\) fit to the ensemble, which is why it captures more tissue per rank than any fixed basis.
\(\sum \sigma_{i}^{2}\) includes the mean level. A log-compressed B-mode image sits around −30 dB everywhere, so the rank-1 term (roughly the mean depth profile times a constant lateral profile) holds 97.3 % of the energy in the cyst script while barely showing the cyst (contrast −6 dB instead of −21 dB). Subtract the mean, or quote \(\lVert A - A_{k}\rVert_{F}/\lVert A - \text{mean}\rVert_{F}\), before talking about compression.
Round-off in \(\mathbf{S}^{H}\mathbf{S}\) is about \(\varepsilon \lVert \mathbf{S}\rVert_{2}^{2}\) \(= \varepsilon \sigma_{1}^{2}\), so eigenvalues \(\sigma_{k}^{2}\) below that level, i.e. \(\sigma_{k}/\sigma_{1} < \sqrt{\varepsilon}\), carry no information. \(\sqrt{\varepsilon}\) is \(3.5\times 10^{-4}\) (−69 dB) in single and \(1.5\times 10^{-8}\) (−156 dB) in double. Measured on the simulated ensemble: double matches svd to \(2.5\times 10^{-11}\); single first errs by > 1 % at k = 46, −66.8 dB re \(\sigma_{1}\), exactly the blood/noise boundary.
With M pixels ≫ N frames, forming \(\mathbf{S}^{H}\mathbf{S} (N\times N)\) costs \(MN^{2}\), its eigendecomposition \(N^{3}\), and the filtered ensemble \(\mathbf{S}_{f} = (\mathbf{S} \mathbf{V}_{b})\mathbf{V}_{b}^{H}\) another 2MNb. A thin SVD of S is also \(O(MN^{2})\) but with a larger constant and less parallelism. For power Doppler alone, PD = \((1/N)\sum_{k\in \mathrm{band}}\lvert \mathbf{S} \mathbf{v}_{k}\rvert^{2}\) needs only \(\mathbf{S} \mathbf{V}_{b}\). In the MATLAB check the Gram-route PD matches the svd PD to \(1.8\times 10^{-11}\).
A global SVD assumes one set of temporal singular vectors serves the whole field. When tissue motion, brightness or noise level varies with position (near a pulsating artery, across depth with TGC), the tissue at one location needs ranks that are blood elsewhere, and a single \(k_{\mathrm{lo}}\) cannot fit both. Processing overlapping spatial blocks, each with its own cutoffs, makes the clutter locally closer to low rank (Song et al. 2017). The cost scales with the block overlap factor, and each block must still have many more pixels than the number of tissue plus blood ranks it has to hold.
The temporal singular vectors live in \(\mathbb{C}^{N}\), whose frequency resolution is 1/T = PRF/N; velocity resolution is (λ/2)·PRF/N = 0.154 mm × 7.8 Hz = 1.20 mm/s at 5 MHz. Longer ensembles give more blood ranks, better slow-flow separation and lower PD variance, but over a longer T the tissue moves further (more ranks, previous rules) and the motion becomes non-stationary. Ultrafast Doppler commonly uses 50–400 ms; ULM processes blocks of a few hundred to about a thousand frames at 0.5–1 kHz.
As in (06.6), expanding \(\mathbf{x}_{0}\) in the eigenbasis, the non-dominant components shrink by \((\lambda_{i}/\lambda_{1})^{k}\), so k ≈ ln(tol)/ln r iterations reach tol: 50 for r = 0.5, 97 for r = 0.7, 674 for r = 0.95 (measured slopes in m06_svd_geometry.m match \(\log_{10}r\) to 4 digits). Iterative time reversal is physical power iteration on the time-reversal operator: it converges to the strongest scatterer at the rate \(\lvert \lambda_{2}/\lambda_{1}\rvert = (\sigma_{2}/\sigma_{1})^{2}\) of \(\mathbf{K}^{H}\mathbf{K}\), about the squared reflectivity ratio of the two strongest well-resolved scatterers.
Perturbing any matrix by \(\mathbf{E}\) moves each \(\sigma_{i}\) by at most \(\lVert \mathbf{E}\rVert_{2}\). For a non-normal matrix an eigenvalue can move by far more: the shear [[1, 1],[0, 1]] has λ = 1, 1, but [[1, 1],[δ, 1]] has \(\lambda = 1 \pm \sqrt{\delta}\), so \(\delta = 10^{-10}\) moves λ by \(10^{-5}\). Use singular values for gains, ranks and thresholds; use eigenvalues of Hermitian matrices (covariances), where they coincide with singular values up to sign.
\(\sigma \mathbf{u}\mathbf{v}^{H}\) is unchanged when both vectors take the same phase (a sign in the real case), and for a repeated σ any unitary mix of the vectors is valid. What is unique is the projector \(\mathbf{V}_{b}\mathbf{V}_{b}^{H}\) onto a band separated from its neighbours by a gap; a perturbation \(\mathbf{E}\) tilts that subspace by an angle of order \(\lVert \mathbf{E}\rVert /\text{gap}\) (Wedin, Davis–Kahan). The clutter filter \(\mathbf{SV}_{b}\mathbf{V}_{b}^{H}\) and PD are therefore well defined; an individual temporal vector's phase is not.
For one point scatterer the received aperture vector is \(a\cdot \mathbf{g}\) (\(\mathbf{g}\) its Green's function), so \(\mathbf{R}\) \(= E\lvert a\rvert^{2}\mathbf{gg}^{H} + \sigma_{n}^{2}\mathbf{I}\): rank 1 plus noise, dominant eigenvector \(\mathbf{g}\), and its phase conjugate refocuses on the scatterer. With several well-resolved scatterers the inter-element matrix \(\mathbf{K} = \mathbf{G} \operatorname{diag} (r) \mathbf{G}^{T}\) has one σ per scatterer (Prada & Fink 1994). In m06_svd_geometry.m, 64 elements and two scatterers 5 mm apart laterally (reflectivities 1 and 0.5, depths 30 and 32 mm) give \(\sigma_{2}/\sigma_{1} = 0.47\) and a floor at 0.002, which is the 0.1 % noise the script adds (the in-page figure of this rule uses 0.47 as the reflectivity ratio and no noise). With an aberrator, the dominant eigenvector carries the aberration phase law: that is the distortion-matrix idea (§06.6).
The pseudo-inverse (06.12) divides each data coefficient \(\mathbf{u}_{i}^{H}\mathbf{b}\) by \(\sigma_{i}\); white noise contributes a constant floor s to every coefficient, so terms past the point where the signal coefficients drop below s add only amplified noise. In m06_tsvd_picard.m (64-sample Gaussian blur, −40 dB noise) the best TSVD index is 27 (error 0.40), the Picard rule predicts 26, Tikhonov at its best α gives 0.40, and the plain pinv gives \(10^{10}\). Lowering the noise 20 dB moves k only to 31 because \(\sigma_{i}\) of a Gaussian blur falls super-exponentially: resolution is bought very expensively with SNR.
For centered data \(\mathbf{X}\) (N observations × p variables), the principal axes are the right singular vectors and the variances \(\sigma_{i}^{2}/(N-1)\), computed without squaring κ. Subtracting each pixel's temporal mean projects every time series off the constant vector \(\mathbf{1}\): a polynomial-regression clutter filter of degree 0. The SVD filter generalizes this by removing the \(k_{\mathrm{lo}}-1\) temporal vectors that the data say carry the most energy, instead of polynomials fixed in advance.
06.9Cheat sheet
| Concept | Formula | Ultrasound use |
|---|---|---|
| Eigenpair | \(\mathbf{A}\mathbf{v} = \lambda\mathbf{v},\ \ \det(\mathbf{A}-\lambda\mathbf{I}) = 0\) | modes of propagation and covariance operators |
| Spectral theorem | \(\mathbf{A} = \mathbf{A}^{H} \Rightarrow \mathbf{A} = \mathbf{Q}\Lambda\mathbf{Q}^{H}\), \(\lambda\) real, \(\mathbf{Q}\) unitary | channel covariance, coherence factor, eigenspace MV |
| Power iteration | error \(\propto \lvert\lambda_2/\lambda_1\rvert^{k}\); Rayleigh (Hermitian \(\mathbf{A}\)) \(\propto \lvert\lambda_2/\lambda_1\rvert^{2k}\) | iterative time reversal (converges to strongest scatterer) |
| SVD | \(\mathbf{A} = \mathbf{U}\Sigma\mathbf{V}^{H},\ \ \mathbf{A}\mathbf{v}_i = \sigma_i\mathbf{u}_i\) | DORT, Casorati filtering, distortion matrix |
| σ ↔ eig | \(\sigma_i^{2} = \lambda_i(\mathbf{A}^{H}\mathbf{A})\) | Gram-matrix route for large Casorati matrices |
| Norms, κ | \(\lVert\mathbf{A}\rVert_2 = \sigma_1,\ \ \lVert\mathbf{A}\rVert_F^{2} = \sum\sigma_i^{2},\ \ \kappa = \sigma_1/\sigma_n\) | stability of inversions (SoS tomography) |
| Eckart–Young | \(\lVert\mathbf{A}-\mathbf{A}_k\rVert_F^{2} = \sum_{i>k}\sigma_i^{2},\ \ \lVert\mathbf{A}-\mathbf{A}_k\rVert_2 = \sigma_{k+1}\) | tissue model = best rank \((k_{\mathrm{lo}} - 1)\) fit of the ensemble |
| PCA | \(\mathbf{C} = \mathbf{V}\Sigma^{2}\mathbf{V}^{H}/(N-1)\) for centered \(\mathbf{X}\) | dominant modes of motion, coherence (Module 07) |
| Pseudo-inverse / TSVD | \(\mathbf{x}_k = \sum_{i\le k}(\mathbf{u}_i^{H}\mathbf{b}/\sigma_i)\,\mathbf{v}_i\) | regularized deconvolution, SoS and aberration inversion |
| SVD clutter filter | \(\mathbf{S}_f = \mathbf{S}\mathbf{V}_b\mathbf{V}_b^{H},\ \ \mathrm{PD} = \sum_{\text{band}}\sigma_k^{2}\lvert u_k\rvert^{2}/n\) | ultrafast Doppler, fUS, ULM input |
| Marchenko–Pastur edge | \(\sigma_{\text{noise}}(\sqrt{m}\pm\sqrt{n})\); spike visible if \(\theta > \sigma(mn)^{1/4}\) | automatic \(k_{\mathrm{hi}}\), detectability of weak flow |
| Gram route | \(\mathbf{S}^{H}\mathbf{S} = \mathbf{V}\Sigma^{2}\mathbf{V}^{H}\), cost \(MN^{2} + N^{3}\); reliable for \(\sigma_k > \sqrt{\varepsilon}\,\sigma_1\) | real-time clutter filtering (beware single precision, −69 dB) |
| Doppler resolution | \(\Delta f = \mathrm{PRF}/N,\ \ \Delta v = (\lambda/2)\,\mathrm{PRF}/N\) | ensemble length vs tissue motion trade-off |
| Rank of moving tissue | uniform phase rotation: rank 1; translation \(D\): ≈ 1 extra rank per \(\sigma_z\) | why \(k_{\mathrm{lo}}\) must adapt to motion |
06.10Interview and qualifying-exam questions
I1What is the relation between PCA, the eigendecomposition of a covariance and the SVD? Which one do you compute, and why? · screen
For centered data \(\mathbf{X} (N\times p), \mathbf{X} = \mathbf{U}\Sigma \mathbf{V}^{H}\) gives \(\mathbf{C}\) \(= \mathbf{X}^{H}\mathbf{X}/(N-1)\) \(= \mathbf{V}[\Sigma^{2}/(N-1)]\mathbf{V}^{H}\): principal axes = right singular vectors, variances = \(\sigma^{2}/(N-1)\), scores = \(\mathbf{U}\Sigma\). Compute the SVD of \(\mathbf{X}\) when accuracy matters, because forming \(\mathbf{C}\) squares κ; use the eigendecomposition of the small Gram/covariance matrix when speed matters and the needed components are well above \(\sqrt{\varepsilon}\cdot \sigma_{1}\). Follow-up: "Does centering matter for a Casorati matrix?" Yes: removing each pixel's temporal mean is a degree-0 regression wall filter, so \(\sigma_{1}\) then describes tissue motion rather than static brightness.
I2Walk me through an SVD clutter filter, and explain why it beats a high-pass filter when tissue moves. · screen
Reshape the n frames into the Casorati matrix \(\mathbf{S}\) (pixels × frames), take its SVD (in practice the eigendecomposition of \(\mathbf{S}^{H}\mathbf{S}\)), keep the band (06.15) \([k_{\mathrm{lo}}, k_{\mathrm{hi}}]\): \(\mathbf{S}_{f} = \mathbf{SV}_{b}\mathbf{V}_{b}^{H}\), and PD = \((1/n)\sum_{\mathrm{band}}\sigma_{k}^{2}\lvert u_{k}\rvert^{2}\). A high-pass is a projection onto a fixed frequency band, so tissue at \(f_{D} = 2v/\lambda\) (52 Hz at 8 mm/s, 5 MHz) that overlaps flow Doppler cannot be removed without removing flow. The SVD projection is data-derived: coherent tissue occupies its own temporal vectors even at the same \(f_{D}\). Numbers from the MATLAB lab: at 8 mm/s, SVD 15.2 dB vessel contrast vs −0.4 dB for the best IIR; at rest, 24.7 vs 23.1 dB. Follow-up: "When does the SVD lose?" Large vessels (coherent, climb into the tissue ranks), non-rigid or out-of-plane motion (tissue spreads into the blood ranks), noise-dominated depth.
I3How do you choose the SVD thresholds automatically? · onsite
\(k_{\mathrm{hi}}\): from the noise model. Estimate \(\sigma_{n}\) (no-transmit frames, or match the median singular value to the Marchenko–Pastur median) and keep \(\sigma_{k} > \sigma_{n}(\sqrt{m}+ \sqrt{n})\), or use the Gavish–Donoho threshold \((4/\sqrt{3})\sqrt{n}\sigma_{n}\) for a square matrix. \(k_{\mathrm{lo}}\): from what distinguishes tissue: (1) the spatial-similarity matrix of \(\lvert \mathbf{u}_{k}\rvert\) (Baranger et al. 2018), where tissue ranks form a correlated block; (2) the Doppler content of the temporal vectors (mean or RMS frequency above a tissue threshold); (3) the knee of \(\sigma_{k}\) in dB; (4) energy-based rules (cut when the cumulative tissue energy reaches a fraction). Per block if the field is non-stationary. The best \(k_{\mathrm{lo}}\) moves with tissue motion (2 → 15 for 0 → 24 mm/s in the MATLAB sweep), which is why it must be adaptive. Follow-up: "How do you validate a threshold rule without ground truth?" Phantoms with known flow, in vivo reproducibility, residual tissue at bright moving interfaces, slow-flow preservation in known vessels, and for ULM the localization count and velocity distribution vs \(k_{\mathrm{lo}}\).
I4What happens to SVD filtering under large tissue motion, and what do you do about it? · onsite
Rank-1 requires separability. A uniform phase rotation stays rank 1, but speckle that slides across the PSF needs more ranks, roughly one extra per \(\sigma_{z}\) of displacement over the ensemble (0.1 mm → 3 ranks, 1 mm → 13 ranks to −50 dB in the module's simulation). Tissue then spreads into the ranks where blood lives, the optimal \(k_{\mathrm{lo}}\) rises and contrast drops (16.5 → 6.4 dB from 4 to 24 mm/s in the MATLAB sweep). Remedies: shorter ensembles or sliding windows (less displacement per window), motion estimation and registration before the SVD, block-wise SVD with local cutoffs, rejecting frames with large motion, and higher-order methods that model motion explicitly. Follow-up: "What does a shorter ensemble cost?" Doppler resolution PRF/N, fewer blood ranks, higher PD variance.
I5What is the computational cost of an SVD clutter filter, and how would you make it real-time? · onsite
Thin SVD of an M×N Casorati matrix (M ≫ N) is \(O(MN^{2})\). The fast route: \(G = \mathbf{S}^{H}\mathbf{S}\) (\(MN^{2}\), a GEMM that GPUs do well), eig of \(G (N^{3})\), then \(\mathbf{SV}_{b}\) (MNb). For 128×128 pixels and 300 frames: \(1.5\times 10^{9}\) complex MACs for \(G, 2.7\times 10^{7}\) for the eig. Further: compute only the leading \(k_{\mathrm{hi}}\) vectors (randomized SVD or subspace iteration, O(MNk)), update across overlapping windows instead of recomputing, use blocks in parallel. Follow-up: "Any catch with single precision?" Yes: forming G squares κ, so \(\sigma_{k}\) below about \(\sqrt{\varepsilon_{\mathrm{single}}}\cdot \sigma_{1}\) (−69 dB) are corrupted; measured on the simulated ensemble the first > 1 % error appears at −66.8 dB, right at the blood/noise boundary. Either keep G in double, or run the SVD on \(\mathbf{S}\) directly.
I6Why are singular vectors unique only up to sign or phase, and when does that bite you? · onsite
\(\sigma \mathbf{uv}^{H}\) \(= \sigma (\mathbf{u}e^{j\varphi})(\mathbf{v}e^{j\varphi})^{H}\), so any common phase is valid, and for a repeated σ any unitary rotation within the singular subspace is valid. Only the projectors onto groups of singular vectors separated by a gap are unique, with perturbation sensitivity of order \(\lVert \mathbf{E}\rVert /\text{gap}\). It bites when you average or track vectors across blocks, windows or acquisitions (align phases first, or compare \(\lvert u_{k}\rvert\) or projectors), when you compare MATLAB with another library (signs differ), and inside the noise bulk where gaps are tiny. The filter \(\mathbf{SV}_{b}\mathbf{V}_{b}^{H}\) and PD are invariant. Follow-up: "How do you align two sets of singular vectors?" Orthogonal Procrustes: the SVD of \(\mathbf{V}_{1}^{H}\mathbf{V}_{2}\) gives the best unitary alignment.
I7Prove that the truncated SVD is the best rank-k approximation in the spectral norm. Does the same hold in Frobenius norm? · research
\(\lVert \mathbf{A} - \mathbf{A}_{k}\rVert_{2} = \sigma_{k+1}\) by unitary invariance (06.9). For any \(\mathbf{B}\) with rank ≤ k, \(\operatorname{null} \mathbf{B}\) has dimension ≥ n − k and therefore intersects the (k+1)-dimensional \(\operatorname{span} (\mathbf{v}_{1}, \dots, \mathbf{v}_{k+1})\) in a unit vector \(\mathbf{w}\). Then \(\lVert (\mathbf{A} - \mathbf{B})\mathbf{w}\rVert\) \(= \lVert \mathbf{Aw}\rVert \ge \sigma_{k+1}\). Frobenius: Weyl's inequality \(\sigma_{i+j-1}(\mathbf{X} + \mathbf{Y}) \le \sigma_{i}(\mathbf{X}) + \sigma_{j}(\mathbf{Y})\) with \(\mathbf{X} = \mathbf{A} - \mathbf{B}\), \(\mathbf{Y} = \mathbf{B}\), \(j = k+1\) gives \(\sigma_{k+i}(\mathbf{A}) \le \sigma_{i}(\mathbf{A} - \mathbf{B})\), so \(\lVert \mathbf{A} - \mathbf{B}\rVert_{F}^{2} \ge \sum_{i>k}\sigma_{i}^{2}\). It holds for every unitarily invariant norm (Mirsky). Follow-up: "Is the minimizer unique?" In Frobenius norm yes if \(\sigma_{k} > \sigma_{k+1}\); in the spectral norm no, many matrices achieve \(\sigma_{k+1}\).
I8What does the dominant eigenvector of the channel (spatial) covariance matrix mean physically? Connect it to DORT and aberration correction. · research
\(\mathbf{R} = E[\mathbf{xx}^{H}]\) across the aperture. For a single dominant scatterer \(\mathbf{x} = a\mathbf{g}\) + noise, so \(\mathbf{R}\) \(= E\lvert a\rvert^{2}\mathbf{gg}^{H} + \sigma_{n}^{2}\mathbf{I}\); the dominant eigenvector is the Green's function \(\mathbf{g}\) (including any aberration), and its phase conjugate is the transmit law that refocuses on the scatterer. \(\lambda_{1}/\sum \lambda_{i}\) measures coherence (a coherence-factor analogue). DORT applies the same idea to the inter-element response matrix \(\mathbf{K}\): one significant singular value per resolved point scatterer, each singular vector a selective focusing law (Prada & Fink 1994); iterative time reversal is power iteration on \(\mathbf{K}^{H}\mathbf{K}\). In speckle there is no single scatterer, so the distortion-matrix method averages over an isoplanatic patch to recover a rank-1 structure whose first singular vector is the aberration law. Follow-up: "What breaks it?" Scatterers within one resolution cell (vectors mix), patches larger than the isoplanatic area (rank grows), low SNR (\(\sigma_{1}\) near the noise bulk).
I9A static tissue ensemble is rank 1. Is tissue moving with a uniform axial Doppler shift also rank 1? What actually raises the rank? · research
If the scene only changes phase, \(\mathbf{S}\) \(= \mathbf{s}_{0}[e^{j2\pi f_{D}t_{1}} \dots e^{j2\pi f_{D}t_{n}}]\) is an outer product: rank 1 at any \(f_{D}\), which a high-pass filter cannot remove if \(f_{D}\) is in the passband but the SVD removes in one term. A real displacement also moves the envelope relative to the pixel grid; each pixel then sees a different, time-varying speckle amplitude, and the pattern is no longer separable. The number of ranks grows with displacement over the PSF size: about 3 ranks for \(1\sigma_{z}\), 6 for \(3\sigma_{z}\), 13 for \(10\sigma_{z}\) at a −50 dB residual. Follow-up: "So how would you make moving tissue low rank again?" Register the frames (undo the displacement) before the SVD, or work in blocks small enough that motion is locally a pure translation over a short window.
I10Where is the noise floor in a singular-value plot, and can a component below that floor still be detected? · research
For i.i.d. noise of standard deviation σ per entry, the noise singular values fill the Marchenko–Pastur bulk \([\sigma (\sqrt{m}- \sqrt{n}), \sigma (\sqrt{m}+ \sqrt{n})]\); for 1600 pixels × 80 frames that is 31.1σ to 48.9σ, only 4.0 dB wide (3.8 dB measured), so the tail of a Casorati spectrum looks like a gently sloping plateau. A rank-1 component of strength θ separates from the bulk only above \(\theta_{c} = \sigma (mn)^{1/4} = 18.9\sigma\) (the BBP transition); just above it \(\sigma_{1}\) barely clears the edge (\(\theta = 1.2\theta_{c}\) gives \(\sigma_{1} = 49.4\sigma\) vs edge 48.9σ) and its singular vectors are only partly aligned with the truth (\(\lvert \langle \mathbf{v}_{1}, \mathbf{v}\rangle \rvert^{2} = 0.45\)). Below \(\theta_{c}\) it is invisible to any SVD threshold. Follow-up: "Why are the temporal vectors better estimated than the spatial ones?" The overlap formulas weight by the aspect ratio: with \(m \gg n\), \(\lvert \langle \mathbf{v}_{1}\), \(\mathbf{v}\rangle \rvert^{2} = 0.89\) but \(\lvert \langle \mathbf{u}_{1}, \mathbf{u}\rangle \rvert^{2} = 0.44\) at \(\theta = 2\theta_{c}\): the n-dimensional temporal vector is estimated from m ≫ n pixels of evidence, while the m-dimensional spatial vector has only n frames.
I11Your ensemble is 128 frames at 1 kHz with a 5 MHz probe. What Doppler and velocity resolution do the temporal singular vectors have, and what would doubling the ensemble change? · screen
Δf = PRF/N = 7.8 Hz, i.e. (λ/2)Δf = 0.154 mm × 7.8 Hz = 1.20 mm/s axial; Nyquist ±500 Hz = ±77 mm/s. Doubling to 256 frames halves Δf to 3.9 Hz (0.60 mm/s), adds blood ranks and lowers PD variance, but doubles the time over which tissue moves (more tissue ranks, possibly non-stationary motion), quadruples the Gram cost \(MN^{2}\) and halves the PD frame rate if windows do not overlap. Follow-up: "Can you measure a 0.5 mm/s flow with 1.2 mm/s resolution?" Its mean frequency can be estimated below Δf at high SNR; resolving it from tissue at a similar Doppler needs the spatial separation the SVD provides.
06.11MATLAB lab
Base MATLAB only (no toolboxes); each script runs as-is in MATLAB R2019b+ and GNU Octave 8. Paste into the editor and press Run. Printed numbers below are from Octave with rng(1); MATLAB's generator gives slightly different values.
m06_svd_cyst.mLow-rank B-mode cyst phantom: images at ranks 1, 2, 5, 20, 60, singular-value spectrum, Eckart–Young checks, cyst contrast and CNR vs k · change PSF, cyst radius, DR, ranks · runtime ≈ 4 s
%% m06_svd_cyst.m -- Module 06: low-rank approximation of a B-mode cyst phantom
% Purpose : Build a synthetic B-mode image (random scatterers * 2-D RF PSF,
% anechoic cyst, point targets, layers), detect the envelope with an
% FFT-based analytic signal, log-compress, then study rank-k
% approximations: images at ranks 1, 2, 5, 20, 60, the singular-value
% spectrum, the Eckart-Young identities ||B - B_k||_F^2 = sum_{i>k} sigma_i^2
% and ||B - B_k||_2 = sigma_{k+1}, a rival rank-k approximation that
% must lose, and cyst contrast / CNR vs k.
% Change : f0, PSF widths, cyst radius, dynamic range DR, the list of ranks ks.
% Expect : both Eckart-Young identities hold (Frobenius to ~1e-14, spectral norm to
% the printed digits); the rival rank-k approximation loses by 1.5-2.2x;
% rank 1 already holds 97.3 % of the energy (the -30 dB mean level), so
% judge the images, not the percentage. Cyst contrast about -21 dB at full
% rank, capped by the 60 dB display floor (the cyst interior is clipped),
% and only -6 dB at k = 1; CNR peaks at k = 2 (9.4 vs 3.8 at full rank)
% because low rank averages speckle, at the price of separable streaks.
% Runtime : ~4 s in Octave.
clear; close all; rng(1);
%% 1. Geometry and RF point-spread function
c0 = 1540; f0 = 5e6; fs = 40e6; % m/s, Hz, Hz
dz = c0/(2*fs); % axial sample spacing (m), 19.25 um
dx = 0.15e-3; % lateral line spacing (m)
z = (10e-3:dz:40e-3)'; x = (-19.2e-3:dx:19.2e-3-dx); % 1559 x 256 grid
Nz = numel(z); Nx = numel(x);
sz = 0.12e-3; % axial envelope std (m), FWHM 0.28 mm
sx = 0.30e-3; % lateral beam std (m), FWHM 0.71 mm
kz = (-ceil(4*sz/dz):ceil(4*sz/dz))'*dz; kx = (-ceil(4*sx/dx):ceil(4*sx/dx))*dx;
psf = exp(-kz.^2/(2*sz^2)) .* cos(2*pi*f0*2*kz/c0) * exp(-kx.^2/(2*sx^2)); % RF PSF (two-way phase)
%% 2. Scatterer field: echogenicity map x Gaussian random amplitudes
[X, Z] = meshgrid(x, z);
echo = ones(Nz, Nx);
echo(Z > 14e-3 & Z < 15.5e-3) = 6; % bright layer (+7.8 dB)
echo(Z > 31e-3 & Z < 33e-3) = 0.3; % dark layer (-5.2 dB)
cyst = (X - 2e-3).^2 + (Z - 24e-3).^2 < (4e-3)^2;
echo(cyst) = 0; % anechoic cyst, radius 4 mm
incl = ((X + 9e-3)/3e-3).^2 + ((Z - 24e-3)/2.5e-3).^2 < 1;
echo(incl) = 3; % hyperechoic inclusion (+4.8 dB)
scat = sqrt(echo) .* randn(Nz, Nx); % one random scatterer per sample
pts = [-12e-3 20e-3; -4e-3 20e-3; 4e-3 20e-3; 12e-3 20e-3; 10e-3 36e-3];
for p = 1:size(pts,1)
[~, iz] = min(abs(z - pts(p,2))); [~, ix] = min(abs(x - pts(p,1)));
scat(iz, ix) = scat(iz, ix) + 400; % point targets (wires)
end
% 2-D convolution via zero-padded FFTs (base MATLAB conv2 would also work)
Pz = Nz + numel(kz) - 1; Px = Nx + numel(kx) - 1;
rf = real(ifft2(fft2(scat, Pz, Px) .* fft2(psf, Pz, Px)));
oz = (numel(kz)-1)/2; ox = (numel(kx)-1)/2;
rf = rf(oz+(1:Nz), ox+(1:Nx));
rf = rf + 0.002*std(rf(:))*randn(Nz, Nx); % electronic noise, -54 dB re mean speckle
%% 3. Envelope (analytic signal via FFT, no toolbox hilbert) and log compression
N = Nz; h = zeros(N,1); h(1) = 1;
if mod(N,2) == 0, h(N/2+1) = 1; h(2:N/2) = 2; else, h(2:(N+1)/2) = 2; end
env = abs(ifft(fft(rf) .* repmat(h, 1, Nx)));
env = env(1:4:end, :); zd = z(1:4:end); % decimate axially to 77 um pixels
cystd = cyst(1:4:end, :);
bgd = ~cystd & abs(Z(1:4:end,:) - 24e-3) < 4e-3 & abs(X(1:4:end,:) - 2e-3) > 6e-3 & abs(X(1:4:end,:) + 9e-3) > 5e-3;
DR = 60; % dynamic range (dB)
B = 20*log10(env/max(env(:))); B = max(B, -DR); % log-compressed image (dB), A in the text
[m, n] = size(B);
fprintf('B-mode image %d x %d pixels (%.0f um axial x %.0f um lateral), DR = %d dB\n', m, n, 4*dz*1e6, dx*1e6, DR);
%% 4. SVD, spectrum, Eckart-Young check, cyst metrics vs rank
[U, S, V] = svd(B, 'econ'); s = diag(S);
inC = cystd & ((X(1:4:end,:) - 2e-3).^2 + (Z(1:4:end,:) - 24e-3).^2 < (3e-3)^2); % cyst core
ks = [1 2 5 10 20 40 80 n];
fprintf('\nEckart-Young: ||B-Bk||_F^2 = sum_{i>k} sigma_i^2 and ||B-Bk||_2 = sigma_{k+1}\n');
fprintf(' k energy%% ||B-Bk||_F^2 sum_{i>k} s^2 rel.diff ||B-Bk||_2 sigma_k+1 contrast(dB) CNR\n');
con = zeros(size(ks)); cnr = con;
for j = 1:numel(ks)
k = ks(j);
Bk = U(:,1:k)*S(1:k,1:k)*V(:,1:k)';
e2 = norm(B - Bk, 'fro')^2; tail = sum(s(k+1:end).^2);
if k < n, e2s = norm(B - Bk, 2); sk1 = s(k+1); else, e2s = 0; sk1 = 0; end
mc = mean(Bk(inC)); mb = mean(Bk(bgd));
con(j) = mc - mb; % contrast on the dB image
cnr(j) = abs(mc - mb)/sqrt(var(Bk(inC)) + var(Bk(bgd)));
if tail > 0, rd = abs(e2 - tail)/tail; else, rd = 0; end
fprintf('%4d %7.3f %13.6e %13.6e %8.1e %9.3f %9.3f %7.1f %5.2f\n', k, 100*sum(s(1:k).^2)/sum(s.^2), e2, tail, rd, e2s, sk1, con(j), cnr(j));
end
fprintf('sigma_1 / sigma_n = %.3g; ranks for 99%% energy: %d; for 99.9%%: %d\n', s(1)/s(end), ...
find(cumsum(s.^2)/sum(s.^2) >= 0.99, 1), find(cumsum(s.^2)/sum(s.^2) >= 0.999, 1));
fprintf('(Energy is dominated by the mean level: judge the residual image, not the percentage.)\n');
% Optimality: any other rank-k matrix does worse. Rival: project B onto the span of
% its k highest-energy columns (column-subset selection, a common "cheap" low rank).
[~, ord] = sort(sum(B.^2, 1), 'descend');
fprintf('\nRival rank-k approximation (span of the k strongest columns) vs truncated SVD, Frobenius error ratio:\n');
for k = [1 5 20 60]
Q = orth(B(:, ord(1:k))); Bc = Q*(Q'*B);
fprintf(' k = %2d: ||B-Bc||_F / ||B-Bk||_F = %.3f (>= 1 by Eckart-Young)\n', k, norm(B - Bc, 'fro')/sqrt(sum(s(k+1:end).^2)));
end
%% 5. Figures
figure('Position', [50 50 1000 640]);
show = [n 1 2 5 20 60]; ttl = {'original (full rank)', 'rank 1', 'rank 2', 'rank 5', 'rank 20', 'rank 60'};
for j = 1:numel(show)
k = show(j); Bk = U(:,1:k)*S(1:k,1:k)*V(:,1:k)';
subplot(2,3,j); imagesc(x*1e3, zd*1e3, Bk, [-DR 0]); colormap(gray); axis image;
title(ttl{j}); xlabel('lateral (mm)'); if mod(j,3) == 1, ylabel('depth (mm)'); end
end
figure('Position', [50 50 1000 360]);
subplot(1,2,1); semilogy(s/s(1), 'k.-'); grid on; hold on;
semilogy(ks, s(ks)/s(1), 'ro');
xlabel('index i'); ylabel('\sigma_i / \sigma_1'); title('Singular values of the log-compressed image');
subplot(1,2,2); [ax, h1, h2] = plotyy(ks, con, ks, cnr); set(ax, 'XScale', 'log');
set(h1, 'Marker', 'o'); set(h2, 'Marker', 's'); grid on;
xlabel('rank k'); ylabel(ax(1), 'cyst contrast (dB)'); ylabel(ax(2), 'CNR');
title('Cyst metrics of the rank-k image');
What to look for. 390×256 log-compressed image (60 dB). Both Eckart–Young identities hold at every printed k (1, 2, 5, 10, 20, 40, 80, 256): \(\lVert B-B_{k}\rVert_{F}^{2}\) equals \(\sum_{i>k}\sigma_{i}^{2}\) to ≤ \(1.1\times 10^{-14}\) relative, and \(\lVert B-B_{k}\rVert_{2}\) equals \(\sigma_{k+1}\) (1059.828 at k = 1, 464.968 at k = 2). Rank 1 already holds 97.3 % of the energy but shows almost no cyst (contrast −6.2 dB vs −21.4 dB at full rank); 99 % energy needs 20 ranks, 99.9 % needs 95. Rank 2 recovers the cyst contrast (−21.9 dB) as a square, separable blob, and has the best CNR (9.35 vs 3.77 at full rank) because it averages speckle away. The rival rank-k approximation (span of the k strongest columns) has 1.55–2.24× the SVD error.
m06_svd_clutter_filter.mCasorati SVD clutter filter vs IIR high-pass, polynomial regression and first difference under tissue motion; velocity sweep; Gram route in double and single · change vt_main, vts, n, PRF, blood/noise levels · runtime ≈ 20 s
%% m06_svd_clutter_filter.m -- Module 06: SVD clutter filter on a simulated ultrafast ensemble
% Purpose : Simulate an ultrafast IQ ensemble (pixels x frames): moving tissue
% speckle, a slow-flow vessel, a faster vessel, a few microbubble tracks,
% white noise. Build the Casorati matrix, take its SVD, look at the
% singular-value curve (with the Marchenko-Pastur noise edge), the
% Doppler spectra of the temporal singular vectors, and power Doppler
% for: raw data, an SVD band, and three FIXED temporal filters (first
% difference, 2nd-order Butterworth IIR high-pass run forward-backward,
% polynomial-regression filter). Then sweep tissue velocity and watch
% the best SVD band move while every fixed temporal filter collapses.
% Last, check the fast "Gram route" (eig of the n x n matrix S'S) in
% double and single precision.
% Change : vt_main (tissue peak axial velocity), the sweep list vts, PRF, n (frames),
% blood_dB, noise_dB, the cutoffs fcs and polynomial degrees pdeg.
% Expect : (rng(1)) at vt = 0 every filter works (SVD 24.7 dB, IIR 23.1 dB contrast).
% At vt = 8 mm/s (52 Hz peak tissue Doppler) the SVD band 9-46 gives
% 15.2 dB vessel/background contrast; IIR, regression and first difference
% all stay near 0 dB. The oracle k_lo rises 2 -> 5 -> 9 -> 11 -> 15 for
% vt = 0, 4, 8, 16, 24 mm/s; k_hi from the MP edge is 45-47. The Gram
% route matches svd() to ~1e-11 in double; in single it misplaces
% sigma_k by > 1 % about 66-69 dB below sigma_1.
% These are oracle (ground-truth-mask) choices: in vivo you have no masks.
% Runtime : ~20 s in Octave (five simulated ensembles; the simulation dominates).
clear; close all; rng(1);
%% 1. Parameters
c0 = 1540; f0 = 5e6; lam = c0/f0*1e3; % wavelength (mm), 0.308 mm
k2 = 4*pi/lam; % two-way wavenumber (rad/mm)
PRF = 1000; n = 128; % frame rate (Hz), frames -> 128 ms
NX = 48; NZ = 48; dx = 0.1; % pixels, pixel pitch (mm)
xg = (0:NX-1)*dx; zg = (0:NZ-1)*dx; m = NX*NZ;
sx = 0.17; sz = 0.10; % PSF std lateral / axial (mm)
blood_dB = -30; % blood scatterer amplitude re tissue scatterer
noise_dB = -50; % noise power re mean tissue pixel power
fm = 3; % tissue motion frequency (Hz), e.g. breathing/pulsation
vt_main = 8; % tissue peak axial velocity for the main figure (mm/s)
vts = [0 4 8 16 24]; % velocity sweep (mm/s)
fcs = [25 50 100 150]; % high-pass cutoffs to try (Hz)
pdeg = [1 2 4 8]; % polynomial-regression degrees to try
% Scatterers are drawn once and reused for every velocity, so only motion changes.
L = NX*dx; Ntis = 4000;
tis = [rand(Ntis,1)*(L+2)-1, rand(Ntis,1)*(L+2)-1, (randn(Ntis,1)+1i*randn(Ntis,1))/sqrt(2)];
ves = [1.2 2.2 10 0.30 5; % [x0 z0 angle(deg) radius(mm) vmax(mm/s)]: slow vessel
3.4 2.6 70 0.22 15]; % faster, steep vessel
blood = []; % [vessel, s0, r, amplitude]
for v = 1:size(ves,1)
nb = round(500*ves(v,4)/0.3);
blood = [blood; v*ones(nb,1), rand(nb,1)*8-4, (2*rand(nb,1)-1)*ves(v,4), ...
10^(blood_dB/20)*(randn(nb,1)+1i*randn(nb,1))/sqrt(2)]; %#ok<AGROW>
end
% microbubbles: [xc zc radius(mm) speed(mm/s) start angle(rad)] on circular arcs
mb = [2.4 1.2 1.5 12 0.3; 1.6 3.6 1.2 20 2.0; 3.8 3.8 1.8 9 4.0; 0.8 1.0 1.0 16 5.5];
mbAmp = 1.0; % 0 dB re a tissue scatterer
PSFx = @(x) exp(-(xg(:) - x(:).').^2/(2*sx^2)); % NX x Ns
PSFz = @(z) exp(-(zg(:) - z(:).').^2/(2*sz^2)); % NZ x Ns
%% 2. Simulate one ensemble per tissue velocity; each gives a Casorati matrix S (m x n)
S_all = cell(numel(vts),1); masks = [];
for iv = 1:numel(vts)
vt = vts(iv); w = 2*pi*fm;
S = zeros(m, n);
for f = 1:n
t = (f-1)/PRF;
dz0 = vt/w*sin(w*t); % bulk axial displacement (mm), peak velocity vt
% mild non-rigid motion: displacement grows 30 % across the field (depth-dependent)
dzs = @(z) dz0*(1 + 0.3*(z - L/2)/L);
dxs = 0.35*dz0;
zt = tis(:,2) + dzs(tis(:,2)); xt = tis(:,1) + dxs;
amp = tis(:,3).*exp(-1i*k2*zt);
img = PSFx(xt)*(amp.*PSFz(zt).'); % NX x NZ
% blood: parabolic profile, riding on the tissue motion
a = ves(blood(:,1),3)*pi/180; ux = cos(a); uz = sin(a); R = ves(blood(:,1),4);
vel = ves(blood(:,1),5).*(1 - (blood(:,3)./R).^2);
sp = mod(blood(:,2) + vel*t + 4, 8) - 4;
xb = ves(blood(:,1),1) + ux.*sp - uz.*blood(:,3);
zb = ves(blood(:,1),2) + uz.*sp + ux.*blood(:,3);
zb = zb + dzs(zb); xb = xb + dxs;
img = img + PSFx(xb)*((blood(:,4).*exp(-1i*k2*zb)).*PSFz(zb).');
% microbubbles on arcs
ang = mb(:,5) + mb(:,4)./mb(:,3)*t;
xm = mb(:,1) + mb(:,3).*cos(ang) + dxs; zm = mb(:,2) + mb(:,3).*sin(ang);
zm = zm + dzs(zm);
img = img + PSFx(xm)*((mbAmp*exp(-1i*k2*zm)).*PSFz(zm).');
S(:, f) = img(:); % column = one frame (x-major, NX*NZ)
end
if iv == 1, p0 = mean(abs(S(:,1)).^2); end % mean tissue pixel power (static case)
sn = sqrt(p0*10^(noise_dB/10)); % noise std per entry
S = S + sn*(randn(m,n) + 1i*randn(m,n))/sqrt(2);
S_all{iv} = S;
end
%% 3. Masks (ground truth, at the ensemble-mean position; only used for scoring)
[XX, ZZ] = ndgrid(xg, zg); % NX x NZ, matches img(:)
dn = inf(NX, NZ); dv = cell(1, size(ves,1));
for v = 1:size(ves,1)
a = ves(v,3)*pi/180;
dv{v} = abs(-(XX - ves(v,1))*sin(a) + (ZZ - ves(v,2))*cos(a))/ves(v,4); % distance in radii
dn = min(dn, dv{v});
end
dmb = inf(NX, NZ); tt = linspace(0, (n-1)/PRF, 60);
for b = 1:size(mb,1)
ang = mb(b,5) + mb(b,4)/mb(b,3)*tt;
for q = 1:numel(tt)
dmb = min(dmb, hypot(XX - mb(b,1) - mb(b,3)*cos(ang(q)), ZZ - mb(b,2) - mb(b,3)*sin(ang(q))));
end
end
vesM = dn(:) < 0.6; % both vessel cores
slowM = dv{1}(:) < 0.6; fastM = dv{2}(:) < 0.6;
bgM = dn(:) > 2.5 & dmb(:) > 0.5; % background, away from vessels and bubble tracks
contrast = @(pd) 10*log10(mean(pd(vesM))/mean(pd(bgM)));
cSlow = @(pd) 10*log10(mean(pd(slowM))/mean(pd(bgM)));
cFast = @(pd) 10*log10(mean(pd(fastM))/mean(pd(bgM)));
c3 = @(pd) [contrast(pd), cSlow(pd), cFast(pd)];
%% 4. Filters
pdOf = @(Y) mean(abs(Y).^2, 2); % power Doppler per pixel
fd = @(Y) Y(:,2:end) - Y(:,1:end-1); % first difference: |H| = 2|sin(pi f/PRF)|
% 2nd-order Butterworth high-pass via the bilinear transform (no toolbox)
bwb = @(fc) [1, -2, 1] / (1 + sqrt(2)*tan(pi*fc/PRF) + tan(pi*fc/PRF)^2);
bwa = @(fc) [1, 2*(tan(pi*fc/PRF)^2 - 1), 1 - sqrt(2)*tan(pi*fc/PRF) + tan(pi*fc/PRF)^2] ...
/ (1 + sqrt(2)*tan(pi*fc/PRF) + tan(pi*fc/PRF)^2);
hp1 = @(Y, fc) filter(bwb(fc), bwa(fc), Y - Y(:,1), [], 2); % one pass; subtract first sample to limit the step
rev = @(Y) Y(:, end:-1:1);
iir = @(Y, fc) rev(hp1(rev(hp1(Y, fc)), fc)); % forward-backward: zero phase, |H|^2 (like filtfilt)
cols = @(Y, idx) Y(:, idx);
iirPD = @(Y, fc) mean(abs(cols(iir(Y, fc), 21:n-20)).^2, 2); % drop 20-frame transients at both ends
% Polynomial regression filter: remove each pixel's projection onto polynomials of
% degree 0..p in slow time. Like the SVD filter it is a projection, S - S*Q*Q',
% but onto a FIXED temporal subspace chosen before seeing the data.
tn = linspace(-1, 1, n)'; % normalized slow time
regPD = @(Y, p) pdOf(Y - (Y*orth(tn.^(0:p)))*orth(tn.^(0:p))');
%% 5. Main case: singular values, Doppler of temporal singular vectors, PD images
iv = find(vts == vt_main); S = S_all{iv};
[U, Sg, V] = svd(S, 'econ'); s = diag(Sg);
sn = sqrt(p0*10^(noise_dB/10));
edgeMP = sn*(sqrt(m) + sqrt(n)); % Marchenko-Pastur upper edge of the noise bulk
k_hi = find(s > 1.05*edgeMP, 1, 'last'); % keep everything above the noise bulk
fprintf('Casorati %d x %d, vt = %g mm/s, tissue peak Doppler 2vt/lambda = %.1f Hz\n', m, n, vt_main, 2*vt_main/lam);
fprintf('sigma_k (dB re sigma_1), k = 1..10: %s\n', sprintf('%.0f ', 20*log10(s(1:10)/s(1))));
fprintf('MP noise edge = %.1f dB re sigma_1 -> k_hi = %d (measured last sigma = %.1f dB)\n', ...
20*log10(edgeMP/s(1)), k_hi, 20*log10(s(end)/s(1)));
NF = 256; fax = ((0:NF-1) - NF/2)*PRF/NF;
Pk = abs(fftshift(fft(conj(V), NF, 1), 1)).^2; % NF x n, spectrum of each temporal vector
fbar = (abs(fax)*Pk)./sum(Pk, 1); % mean |Doppler| per rank (Hz)
fprintf('mean |Doppler| of temporal singular vectors, k = 1..12 (Hz): %s\n', sprintf('%.0f ', fbar(1:12)));
% PD for every band start k_lo (with k_hi fixed): uses PD = sum sigma^2 |u|^2 / n
E = (abs(U).^2) .* (s.'.^2) / n; % m x n, energy of each rank per pixel
conK = zeros(1, k_hi);
for klo = 1:k_hi, conK(klo) = contrast(sum(E(:, klo:k_hi), 2)); end
[cbest, klo_best] = max(conK);
pdRaw = pdOf(S); pdSVD = sum(E(:, klo_best:k_hi), 2);
pdFD = pdOf(fd(S));
cI3 = zeros(numel(fcs), 3); pdI = cell(1, numel(fcs));
for j = 1:numel(fcs), pdI{j} = iirPD(S, fcs(j)); cI3(j,:) = c3(pdI{j}); end
[cIb, jI] = max(cI3(:,1)); pdIIR = pdI{jI};
fprintf('\nPower Doppler contrast re background (dB): both slow fast vessel\n');
fprintf(' raw (no filter) %6.1f %6.1f %6.1f\n', c3(pdRaw));
fprintf(' SVD band %2d-%2d (oracle k_lo) %6.1f %6.1f %6.1f\n', klo_best, k_hi, c3(pdSVD));
fprintf(' first difference %6.1f %6.1f %6.1f\n', c3(pdFD));
for j = 1:numel(fcs)
fprintf(' IIR Butterworth HP, zero-phase %3d Hz %6.1f %6.1f %6.1f\n', fcs(j), cI3(j,:));
end
for j = 1:numel(pdeg)
fprintf(' polynomial regression, degree %d %6.1f %6.1f %6.1f\n', pdeg(j), c3(regPD(S, pdeg(j))));
end
fprintf('Doppler resolution of the ensemble PRF/n = %.1f Hz (%.2f mm/s axial)\n', PRF/n, PRF/n*lam/2);
%% 6. Velocity sweep: the best band moves, the high-pass fails
fprintf('\nContrast both / slow / fast vessel (dB) versus tissue velocity\n');
fprintf(' vt(mm/s) 2vt/lam(Hz) oracle band SVD band best IIR (fc) best regr. (p) 1st diff\n');
conCurves = zeros(numel(vts), 40);
for iv = 1:numel(vts)
Sv = S_all{iv}; [Uv, Sv2, ~] = svd(Sv, 'econ'); sv = diag(Sv2);
kh = find(sv > 1.05*edgeMP, 1, 'last');
Ev = (abs(Uv).^2) .* (sv.'.^2) / n;
cc = -inf(1, kh); for klo = 1:kh, cc(klo) = contrast(sum(Ev(:, klo:kh), 2)); end
[cb, kb] = max(cc); conCurves(iv, 1:min(40,kh)) = cc(1:min(40,kh));
ci = -inf; for j = 1:numel(fcs), pj = iirPD(Sv, fcs(j)); cj = contrast(pj); if cj > ci, ci = cj; jb = j; pib = pj; end, end
cr = -inf; for j = 1:numel(pdeg), cj = contrast(regPD(Sv, pdeg(j))); if cj > cr, cr = cj; jr = j; end, end
fprintf(' %5.0f %6.1f %2d-%2d %5.1f %5.1f %5.1f %5.1f %5.1f %5.1f (%3d Hz) %5.1f (%d) %5.1f\n', vts(iv), 2*vts(iv)/lam, kb, kh, ...
c3(sum(Ev(:, kb:kh), 2)), c3(pib), fcs(jb), cr, pdeg(jr), contrast(pdOf(fd(Sv))));
end
%% 7. The fast route: eigendecomposition of the n x n Gram matrix S'S
% sigma_k^2 = eig(S'S), V = its eigenvectors; the filter S*Vb*Vb' never needs U.
% Forming S'S squares the condition number: a sigma_k below sqrt(eps)*sigma_1 is lost.
S = S_all{find(vts == vt_main)};
G = S'*S; G = (G + G')/2; % n x n Hermitian, cost O(m n^2)
[W, L] = eig(G); [lg, o] = sort(real(diag(L)), 'descend'); W = W(:, o);
sgD = sqrt(max(lg, 0));
Gs = single(S)'*single(S); Gs = (Gs + Gs')/2;
sgS = sqrt(max(double(sort(real(eig(Gs)), 'descend')), 0));
reS = abs(sgS - s)./s; kbad = find(reS > 0.01, 1);
Vb = W(:, klo_best:k_hi); pdGram = sum(abs(S*Vb).^2, 2)/n; % = (1/n) sum_t |S Vb Vb'|^2, since Vb'Vb = I
fprintf('\nGram route (eig of %dx%d S''S): max rel. error of sigma_1..k_hi = %.1e (double)\n', n, n, max(abs(sgD(1:k_hi) - s(1:k_hi))./s(1:k_hi)));
fprintf(' PD from Gram route vs svd: max rel. difference %.1e\n', max(abs(pdGram - pdSVD)./pdSVD));
fprintf(' single precision: first sigma with > 1 %% error is k = %d at %.1f dB re sigma_1 (sqrt(eps_single) = %.1f dB)\n', ...
kbad, 20*log10(s(kbad)/s(1)), 20*log10(sqrt(eps('single'))));
%% 8. Figures
figure('Position', [40 40 1100 640]);
subplot(2,3,1);
plot(20*log10(s/s(1)), 'k.-'); hold on; grid on;
plot([1 n], 20*log10(edgeMP/s(1))*[1 1], 'b--');
plot([klo_best klo_best], [-90 0], 'r'); plot([k_hi k_hi], [-90 0], 'r');
xlabel('singular value index k'); ylabel('\sigma_k (dB re \sigma_1)'); ylim([-90 5]);
title(sprintf('Singular values, vt = %g mm/s', vt_main)); legend('\sigma_k', 'MP noise edge', 'band', 'Location', 'northeast');
subplot(2,3,2);
Pn = 10*log10(Pk./max(Pk, [], 1));
imagesc(1:n, fax, Pn, [-30 0]); axis xy; colormap(gray); hold on;
plot([1 n], 2*vt_main/lam*[1 1], 'r--'); plot([1 n], -2*vt_main/lam*[1 1], 'r--');
xlabel('rank k'); ylabel('Doppler frequency (Hz)'); title('Spectra of temporal singular vectors (dB)');
subplot(2,3,3);
for iv = 1:numel(vts)
kk = find(isfinite(conCurves(iv,:)) & conCurves(iv,:) ~= 0);
plot(kk, conCurves(iv,kk), 'LineWidth', 1.5); hold on;
end
grid on; xlabel('k_{lo} (k_{hi} from MP edge)'); ylabel('contrast (dB)'); xlim([1 30]);
title('Best k_{lo} moves with tissue velocity');
legend(arrayfun(@(v) sprintf('%g mm/s', v), vts, 'UniformOutput', false), 'Location', 'southeast');
imgs = {pdRaw, pdSVD, pdIIR};
ttl = {'raw PD', sprintf('SVD band %d-%d', klo_best, k_hi), sprintf('IIR high-pass %d Hz', fcs(jI))};
for j = 1:3
subplot(2,3,3+j);
P = reshape(imgs{j}, NX, NZ).'; % rows = depth
imagesc(xg, zg, 10*log10(P/max(P(:))), [-35 0]); axis image;
xlabel('lateral (mm)'); ylabel('depth (mm)');
title(sprintf('%s: %.1f dB', ttl{j}, contrast(imgs{j})));
end
What to look for. Casorati 2304×128, tissue at 8 mm/s peak (52 Hz peak Doppler). \(\sigma_{k} = 0\), −5, −9, −16, −23, −31 dB for k = 1–6, the Marchenko–Pastur edge at −67.6 dB sets \(k_{\mathrm{hi}} = 46\). Vessel/background PD contrast: raw −1.1 dB, SVD band 9–46 15.2 dB, IIR zero-phase high-pass −0.9 to −0.4 dB at 25–150 Hz, polynomial regression −1.1 to −1.0 dB, first difference −0.8 dB. The sweep (vt = 0, 4, 8, 16, 24 mm/s) gives SVD 24.7, 16.5, 15.2, 9.1, 6.4 dB with the oracle \(k_{\mathrm{lo}}\) moving 2, 5, 9, 11, 15, while the best IIR gives 23.1 dB at rest and 1.4 dB or less as soon as tissue moves. The Gram route reproduces σ to \(2.5\times 10^{-11}\) and PD to \(1.8\times 10^{-11}\) in double; in single the first σ with > 1 % error is k = 46 at −66.8 dB (\(\sqrt{\varepsilon_{\mathrm{single}}} = -69.2\) dB). The band is chosen with ground-truth masks, an oracle you do not have in vivo.
m06_noise_floor_mp.mMarchenko–Pastur noise bulk for Casorati shapes, MP density, and the BBP detectability threshold of a rank-1 component · change m, n, σ, spike strength · runtime ≈ 4 s
%% m06_noise_floor_mp.m -- Module 06: the noise floor of the SVD
% Purpose : Singular values of a pure-noise matrix fill the Marchenko-Pastur
% bulk sigma*(sqrt(m)-sqrt(n)) ... sigma*(sqrt(m)+sqrt(n)).
% A rank-1 coherent component of strength theta separates from the
% bulk only if theta > sigma*(m*n)^(1/4) (BBP transition).
% Change : m, n (Casorati shape: pixels x frames), sig (noise std),
% ratios (spike strength / threshold).
% Expect : measured noise edges within ~2 % of theory for m = 1600, n = 80;
% sigma_1 and singular-vector overlaps match the BBP formulas.
% Runtime : ~3 s in Octave.
clear; close all; rng(1);
%% 1. Pure complex Gaussian noise: bulk edges
sig = 1.0; % noise std per entry, E|z|^2 = sig^2
shapes = [1600 80; 1600 400; 4096 128; 96 96];
fprintf('--- pure noise, complex Gaussian, sigma = %.1f\n', sig);
fprintf(' m n max(s) theory min(s) theory spread(dB)\n');
for i = 1:size(shapes,1)
m = shapes(i,1); n = shapes(i,2);
X = sig*(randn(m,n) + 1i*randn(m,n))/sqrt(2);
s = svd(X);
fprintf('%5d %5d %6.2f %6.2f %6.2f %6.2f %5.1f\n', m, n, s(1), sig*(sqrt(m)+sqrt(n)), ...
s(end), sig*(sqrt(m)-sqrt(n)), 20*log10(s(1)/s(end)));
end
fprintf('Gavish-Donoho optimal hard threshold (square, known sigma): %.3f*sqrt(n)*sigma (edge is 2*sqrt(n)*sigma)\n', 4/sqrt(3));
%% 2. Histogram of singular values against the Marchenko-Pastur density
m = 1600; n = 400; c = n/m;
X = sig*(randn(m,n) + 1i*randn(m,n))/sqrt(2);
s = svd(X);
a = (1-sqrt(c))^2; b = (1+sqrt(c))^2; % eigenvalue support of X'X/(sig^2 m)
sg = linspace(sig*sqrt(m*a), sig*sqrt(m*b), 400);
x = sg.^2/(sig^2*m);
p = sqrt(max((b-x).*(x-a),0))./(2*pi*c*x) .* 2.*sg/(sig^2*m); % density of s
figure('Position',[100 100 900 340]);
subplot(1,2,1);
[cnt, ctr] = hist(s, 30); bw = ctr(2)-ctr(1);
bar(ctr, cnt/(sum(cnt)*bw), 1, 'FaceColor', [0.75 0.8 0.9]); hold on;
plot(sg, p, 'r', 'LineWidth', 2);
xlabel('singular value'); ylabel('density');
title(sprintf('Pure noise %dx%d: MP density', m, n));
legend('svd(X)', 'Marchenko-Pastur', 'Location', 'north');
%% 3. Rank-1 coherent component in noise: BBP detectability threshold
m = 1600; n = 80; c = n/m;
thc = sig*(m*n)^(1/4); % detection threshold on theta
edge = sig*(sqrt(m)+sqrt(n));
fprintf('\n--- rank-1 spike in %dx%d noise: theta_c = %.2f, bulk edge = %.2f\n', m, n, thc, edge);
fprintf('theta/theta_c s1(meas) s1(pred) |<v1,v>|^2 meas/pred |<u1,u>|^2 meas/pred\n');
ratios = [0.5 0.8 1.0 1.2 1.5 2 3 4];
ntr = 10; s1m = zeros(size(ratios));
for i = 1:numel(ratios)
th = ratios(i)*thc; acc = zeros(1,3);
for r = 1:ntr
u = randn(m,1) + 1i*randn(m,1); u = u/norm(u); % spatial pattern
v = randn(n,1) + 1i*randn(n,1); v = v/norm(v); % time course
Y = th*(u*v') + sig*(randn(m,n) + 1i*randn(m,n))/sqrt(2);
[U,S,V] = svd(Y, 'econ');
acc = acc + [S(1,1), abs(V(:,1)'*v)^2, abs(U(:,1)'*u)^2]/ntr;
end
tp = th/(sig*sqrt(m)); % normalized strength
if ratios(i) > 1
s1p = sqrt((th^2 + sig^2*m)*(th^2 + sig^2*n))/th;
pv = 1 - c*(1+tp^2)/(tp^2*(tp^2+c)); pu = 1 - (c+tp^2)/(tp^2*(tp^2+1));
else
s1p = edge; pv = 0; pu = 0;
end
s1m(i) = acc(1);
fprintf(' %4.1f %6.2f %6.2f %5.2f / %5.2f %5.2f / %5.2f\n', ...
ratios(i), acc(1), s1p, acc(2), pv, acc(3), pu);
end
subplot(1,2,2);
tt = linspace(0.05, 4.2, 200)*thc;
s1th = edge*ones(size(tt)); k = tt > thc;
s1th(k) = sqrt((tt(k).^2 + sig^2*m).*(tt(k).^2 + sig^2*n))./tt(k);
plot(tt/thc, s1th, 'r', 'LineWidth', 2); hold on;
plot(ratios, s1m, 'ko', 'MarkerFaceColor', 'k');
plot([0 4.2], [edge edge], 'b--');
xlabel('\theta / \theta_c'); ylabel('\sigma_1');
title('Spike emerges only above \theta_c = \sigma (mn)^{1/4}');
legend('BBP prediction', 'measured', 'bulk edge', 'Location', 'northwest');
fprintf('Note: theta_c = %.1f sigma is far below the bulk edge %.1f sigma: a coherent\n', thc/sig, edge/sig);
fprintf('component is detectable even when sigma_1 barely clears the noise bulk.\n');
What to look for. Pure noise 1600×80: \(\sigma_{\max} = 48.54\) vs 48.94 predicted, \(\sigma_{\min} = 31.45\) vs 31.06, a 3.8 dB spread; 96×96 spreads over 41.7 dB. With a rank-1 spike, \(\sigma_{1}\) stays at the bulk edge until \(\theta = \theta_{c} = 18.9\sigma\) and then follows the BBP prediction (51.35 vs 51.42 at \(1.5\theta_{c}\), 86.07 vs 86.18 at \(4\theta_{c}\)); temporal-vector overlap reaches 0.88 at \(2\theta_{c}\) while the spatial overlap is only 0.44.
m06_svd_geometry.mCircle → ellipse, eig vs svd for symmetric, oblique, shear and rotation matrices, power-iteration rates, DORT with two scatterers · change A, r, scatterers · runtime ≈ 2 s
%% m06_svd_geometry.m -- Module 06: SVD geometry, eig vs svd, power iteration, DORT
% Purpose : (1) the unit circle maps to an ellipse with semi-axes sigma_i*u_i;
% (2) eigenvalues and singular values agree only for normal matrices;
% (3) power iteration converges as |lambda2/lambda1|^k;
% (4) DORT: the SVD of an array transfer matrix gives one singular
% value per point scatterer and a focusing law for each.
% Change : A (2x2), the gap ratio r, scatterer positions/reflectivities.
% Expect : sigma = 1.618, 0.618 for the shear; power-iteration slope = log10(r);
% two significant singular values for two point scatterers.
% Runtime : ~2 s in Octave.
clear; close all; rng(1);
%% 1. Circle -> ellipse
A = [1.2 0.9; -0.3 0.6];
[U,S,V] = svd(A);
th = linspace(0, 2*pi, 361); C = [cos(th); sin(th)]; E = A*C;
fprintf('A = [%.2f %.2f; %.2f %.2f]\n', A');
fprintf('sigma = %.4f, %.4f |det A| = %.4f = sigma1*sigma2 = %.4f\n', S(1,1), S(2,2), abs(det(A)), S(1,1)*S(2,2));
fprintf('||A V - U S|| = %.1e, ||A||_F^2 = %.4f = sum sigma^2 = %.4f\n', norm(A*V - U*S), norm(A,'fro')^2, sum(diag(S).^2));
fprintf('v1 at %.1f deg, u1 at %.1f deg (signs of (u_i, v_i) pairs are arbitrary)\n', ...
atan2(V(2,1),V(1,1))*180/pi, atan2(U(2,1),U(1,1))*180/pi);
figure('Position',[100 100 900 420]);
subplot(1,2,1);
plot(C(1,:), C(2,:), 'Color', [0.6 0.6 0.6]); hold on; plot(E(1,:), E(2,:), 'b', 'LineWidth', 2);
for i = 1:2
plot([0 V(1,i)], [0 V(2,i)], '--', 'Color', [0.6 0.6 0.6], 'LineWidth', 1.5);
plot([0 S(i,i)*U(1,i)], [0 S(i,i)*U(2,i)], 'r', 'LineWidth', 2);
end
axis equal; axis([-1.8 1.8 -1.8 1.8]); grid on; xlabel('x_1'); ylabel('x_2');
title('unit circle (grey) -> A x (blue); v_i (dashed) -> \sigma_i u_i (red)');
%% 2. Eigenvalues versus singular values
names = {'symmetric', 'non-symmetric', 'shear', 'rotation 35 deg x 1.1'};
t = 35*pi/180;
mats = {[1.5 0.5; 0.5 0.8], [1.2 0.9; 0.15 0.5], [1 1; 0 1], 1.1*[cos(t) -sin(t); sin(t) cos(t)]};
fprintf('\n%-24s %-26s %-16s %s\n', 'matrix', 'eig', 'svd', 'angle(v1,v2)');
for i = 1:numel(mats)
M = mats{i}; [X,L] = eig(M); l = diag(L); s = svd(M);
if isreal(l)
ang = acos(min(1, abs(X(:,1)'*X(:,2))/(norm(X(:,1))*norm(X(:,2)))))*180/pi;
fprintf('%-24s %8.4f %8.4f %6.4f %6.4f %5.1f deg\n', names{i}, l(1), l(2), s(1), s(2), ang);
else
fprintf('%-24s %6.3f%+6.3fj (pair) %6.4f %6.4f complex\n', names{i}, real(l(1)), abs(imag(l(1))), s(1), s(2));
end
end
%% 3. Power iteration on an 8x8 symmetric matrix
n = 8; [Q,~] = qr(randn(n));
subplot(1,2,2);
rs = [0.5 0.7 0.95]; cols = {'b-', 'r--', 'k-.'}; hp = zeros(1, numel(rs));
for j = 1:numel(rs)
r = rs(j);
lam = [1, r, r*0.75.^(1:n-2)];
A8 = Q*diag(lam)*Q';
x = randn(n,1); K = 80; err = zeros(1,K+1);
for k = 0:K
x = x/norm(x); c1 = Q(:,1)'*x;
err(k+1) = norm(x - c1*Q(:,1))/abs(c1); % tan of angle to q1
x = A8*x;
end
hp(j) = semilogy(0:K, err, cols{j}, 'LineWidth', 1.6); hold on;
kk = 5:min(K, find(err > 1e-13, 1, 'last'));
p = polyfit(kk, log10(err(kk+1)), 1);
fprintf('power iteration r = %.2f: slope %.4f (theory %.4f), iterations to 1e-15 = %d\n', ...
r, p(1), log10(r), ceil(-15/log10(r)));
end
ylim([1e-16 1e2]); grid on; xlabel('iteration k'); ylabel('tan \angle(x_k, q_1)');
title('Power iteration: error ~ r^k'); legend(hp, 'r = 0.5', 'r = 0.7', 'r = 0.95', 'Location', 'southwest');
%% 4. DORT: SVD of the inter-element transfer matrix
c0 = 1540; f0 = 5e6; lam0 = c0/f0; kw = 2*pi/lam0; % m, rad/m
Ne = 64; pitch = 0.3e-3; xe = ((0:Ne-1) - (Ne-1)/2)*pitch; % element x (m)
sc = [-2e-3 30e-3 1.0; 3e-3 32e-3 0.5]; % [x z reflectivity] of two scatterers
G = zeros(Ne, size(sc,1));
for q = 1:size(sc,1)
d = sqrt((xe - sc(q,1)).^2 + sc(q,2)^2);
G(:,q) = exp(-1i*kw*d(:))./sqrt(d(:)); % 2-D Green's function (far-field form)
end
K = G*diag(sc(:,3))*G.'; % K = K.' by reciprocity
K = K + 1e-3*norm(K)*(randn(Ne) + 1i*randn(Ne))/sqrt(2*Ne);
[Uk,Sk,Vk] = svd(K); sk = diag(Sk);
fprintf('\nDORT, 64 elements, two scatterers (refl. 1.0, 0.5): sigma_1..4 / sigma_1 = %.3f %.3f %.4f %.4f\n', sk(1:4)/sk(1));
fprintf('lateral resolution lambda*z/D = %.2f mm; lateral separation of scatterers = %.1f mm\n', lam0*31e-3/(Ne*pitch)*1e3, (sc(2,1)-sc(1,1))*1e3);
figure('Position',[100 100 900 340]);
subplot(1,2,1); semilogy(sk/sk(1), 'ko-'); grid on; xlabel('index i'); ylabel('\sigma_i / \sigma_1');
title('DORT: one singular value per scatterer');
xg = linspace(-8e-3, 8e-3, 401); zf = 31e-3; % back-propagate onto a line at 31 mm
subplot(1,2,2); hq = zeros(1,2);
for q = 1:2
w = conj(Uk(:,q)); % phase-conjugate (time-reversed) law
P = zeros(size(xg));
for ix = 1:numel(xg)
d = sqrt((xe - xg(ix)).^2 + zf^2);
P(ix) = abs(sum(w(:).*exp(-1i*kw*d(:))./sqrt(d(:))));
end
hq(q) = plot(xg*1e3, 20*log10(P/max(P)), 'LineWidth', 1.6); hold on;
[~, im] = max(P); fprintf('singular vector %d focuses at x = %.2f mm\n', q, xg(im)*1e3);
end
hq(3) = plot(sc(:,1)*1e3, [0 0], 'kv', 'MarkerFaceColor', 'k');
ylim([-40 3]); grid on; xlabel('lateral position (mm)'); ylabel('field (dB)');
title('Back-propagated u_1, u_2 at z = 31 mm'); legend(hq, 'conj(u_1)', 'conj(u_2)', 'scatterers', 'Location', 'northwest');
What to look for. Shear: λ = 1, 1 but σ = 1.618, 0.618; symmetric: eigenvectors at 90.0°; non-symmetric: 53.5°. Power-iteration slopes equal \(\log_{10}r\) to four digits (−0.3010, −0.1549, −0.0223) with 50, 97 and 674 iterations to \(10^{-15}\). DORT: \(\sigma /\sigma_{1} = 1.000\), 0.467, then 0.0019; the two singular vectors refocus at −2.08 mm and 2.92 mm on scatterers at −2 and 3 mm.
m06_tsvd_picard.mTruncated SVD and Tikhonov deconvolution of a blurred reflectivity profile, Picard plot, default pinv tolerance · change blur width, noise level · runtime < 2 s
%% m06_tsvd_picard.m -- Module 06: truncated SVD, Tikhonov and the Picard plot
% Purpose : Deconvolve a blurred, noisy 1-D reflectivity profile b = A x + noise,
% where A is a 64 x 64 Gaussian blur (the same problem as Demo 06.5).
% Compare the plain pseudo-inverse, truncated SVD (TSVD) and Tikhonov,
% read the Picard plot (sigma_i, |u_i' b|, |u_i' b|/sigma_i) and see
% why the truncation index sits where |u_i' b| meets the noise floor.
% Change : blur width sg (samples), noise levels nl (dB re signal RMS), n.
% Expect : kappa(A) = 5.7e12 (sigma_64/sigma_1 = 1.75e-13); MATLAB's default
% pinv tolerance (7e-15) keeps all 64 terms, so pinv(A)*b has relative
% error ~1e10 at -40 dB noise. Best TSVD k = 27 (error 0.40), and the
% Picard rule "last i with |u_i' b0| above the noise std" predicts 26;
% Tikhonov at its best alpha gives 0.40 too. At -60 dB the best k moves
% only to 31: sigma_i of a Gaussian blur falls super-exponentially.
% Runtime : < 1 s.
clear; close all; rng(1);
%% 1. Forward model
n = 64; sg = 2.5; % samples, Gaussian blur std (samples)
[I, J] = ndgrid(1:n, 1:n);
A = exp(-(I - J).^2/(2*sg^2))/(sqrt(2*pi)*sg); % symmetric Toeplitz blur, rows sum to ~1
x = zeros(n,1);
x(11:18) = 0.6; % a uniform layer
x(39:50) = 0.35 + 0.02*((39:50) - 39); % a ramped layer
x(28) = 1; x(31) = -0.7; % two point reflectors 3 samples apart
b0 = A*x;
[U, S, V] = svd(A); s = diag(S);
fprintf('kappa(A) = sigma_1/sigma_n = %.2e (sigma_n/sigma_1 = %.2e)\n', s(1)/s(end), s(end)/s(1));
fprintf('default rank/pinv tolerance max(m,n)*eps*sigma_1 = %.1e -> numerical rank %d of %d\n', ...
max(size(A))*eps(s(1)), sum(s > max(size(A))*eps(s(1))), n);
%% 2. Spectral filters at two noise levels
nl = [-40 -60]; % noise re signal RMS (dB)
rmsb = sqrt(mean(b0.^2));
fprintf('\n noise pinv err best TSVD k err best Tikhonov alpha err\n');
for q = 1:numel(nl)
sn = rmsb*10^(nl(q)/20); % noise std per sample
b = b0 + sn*randn(n,1);
beta = U'*b; % data coefficients u_i' b
errK = zeros(n,1);
for k = 1:n
xk = V(:,1:k)*(beta(1:k)./s(1:k));
errK(k) = norm(xk - x)/norm(x);
end
[eK, kB] = min(errK);
alphas = logspace(-6, 0, 121); errA = zeros(size(alphas));
for j = 1:numel(alphas)
f = s.^2./(s.^2 + alphas(j)^2); % Tikhonov filter factors
errA(j) = norm(V*(f.*beta./s) - x)/norm(x);
end
[eA, jA] = min(errA);
ep = norm(pinv(A)*b - x)/norm(x);
fprintf(' %3d dB %8.1e %2d %.3f %.1e %.3f\n', nl(q), ep, kB, eK, alphas(jA), eA);
% Picard prediction: keep terms while |u_i' b0| > noise std
kP = find(abs(U'*b0) > sn, 1, 'last');
fprintf(' last i with |u_i''b0| > noise std: %d\n', kP);
if q == 1, b1 = b; beta1 = beta; errK1 = errK; kB1 = kB; sn1 = sn; end
end
%% 3. Figures (first noise level)
figure('Position', [60 60 1000 380]);
subplot(1,2,1);
semilogy(1:n, s, 'k.-', 1:n, abs(beta1), 'mo', 1:n, abs(beta1)./s, 'b.'); hold on;
semilogy([1 n], sn1*[1 1], 'm--'); semilogy([kB1 kB1]+0.5, [1e-16 1e8], 'r-');
ylim([1e-16 1e8]); grid on; xlabel('index i'); ylabel('magnitude');
legend('\sigma_i', '|u_i^T b|', '|u_i^T b| / \sigma_i', 'noise std', 'best k', 'Location', 'southwest');
title(sprintf('Picard plot, noise %d dB', nl(1)));
subplot(1,2,2);
xk = V(:,1:kB1)*(beta1(1:kB1)./s(1:kB1));
plot(1:n, x, 'k--', 1:n, b1, 'm', 1:n, xk, 'b', 'LineWidth', 1.4); grid on;
xlabel('depth sample'); ylabel('reflectivity');
legend('true x', 'data b', sprintf('TSVD, k = %d', kB1), 'Location', 'northeast');
title(sprintf('TSVD estimate, relative error %.2f', errK1(kB1)));
What to look for. \(\kappa = 5.70\times 10^{12}\); the default tolerance \(7.1\times 10^{-15}\) keeps all 64 terms, so pinv(A)*b has relative error \(8.5\times 10^{9}\) at −40 dB noise. Best TSVD k = 27 (error 0.403) against the Picard prediction 26; Tikhonov reaches 0.397. At −60 dB the best k moves only to 31 (error 0.359).
06.12Self-check
Q1\(\mathbf{A}\) has σ = [10, 3, 0.5, 0.1]. What are \(\lVert \mathbf{A}-\mathbf{A}_{2}\rVert_{F}\), \(\lVert \mathbf{A}-\mathbf{A}_{2}\rVert_{2}\), the energy captured by \(\mathbf{A}_{2}\), and \(\kappa_{2}(\mathbf{A})\)?
\(\lVert \mathbf{A}\rVert_{F}^{2} = 100 + 9 + 0.25 + 0.01 = 109.26\). Tail: 0.25 + 0.01 = 0.26, so \(\lVert \mathbf{A}-\mathbf{A}_{2}\rVert_{F} = \sqrt{0.26}= 0.510\). Spectral-norm error = \(\sigma_{3} = 0.5\). Energy captured = 109/109.26 = 99.76 %. κ = 10/0.1 = 100, so least-squares solutions can amplify relative data error by up to 100 (and \(10^{4}\) if you solve the normal equations).
Q2Why are the eigenvalues of a channel covariance matrix real and non-negative, and its eigenvectors orthogonal? Would that still hold for the matrix \(\mathbf{A} = \begin{bmatrix}1 & 2\\ 0 & 3\end{bmatrix}\)?
\(\mathbf{R} = E[\mathbf{xx}^{H}]\) is Hermitian, so λ is real and eigenvectors for distinct λ are orthogonal (06.1 derivations). It is also PSD: \(\mathbf{w}^{H}\mathbf{Rw}\) \(= E\lvert \mathbf{w}^{H}\mathbf{x}\rvert^{2} \ge 0\), the output power of beamformer \(\mathbf{w}\). For [[1, 2],[0, 3]] the eigenvalues are 1 and 3 (triangular), eigenvectors (1, 0) and (1, 1): angle 45°, not orthogonal. Its singular values are \(\sqrt{7 \pm \sqrt{40}} = 3.65\) and 0.82, different from |λ|.
Q3A Casorati matrix has 128×128 pixels and 300 frames. What are the sizes of \(\mathbf{U}, \Sigma, \mathbf{V}\) in the thin SVD, and what is the cheapest way to compute the filter?
m = 16384, n = 300. Thin SVD: \(\mathbf{U} 16384\times 300\), \(\Sigma 300\times 300\), \(\mathbf{V} 300\times 300\). Cheapest: form the 300×300 Gram matrix \(\mathbf{S}^{H}\mathbf{S}\) (cost \(mn^{2} \approx 1.5\times 10^{9}\) complex multiply-adds), eigendecompose it (\(n^{3} \approx 2.7\times 10^{7}\)), then \(\mathbf{S}_{f} = (\mathbf{S} \mathbf{V}_{b})\mathbf{V}_{b}^{H}\) with cost 2mn·b. You never need the full \(\mathbf{U}\). The Gram route squares κ, acceptable because the band of interest is well above \(\varepsilon \cdot \sigma_{1}^{2}\).
Q4Tissue moves at 10 mm/s axially, \(f_{0} = 6\) MHz, PRF = 1 kHz. What Doppler frequency does it produce, and why does a 50 Hz high-pass fail? Why can the SVD still separate it from blood at the same Doppler?
\(\lambda = 1540/6\times 10^{6} = 0.257\) mm, \(f_{D} = 2v/\lambda = 2\times 10/0.257 = 78\) Hz. The tissue lies above the 50 Hz cutoff and passes with 40–60 dB of excess energy, swamping blood. Raising the cutoff above 78 Hz removes any blood with axial velocity below 10 mm/s. The SVD separates by spatial coherence and energy: the moving tissue is one large, nearly rigid pattern (a few rank-1 terms with high σ), while blood at the same \(f_{D}\) occupies small, independent regions and lower σ. The time courses can overlap in frequency yet live in orthogonal temporal singular vectors because the spatial maps differ.
Q5With the SVD cached, what does changing \(k_{\mathrm{lo}}\) cost, and why do the cross terms vanish in PD = \((1/n)\sum_{t}\lvert S_{f}\rvert^{2}\)?
\(\mathrm{PD}(p) = (1/n)\lVert \mathbf{s}_{f}(p)\rVert^{2}\) where the row \(\mathbf{s}_{f}(p)\) \(= \sum_{k\in \mathrm{band}}\sigma_{k}u_{k}(p)\mathbf{v}_{k}^{H}\). Since \(\mathbf{v}_{k}^{H}\mathbf{v}_{l} = \delta_{kl}\), \(\lVert \mathbf{s}_{f}(p)\rVert^{2}\) \(= \sum_{k}\sigma_{k}^{2}\lvert u_{k}(p)\rvert^{2}\). This is (06.16). With prefix sums over k it is O(m) per change; directly it is O(m·b). No SVD and no per-frame work.
Q6In the truncated-SVD deconvolution, the noise has standard deviation s per sample and \(\sigma_{i} = 10^{-i/4}\). The noise-free data coefficients are \(\lvert \mathbf{u}_{i}^{H}\mathbf{b}_{0}\rvert \approx 0.5\sigma_{i}\) and \(s = 10^{-3}\). Where should you truncate?
The data coefficient is \(\lvert \mathbf{u}_{i}^{H}\mathbf{b}\rvert \approx \sigma_{i}\cdot 0.5\) + noise of size s (the projection of white noise on a unit vector keeps standard deviation s). Signal exceeds noise while \(0.5\cdot 10^{-i/4} > 10^{-3}\), i.e. \(i < 4\cdot \log_{10}500 = 10.8\). Truncate at k ≈ 10. Beyond that each term adds noise amplified by \(1/\sigma_{i}\) (already \(10^{3}\cdot s = 1\) per term at i = 12) and almost no signal.
Q7Why is the distortion matrix over an isoplanatic patch approximately rank 1, and what limits the quality of its first singular vector?
Within an isoplanatic patch every focal point sees the same aberration transmittance H(u) across the aperture. Each row of \(\mathbf{D}\) (one focal point) is then H(u) multiplied by the point's speckle-dependent “virtual guide star” wavefront, which after the focusing operation is a broad, random-phase spot. The rows share the common factor H, so \(\mathbf{D} \approx (\text{speckle coefficients})\cdot H^{T}\) plus fluctuations: rank 1 with \(\mathbf{v}_{1} \approx H\). Quality is limited by the number of independent speckle realizations (more focal points → better averaging, \(\sigma_{1}\) grows faster than the fluctuation \(\sigma_{2}\)), by the patch exceeding the isoplanatic area (the aberration then varies across rows and rank grows), by the size of the initial focal spot, and by noise.
Q8The 2×2 rotation-by-θ matrix has no real eigenvectors. What are its eigenvalues and singular values, and what does that say about using eigenvalues to measure “gain”?
\(\lambda = \cos \theta \pm j \sin \theta = e^{\pm j\theta}\) with complex eigenvectors \((1, \mp j)/\sqrt{2}\). Its singular values are both 1: rotation preserves length (orthogonal matrix, \(\mathbf{A}^{T}\mathbf{A} = \mathbf{I}\)). For a normal matrix \(\lvert \lambda_{i}\rvert = \sigma_{i}\); here both equal 1. For non-normal matrices \(\lvert \lambda \rvert_{\max}\) can be far below \(\sigma_{1}\) (shear: \(\lvert \lambda \rvert = 1, \sigma_{1} = 1.62\)), so eigenvalues describe asymptotic growth of \(\mathbf{A}^{k}\), while \(\sigma_{1}\) is the worst-case one-step gain.
06.13Figures from the literature
Published figures with real data for the decompositions of this module. Links only; open each next to the section it illustrates. Where a free preprint is linked, figure numbers are those of that version.
Singular values, Doppler content and the spatial-similarity matrix on neonate data
J. Baranger, B. Arnal, F. Perren, O. Baud, M. Tanter, C. Demené, “Adaptive spatiotemporal SVD clutter filtering for ultrafast Doppler imaging using similarity of spatial singular vectors,” IEEE Trans. Med. Imaging 37(7), 1574–1586 (2018). doi:10.1109/TMI.2018.2789499; published version under CC BY at archive-ouverte.unige.ch. Figs. 1, 2, 3 and 4.
Fig. 1 shows that the optimal SVD threshold changes with tissue movement, on two ultrafast Doppler acquisitions of a neonate brain: the in vivo version of the rule “the cut is set from the data, not by a fixed rank”. Fig. 2 plots the singular values and the blood-subspace energy behind energy criteria; Fig. 3(a) gives the power spectral density of the temporal singular vectors (neonate brain), the Doppler-content criterion; Fig. 4(a) is the correlation matrix of spatial singular vectors, in which tissue, blood and noise ranks form blocks. Put Fig. 2 next to the spectrum of Demo 06.6: same three regimes, measured.
What the filtered ensemble must look like before localization
C. Errico, J. Pierre, S. Pezet, Y. Desailly, Z. Lenkei, O. Couture, M. Tanter, “Ultrafast ultrasound localization microscopy for deep super-resolution vascular imaging,” Nature 527, 499–502 (2015). doi:10.1038/nature16066. Extended Data Fig. 1 and Fig. 2.
Extended Data Fig. 1 shows a stack of B-mode images over a 2 mm × 1.1 mm cortical region and, after spatiotemporal filtering, the individual decorrelating microbubbles in each frame: the filtered ensemble \(\mathbf{S}_f\) of (06.15) that the localizer sees. Fig. 2 quantifies the spatial resolution of ULM in the rat brain cortex through a thinned-skull window. Tissue residue left in the first becomes false localizations in the second, which is why \(k_{\mathrm{lo}}\) is a ULM design parameter, not a cosmetic one.
Singular vectors of the distortion matrix carry the aberration law, phantom and in vivo
W. Lambert, L. A. Cobus, T. Frappart, M. Fink, A. Aubry, “Distortion matrix approach for ultrasound imaging of random scattering media,” Proc. Natl. Acad. Sci. USA 117(26), 14645–14656 (2020). Open preprint arXiv:1912.05417. Figs. 5, 6 and S4 (preprint numbering).
Fig. 5 retrieves the transmission (aberration) matrix from the SVD of the normalized correlation matrix built from \(\mathbf{D}\): (A) its normalized eigenvalue spectrum, (B) the phase of the first three eigenvectors. Fig. 6 shows aberration correction of in vivo imaging (Strehl-ratio map and confocal image before and after). Fig. S4 displays the phase of the first singular vector for different areas of the in vivo field of view, that is, how the phase law changes from one isoplanatic patch to the next. Compare with the rank-1 card and Figure 06.B in §06.6.
Matrix aberration correction through a skull-mimicking phantom
F. Bureau, J. Robin, A. Le Ber, W. Lambert, M. Fink, A. Aubry, “Three-dimensional ultrasound matrix imaging,” Nature Communications 14, 6793 (2023). doi:10.1038/s41467-023-42338-8 (open access). Figs. 2, 4 and 6.
Fig. 2 applies matrix imaging through a pork-tissue aberrating layer and shows the estimated aberration law; Fig. 4 is the experimental configuration with a head phantom containing a skull; Fig. 6 compares 2D and 3D matrix imaging on a target at z = 38 mm: (a) is the aberration law from 2D matrix imaging with the original and corrected images in (b, c), and (d–f) give the same for the full 3D correction. The law is again a dominant singular vector of a distortion matrix computed patch by patch, the 3D version of §06.6.
06.14Go deeper
- G. Strang, Introduction to Linear Algebra, 5th ed., Wellesley-Cambridge Press, 2016: ch. 6 (eigenvalues, symmetric matrices) and ch. 7 (SVD, PCA, low rank).
- L. N. Trefethen and D. Bau, Numerical Linear Algebra, SIAM, 1997: Lectures 4–5 (SVD and its properties, Eckart–Young), 27 (Rayleigh quotient, power iteration), 31 (computing the SVD).
- G. H. Golub and C. F. Van Loan, Matrix Computations, 4th ed., Johns Hopkins University Press, 2013: ch. 8 (symmetric eigenproblem, Jacobi methods, computing the SVD).
- P. C. Hansen, Rank-Deficient and Discrete Ill-Posed Problems, SIAM, 1998: Picard condition, TSVD and Tikhonov as spectral filters.
- C. Eckart and G. Young, “The approximation of one matrix by another of lower rank,” Psychometrika 1, 211–218, 1936.
- C. Demené, T. Deffieux, M. Pernot, B.-F. Osmanski, V. Biran, J.-L. Gennisson, L.-A. Sieu, A. Bergel, S. Franqui, J.-M. Correas, I. Cohen, O. Baud, M. Tanter, “Spatiotemporal clutter filtering of ultrafast ultrasound data highly increases Doppler and fUltrasound sensitivity,” IEEE Trans. Med. Imaging 34(11), 2271–2285, 2015.
- J. Baranger, B. Arnal, F. Perren, O. Baud, M. Tanter, C. Demené, “Adaptive spatiotemporal SVD clutter filtering for ultrafast Doppler imaging using similarity of spatial singular vectors,” IEEE Trans. Med. Imaging 37(7), 1574–1586, 2018.
- C. Errico, J. Pierre, S. Pezet, Y. Desailly, Z. Lenkei, O. Couture, M. Tanter, “Ultrafast ultrasound localization microscopy for deep super-resolution vascular imaging,” Nature 527, 499–502, 2015.
- W. Lambert, L. A. Cobus, T. Frappart, M. Fink, A. Aubry, “Distortion matrix approach for ultrasound imaging of random scattering media,” Proc. Natl. Acad. Sci. USA 117(26), 14645–14656, 2020.
- W. Lambert, L. A. Cobus, M. Couade, M. Fink, A. Aubry, “Reflection matrix approach for quantitative imaging of scattering media,” Phys. Rev. X 10, 021048, 2020.
- C. Prada and M. Fink, “Eigenmodes of the time reversal operator: a solution to selective focusing in multiple-target media,” Wave Motion 20, 151–163, 1994.
- P. Song, A. Manduca, J. D. Trzasko, S. Chen, “Ultrasound small vessel imaging with block-wise adaptive local clutter filtering,” IEEE Trans. Med. Imaging 36(1), 251–262, 2017.
- M. Gavish and D. L. Donoho, “The optimal hard threshold for singular values is 4/√3,” IEEE Trans. Inf. Theory 60(8), 5040–5053, 2014.
- F. Benaych-Georges and R. R. Nadakuditi, “The singular values and vectors of low rank perturbations of large rectangular random matrices,” J. Multivariate Anal. 111, 120–135, 2012 (the BBP-type formulas used in the noise-floor script).
- N. Halko, P.-G. Martinsson, J. A. Tropp, “Finding structure with randomness: probabilistic algorithms for constructing approximate matrix decompositions,” SIAM Review 53(2), 217–288, 2011.
- B. M. Asl and A. Mahloojifar, “Eigenspace-based minimum variance beamforming applied to medical ultrasound imaging,” IEEE Trans. Ultrason. Ferroelectr. Freq. Control 57(11), 2381–2390, 2010.