Report an errorErrata
Part I · Module 06

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

Assumes

  • Module 05 · Matrices as operators: matrix–vector products, subspaces, projections, least squares, condition number
  • Complex IQ data (phasors as in Module 01) and the Doppler relation \(f_{D} = 2v_{z}/\lambda\)
  • Plane-wave compounded ultrafast acquisition (you know how the frames are made)
Exact formulaclosed form plotted as isSimulationnumerical solution run in this page (JS) or in the module's Octave scriptsApprox. modelsimplified physics; assumptions under the badgeSchematicdrawing for intuition, not computedSimulated ensembles (Demo 06.6, the clutter-spectrum card) come from this page’s own Gaussian-PSF IQ simulator or from m06_svd_clutter_filter.m (Octave); quoted numbers in rule figures are those printed by the MATLAB lab scripts. No Field II or k-Wave output is shown.

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}\mathbf{v} = \lambda\mathbf{v} \;\Leftrightarrow\; (\mathbf{A}-\lambda\mathbf{I})\mathbf{v} = \mathbf{0}\ \text{ with } \mathbf{v}\ne\mathbf{0} \;\Leftrightarrow\; \det(\mathbf{A}-\lambda\mathbf{I}) = 0 \]
(06.1)
\(\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 non-trivial null space of \(\mathbf{A} - \lambda \mathbf{I}\) needs a singular matrix. The determinant is a degree-n polynomial in λ (the characteristic polynomial), so an n×n matrix has exactly n eigenvalues counted with multiplicity, possibly complex.
\[ \begin{aligned} &2\times 2:\quad \lambda^{2} - \tau\lambda + \delta = 0,\qquad \tau = \operatorname{tr}\mathbf{A} = a + d,\qquad \delta = \det\mathbf{A} = ad - bc \\ &\lambda_{1,2} = \frac{\tau}{2} \pm \sqrt{\frac{\tau^{2}}{4} - \delta}\qquad (\text{discriminant } \Delta = \tau^{2} - 4\delta) \end{aligned} \]
(06.2)
\(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)
Δ > 0: two real, distinct eigenvalues. Δ = 0: a repeated eigenvalue, possibly with only one eigenvector (defective). Δ < 0: a complex-conjugate pair and no real invariant direction (the matrix rotates every real vector). Always: \(\sum \lambda_{i} = \operatorname{tr} \mathbf{A}\), \(\prod \lambda_{i} = \det \mathbf{A}\).

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.

\[ \text{Real } \lambda:\quad \lambda\lVert\mathbf{v}\rVert^{2} = \mathbf{v}^{H}\mathbf{A}\mathbf{v} = (\mathbf{A}^{H}\mathbf{v})^{H}\mathbf{v} = (\mathbf{A}\mathbf{v})^{H}\mathbf{v} = \bar{\lambda}\lVert\mathbf{v}\rVert^{2} \;\Rightarrow\; \lambda = \bar{\lambda} \]
(06.3)
\(\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
\[ \begin{aligned} \text{Orthogonal } \mathbf{v}:\quad \lambda_1\mathbf{v}_2^{H}\mathbf{v}_1 &= \mathbf{v}_2^{H}\mathbf{A}\mathbf{v}_1 = (\mathbf{A}\mathbf{v}_2)^{H}\mathbf{v}_1 = \lambda_2\mathbf{v}_2^{H}\mathbf{v}_1 \\ \Rightarrow\quad (\lambda_1-\lambda_2)\,\mathbf{v}_2^{H}\mathbf{v}_1 &= 0 \end{aligned} \]
(06.4)
\(\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{Q}\Lambda\mathbf{Q}^{H} = \sum_i \lambda_i\,\mathbf{q}_i\mathbf{q}_i^{H}, \qquad \mathbf{Q}^{H}\mathbf{Q} = \mathbf{I}, \qquad \lambda_i \in \mathbb{R} \]
(06.5)
\(\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
Spectral theorem: a Hermitian matrix is a weighted sum of orthogonal rank-1 projectors. Repeated eigenvalues still admit an orthonormal eigenbasis (choose one inside the eigenspace). If additionally \(\mathbf{A} \succeq 0\) (all \(\lambda_{i} \ge 0\)), as for \(\mathbf{A}^{H}\mathbf{A}\) or any covariance, the eigenvalues are variances along \(\mathbf{q}_{i}\).

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.

Demo 06.1

Invariant directions of a 2×2 matrix

Exact formula
unit circle, ring of vimage Av (ellipse)eigen-directionprobe v (drag) → Av
Try: drag the probe until \(\mathbf{Av}\) lines up with \(\mathbf{v}\); you have found an eigen-direction. Set c = b (symmetric) and the two eigen-directions lock at 90°. Pull c away from b: they become oblique, merge at Δ = 0 (defective) and vanish when Δ < 0 (rotation): every probe direction then turns.

Power 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{A}^{k}\mathbf{x}_0 = \lambda_1^{k}\Big[c_1\mathbf{q}_1 + \sum_{i\ge 2} c_i\Big(\frac{\lambda_i}{\lambda_1}\Big)^{k}\mathbf{q}_i\Big] \;\Rightarrow\; \tan\angle(\mathbf{x}_k,\mathbf{q}_1) = O\big(\lvert\lambda_2/\lambda_1\rvert^{k}\big) \]
(06.6)
\(\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
For Hermitian \(\mathbf{A}\) the Rayleigh quotient \(\mathbf{x}_{k}^{H}\mathbf{Ax}_{k}\) converges to \(\lambda_{1}\) twice as fast, \(O(\lvert \lambda_{2}/\lambda_{1}\rvert^{2k})\), because the eigenvalue error is quadratic in the vector error. The gap ratio \(\lvert \lambda_{2}/\lambda_{1}\rvert\) sets the cost; Lanczos and randomized SVD are refinements of this one idea.
Demo 06.2

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).
tan∠(xk, q1)|λ1 − Rayleigh quotient|theory rk, r2k (dashed)
Try: r = 0.99 needs about 3400 iterations for \(10^{-15}\); r = 0.1 needs 15. The measured slopes match \(\log_{10}r\) and \(2\cdot \log_{10}r\). A negative \(\lambda_{2}\) gives the same rate (only |r| matters) but the iterate sign alternates.
Ultrasound link

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.

Pitfall

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} = \mathbf{U}\Sigma\mathbf{V}^{H} = \sum_{i=1}^{r}\sigma_i\,\mathbf{u}_i\mathbf{v}_i^{H}, \qquad \sigma_1 \ge \sigma_2 \ge \dots \ge \sigma_r > 0 \]
(06.7)
\(\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
\(\mathbf{U} (m\times m)\) and \(\mathbf{V} (n\times n)\) are unitary; \(\Sigma\) is m×n diagonal with non-negative entries. \(r = \operatorname{rank} \mathbf{A}\). The thin form keeps only the first min(m,n) columns.

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^{H}\mathbf{u}_j = \frac{\mathbf{v}_i^{H}\mathbf{A}^{H}\mathbf{A}\mathbf{v}_j}{\sigma_i\sigma_j} = \frac{\lambda_j\,\mathbf{v}_i^{H}\mathbf{v}_j}{\sigma_i\sigma_j} = \delta_{ij} \]
(06.8)
\(\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
Complete the \(\mathbf{u}_{i}\) to an orthonormal basis of \(\mathbb{C}^{m}\). Then \(\mathbf{AV} = \mathbf{U}\Sigma\), i.e. \(\mathbf{A} = \mathbf{U}\Sigma \mathbf{V}^{H}\).

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.

Demo 06.3

Circle → VH → Σ → U → ellipse

Exact formula
current shapeinput circle, final ellipse (dashed)v1 → σ1u1v2 → σ2u2
Try: step the stage slider through 1 and 2: the first rotation puts \(\mathbf{v}_{1}, \mathbf{v}_{2}\) on the axes, the stretch scales them by \(\sigma_{1}, \sigma_{2}\), the last rotation sends them to \(\sigma_{i}\mathbf{u}_{i}\). Make \(\det \mathbf{A} < 0\) and the stretch flips one axis through zero (a reflection, shown as a signed \(\sigma_{2}\); the true \(\sigma_{2}\) stays positive and the sign moves into \(\mathbf{U}\)). Make the rows proportional (e.g. a = 1, b = 1, c = 0.5, d = 0.5): \(\sigma_{2} = 0\), the ellipse collapses to a segment, rank 1.

What the singular values tell you

QuantityIn terms of the SVDWhy
\(\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
ranknumber 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.

Intuition

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:

\[ \lVert\mathbf{A}-\mathbf{A}_k\rVert_F^{2} = \Big\lVert\sum_{i>k}\sigma_i\mathbf{u}_i\mathbf{v}_i^{H}\Big\rVert_F^{2} = \sum_{i>k}\sigma_i^{2}, \qquad \lVert\mathbf{A}-\mathbf{A}_k\rVert_2 = \sigma_{k+1} \]
(06.9)
\(\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
\[ \begin{aligned} &\text{Eckart–Young–Mirsky:}\quad \min_{\operatorname{rank}\mathbf{B}\le k}\lVert\mathbf{A}-\mathbf{B}\rVert = \lVert\mathbf{A}-\mathbf{A}_k\rVert \\ &(\text{for } \lVert\cdot\rVert_2,\ \lVert\cdot\rVert_F \text{ and every unitarily invariant norm}) \end{aligned} \]
(06.10)
\(\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\)
Proof sketch for \(\lVert \cdot \rVert_{2}\): \(\operatorname{rank} \mathbf{B} \le k\) means \(\operatorname{null} \mathbf{B}\) has dimension ≥ n − k, so it intersects the (k+1)-dimensional \(\operatorname{span} (\mathbf{v}_{1..k+1})\) in some unit \(\mathbf{w}\). Then \(\lVert (\mathbf{A}-\mathbf{B})\mathbf{w}\rVert\) \(= \lVert \mathbf{Aw}\rVert \ge \sigma_{k+1}\).

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.

Demo 06.4

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.
σi keptσi discardedcut at kenergy captured (right axis, %)
Try: turn speckle off: the layered phantom is captured to 99 % energy within a few ranks because horizontal layers are nearly rank 1 (a depth profile times a constant lateral profile); only the cyst and point targets need more. With speckle on, the tail is long and flat: speckle is a random, full-rank matrix, so low rank removes it along with detail. The readout compares the measured \(\lVert \mathbf{A}-\mathbf{A}_{k}\rVert_{F}^{2}\) with \(\sum_{i>k}\sigma_{i}^{2}\).
Ultrasound link

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} = \mathbf{U}\Sigma\mathbf{V}^{H} \;\Rightarrow\; \mathbf{C} = \frac{\mathbf{X}^{H}\mathbf{X}}{N-1} = \mathbf{V}\,\frac{\Sigma^{2}}{N-1}\,\mathbf{V}^{H} \]
(06.11)
\(\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\))
The principal axes are the right singular vectors \(\mathbf{v}_{i}\); the variances along them are \(\sigma_{i}^{2}/(N-1)\); the scores (coordinates of each observation) are \(\mathbf{U}\Sigma\). Working on \(\mathbf{X}\) directly avoids squaring the condition number, which forming \(\mathbf{X}^{H}\mathbf{X}\) does (\(\kappa (\mathbf{C}) = \kappa (\mathbf{X})^{2}\)). Module 07 builds the covariance view from the statistics side.

Pseudo-inverse and the cost of small σ

\[ \mathbf{A}^{+} = \mathbf{V}\Sigma^{+}\mathbf{U}^{H},\quad \Sigma^{+} = \operatorname{diag}(1/\sigma_1,\dots,1/\sigma_r,0,\dots) \;\Rightarrow\; \mathbf{x}^{+} = \mathbf{A}^{+}\mathbf{b} = \sum_{i\le r}\frac{\mathbf{u}_i^{H}\mathbf{b}}{\sigma_i}\,\mathbf{v}_i \]
(06.12)
\(\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{x}^{+}\) is the minimum-norm least-squares solution (Module 05). Noise \(\mathbf{n}\) with variance \(s^{2}\) per sample contributes \(s/\sigma_{i}\) along each \(\mathbf{v}_{i}\): the components with tiny \(\sigma_{i}\) dominate the solution.
\[ \text{Truncated SVD: } \mathbf{x}_k = \sum_{i\le k}\frac{\mathbf{u}_i^{H}\mathbf{b}}{\sigma_i}\,\mathbf{v}_i \qquad \text{vs Tikhonov: } \mathbf{x}_\alpha = \sum_i \frac{\sigma_i^{2}}{\sigma_i^{2}+\alpha^{2}}\,\frac{\mathbf{u}_i^{H}\mathbf{b}}{\sigma_i}\,\mathbf{v}_i \]
(06.13)
\(\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)
Both are spectral filters: TSVD uses a 0/1 filter factor, Tikhonov a smooth one. The discrete Picard condition says a meaningful solution exists only while \(\lvert \mathbf{u}_{i}^{H}\mathbf{b}\rvert\) decays faster than \(\sigma_{i}\); once \(\lvert \mathbf{u}_{i}^{H}\mathbf{b}\rvert\) hits the noise floor, stop.
Demo 06.5

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.
true reflectivity xblurred, noisy data bTSVD estimate xk
σi|uiHb||uiHb|/σicut k
Try: slide k to 64 (the plain pseudo-inverse): the estimate explodes because \(\sigma_{64} \approx 1.8\times 10^{-13}\sigma_{1} (\kappa \approx 5.7\times 10^{12})\). The best k sits where \(\lvert \mathbf{u}_{i}^{H}\mathbf{b}\rvert\) (pink) meets its noise floor. Lower the noise by 20 dB: the floor drops and the optimum k moves right, but only by a few terms, because \(\sigma_{i}\) of a Gaussian blur decays super-exponentially.
Ultrasound link

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.

Pitfall

“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

\[ \mathbf{S} \in \mathbb{C}^{(N_xN_z)\times n},\quad S_{pt} = s(x_p, z_p, t) \;\Rightarrow\; \mathbf{S} = \sum_k \sigma_k\,\mathbf{u}_k\mathbf{v}_k^{H} \]
(06.14)
\(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)
\(\mathbf{u}_{k}\) is a spatial singular vector (an image), \(\operatorname{conj} (\mathbf{v}_{k})\) a temporal singular vector (a time course), \(\sigma_{k}^{2}\) the energy of that separable component.
Schematic Figure 06.A · The Casorati matrix and what its singular vectors meanLayout schematic; sizes are those of Demo 06.6 (40 × 40 px, 80 frames at 1 kHz).
Casorati matrix: frames become columns; the SVD returns image × time-course pairs n frames s(x, z, t), t = 1 … n each frame Nz × Nx pixels e.g. 40 × 40 = 1600 (0.1 mm grid) PRF 1 kHz, n = 80 frames = 80 ms reshape eachframe to a column S: (Nx Nz) × n frames t → = Σk σk × uk reshape uk: spatial map (Nz × Nx image) × vkH: time course over n frames σk² = energy of component k (tissue first, blood middle, noise tail)

Demené et al. (2015) showed that the three signal classes separate along k because they differ in energy and in spatiotemporal coherence:

ClassEnergyCoherenceWhere in the spectrum
Tissue clutter40–60 dB above bloodlarge region moves together, slowly (mm/s) → nearly separablefirst few \(\sigma_{k}\), low-Doppler \(\mathbf{v}_{k}\)
Blood / microbubbleslowsmall structures, fast (cm/s), decorrelate over a few framesmiddle ranks, higher-Doppler \(\mathbf{v}_{k}\)
Electronic noiselowesti.i.d. in space and time → no coherent structuretail: 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:

\[ \mathbf{S}_f = \sum_{k=k_{\mathrm{lo}}}^{k_{\mathrm{hi}}}\sigma_k\,\mathbf{u}_k\mathbf{v}_k^{H} = \mathbf{S}\,\mathbf{V}_b\mathbf{V}_b^{H} \]
(06.15)
\(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
A projection of every pixel's time series onto a data-derived temporal subspace. Contrast this with a fixed temporal high-pass, which projects onto a fixed band of Doppler frequencies regardless of what the tissue is doing.
\[ \text{Power Doppler:}\quad \mathrm{PD}(p) = \frac{1}{n}\sum_t \lvert S_f(p,t)\rvert^{2} = \frac{1}{n}\sum_{k=k_{\mathrm{lo}}}^{k_{\mathrm{hi}}}\sigma_k^{2}\,\lvert u_k(p)\rvert^{2} \]
(06.16)
\(\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)
Because the \(\mathbf{v}_{k}\) are orthonormal, the cross terms vanish. Once the SVD is cached, a new cutoff costs O(band × pixels), which is why the demo's cutoff sliders respond instantly.

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.

Demo 06.6

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.
σk (dB re σ1)band [klo, khi] (drag)RMS Doppler of vk (right axis, Hz)tissue peak Doppler 2vt/λ
computing…
Setup: 40×40 pixels (4×4 mm, 0.1 mm grid), \(f_{0} = 5\) MHz, PRF = 1 kHz, Gaussian PSF (\(\sigma_{x}\) 0.17 mm, \(\sigma_{z}\) 0.10 mm) with IQ phase \(e^{-j4\pi z/\lambda}\). Tissue: 2600 scatterers with a 4 Hz sinusoidal bulk motion (axial, plus 35 % lateral). Three vessels (radius 0.15–0.22 mm, parabolic flow, peak 12–25 mm/s at 80°, 35° and 5° to the lateral axis) ride on the tissue motion. Images are PD in dB, each normalized to its own maximum, 35 dB range. Contrast = mean PD in vessel cores / mean PD in background (> 2.5 radii from any vessel); \(\mathrm{CNR} = (\mathrm{mean} - \mathrm{mean}_{\mathrm{bg}})/\mathrm{std}_{\mathrm{bg}}\) on the dB image. “Best-contrast band” searches all bands at least n/4 ranks wide using the ground-truth masks, an oracle you do not have in vivo. Try: set velocity to 0: both filters work. Raise it to 12 mm/s: the high-pass image fills with tissue at any cutoff that still passes the slow vessel, while the SVD keeps contrast after you raise \(k_{\mathrm{lo}}\) by a few ranks. Drag \(k_{\mathrm{lo}}\) to 1 to see the raw (B-mode-like) PD inside the band panel.
Pitfall: choosing the cutoffs

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.

Ultrasound link: ULM

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.
Schematic Figure 06.B · Distortion-matrix pipeline: changes of basis, then one SVD per isoplanatic patchBlock diagram after Lambert et al. (2020); not computed.
Distortion-matrix aberration correction: changes of basis, then one SVD per isoplanatic patch 1. Record R transmit × receive responses(element or plane-wave basis) 2. Focus change of basis to focal pointsconfocal image = diagonal 3. Distortion matrix D each focused wavefront multipliedby the conjugate ideal wavefront 4. Isoplanatic patch D ≈ speckle coeff. × H(u)ᵀrank ≈ 1 plus fluctuations 5. SVD of D u₁ ≈ H: aberration phase lawσ₁ ≫ σ₂ with enough speckle 6. Correct apply conj(u₁) in transmitand receive, refocus the patch Patch size trades speckle averaging (more focal points: better u₁) against isoplanatism (larger patch: the law varies, rank grows).

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.

Tissue lives in the first few singular vectors, blood in the middle, noise at the bottom.
tissue 40–60 dB above bloodvt = 0: tissue ≈ rank 1blood band ends at the MP edge

\(\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.

Simulationσ_k values printed by m06_svd_clutter_filter.m (Octave, 2304 px × 128 frames); dashes interpolate between quoted points.
An ordering by energy, not a law. Large vessels and slow flow are spatially coherent and climb into the tissue ranks; moving tissue spreads downward into the blood ranks; at depth, noise can exceed blood so the band shrinks to nothing.
Rank 1 means separable, not static: a uniform Doppler shift is still rank 1; what raises the rank is speckle sliding across the PSF.
translation \(1\sigma_{z} \to 3\) ranks\(10\sigma_{z} \to 13\) ranks(to −50 dB residual)

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:

SimulationRanks from this module’s Gaussian-PSF speckle simulation (40×40 px, 80 frames, σz 0.10 mm, 2600 scatterers; reproduced in NumPy: 1, 3, 6, 8, 13). Dashed 2 + D/σz is a rule of thumb for D > 0 (1 + D/σz would undershoot every point by 1 to 2 ranks).
\[ D = 0 \to 1,\quad 0.1\ \mathrm{mm} \to 3,\quad 0.3\ \mathrm{mm} \to 6,\quad 0.5\ \mathrm{mm} \to 8,\quad 1.0\ \mathrm{mm} \to 13 \]
\(D\)
axial translation of the tissue over the ensemble, mm
\(\to\)
"requires" (number of ranks to reach −50 dB tissue residual)
Roughly one extra rank per \(\sigma_{z}\) of displacement. Lateral motion acts the same way with \(\sigma_{x}\).
The count depends on the required residual level, the PSF size and the motion profile (non-rigid or rotational motion is worse than translation). Out-of-plane motion decorrelates speckle and is not a low-rank process at all.
SVD filters beat high-pass filters when tissue moves because they separate by spatial coherence, not only by Doppler frequency.
vt = 8 mm/s: SVD 15.2 dBbest IIR −0.4 dBvt = 0: 24.7 vs 23.1 dB

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.

SimulationContrast values printed by the velocity sweep of m06_svd_clutter_filter.m (Octave).
At rest a fixed filter is as good (regression 25.8 dB, SVD 24.7 dB). The SVD loses too when tissue motion spreads over the blood ranks (contrast falls 10 dB from 4 to 24 mm/s) or when vessels are large enough to be coherent.
The tissue/blood cut is set from the data, by the spatial-similarity matrix or the Doppler content of the temporal singular vectors, not by a fixed rank.
oracle \(k_{\mathrm{lo}}\): 2 → 15for vt 0 → 24 mm/s\(k_{\mathrm{hi}}\) from MP edge: 45–47

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})\).

SimulationOracle k_lo and MP-edge k_hi printed by m06_svd_clutter_filter.m (Octave).
Each estimator has a failure regime: the similarity matrix needs spatially structured tissue (it shows no block in homogeneous simulated speckle), the Doppler rule fails when tissue and flow Doppler overlap, and knees are often absent. Ground-truth "best band" numbers in this module are oracles.
Noise singular values follow Marchenko–Pastur: the noise floor edge is \(\sigma_{\mathrm{noise}}(\sqrt{M}+ \sqrt{N})\).
1600×80: 31.1σ … 48.9σspread 4.0 dB (3.8 measured)BBP: \(\theta_{c} = \sigma (MN)^{1/4}\)

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\).

Exact formulaMarchenko–Pastur singular-value densities for 1600×80 and 96×96 and the BBP threshold σ(MN)^(1/4).
Needs i.i.d. noise of known σ. Beamformed noise is spatially correlated (PSF-shaped), which lowers the effective M; depth-dependent TGC makes σ non-uniform. Estimate σ from the median singular value or a no-transmit acquisition.
Eckart–Young: the truncated SVD is the optimal rank-k approximation in both the Frobenius and the spectral norm.
\(\lVert A-A_{k}\rVert_{F}^{2} = \sum_{i>k}\sigma_{i}^{2}\)\(\lVert A-A_{k}\rVert_{2} = \sigma_{k+1}\)rival loses 1.5–2.2×

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.

SimulationLeft: illustrative σ_i = e^(−(i−1)/5), exact tail sums. Right: error ratios printed by m06_svd_cyst.m (Octave).
Optimal for squared error on the given matrix, not for the task: a low-rank image can have better CNR (9.4 at k = 2 vs 3.8 at full rank in the cyst script) and still be useless (separable streaks, a square cyst).
Judge a low-rank fit by its residual, not by "energy captured".
rank 1 = 97.3 % energy99 % at k = 2099.9 % at k = 95

\(\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.

SimulationJacobi SVD (JS) of a seeded 48×48 log-compressed speckle image with a −15 dB cyst.
For zero-mean data (IQ, noise-like speckle) energy fractions are meaningful; for power or dB images they are dominated by the DC term.
\(\sigma^{2}\) are the eigenvalues of \(S^{H}S\), but never form \(S^{H}S\) in floating point when κ is large.
\(\kappa (S^{H}S) = \kappa (S)^{2}\)single: lost below ≈ −69 dBdouble: ≈ −156 dB

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.

Exact formulaIllustrative linear spectrum; thresholds √ε for IEEE single (2⁻²³) and double (2⁻⁵²).
For a clutter filter in double precision the Gram route is safe (the band sits far above −156 dB). It matters for single-precision GPU code, for regularized inversions where small σ are the point, and for least squares via the normal equations (Module 05).
Use the frames × frames Gram matrix to get V, then U = SV/σ, or skip U entirely: that is how fast SVD filters run.
cost \(O(MN^{2}) + O(N^{3})\)16384×300: \(1.5\times 10^{9}\) CMAC\(N^{3} = 2.7\times 10^{7}\)

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}\).

Exact formulaOperation counts MN² and N³ for M = 16 384.
Precision (previous rule). For very long ensembles (N in the thousands) the \(N^{3}\) step and memory dominate; then randomized or block-Krylov methods that compute only the leading \(k_{\mathrm{hi}}\) vectors, or sliding-window updates, win.
Block-wise (local) SVD helps when clutter is spatially non-stationary.
rank ≤ \(\min (m_{\mathrm{block}}, N)\)cost × overlap factor

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.

Approx. modelAssumes blood σ ∝ √m (energy proportional to block pixels) and the MP edge σ(√m + √N); relative to the 2304-pixel global SVD.
Small blocks raise the noise floor relative to signal (a smaller M shrinks the MP edge less than it shrinks blood energy) and leave block seams; cutoffs must be automatic because there are hundreds of blocks.
Ensemble length sets Doppler resolution: Δf = PRF/N, and it also sets how far the tissue moves.
1 kHz, 128 frames: 7.8 Hz= 1.20 mm/s at 5 MHzULM: hundreds of frames at 0.5–1 kHz

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.

Exact formulaΔv = (λ/2)·PRF/N at 5 MHz, PRF 1 kHz.
Δf is a resolution, not an accuracy: the mean frequency of a temporal vector can be estimated far more finely than PRF/N at high SNR (Batch 2, estimation theory).
Power iteration converges as \(\lvert \lambda_{2}/\lambda_{1}\rvert^{k}\); the Rayleigh quotient twice as fast.
r = 0.5: 50 iterations to \(10^{-15}\)r = 0.99: ≈ 3400

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.

Exact formulaError r^k and Rayleigh-quotient r^(2k) lines; iterations to 10⁻¹⁵ = ln(10⁻¹⁵)/ln r.
Needs a gap; a start vector with \(c_{1} = 0\) never converges in exact arithmetic. The doubled Rayleigh-quotient rate needs a Hermitian (or normal) A; for a non-normal A it converges only at \(\lvert \lambda_{2}/\lambda_{1}\rvert^{k}\). Subspace iteration, Lanczos and randomized SVD extend the idea to several vectors and accelerate it.
Singular values are perfectly conditioned; eigenvalues of non-normal matrices are not.
\(\lvert \Delta \sigma_{i}\rvert \le \lVert E\rVert_{2}\) (Weyl)[[1,1],[δ,1]]: \(\Delta \lambda = \sqrt{\delta}\)

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.

Exact formulaClosed-form eigenvalues 1 ± √δ and singular values of [[1, 1], [δ, 1]].
Singular vectors are not equally robust: their sensitivity scales with 1/gap between neighbouring σ (next rule).
Singular vectors are unique only up to a phase, and only when σ is isolated: compare subspaces, not vectors.
(\(\mathbf{u}e^{j\varphi}, \mathbf{v}e^{j\varphi}\)) is as valid\(\sin \theta \lesssim \lVert E\rVert /\text{gap}\)

\(\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.

Exact formulaClosed-form tilt ½·atan(2‖E‖/gap) of the top singular vector of diag(1, 1 − gap) + E, and the bound asin(‖E‖/gap).
Averaging singular vectors across blocks, ensembles or sliding windows requires phase alignment (or working with \(\lvert u_{k}\rvert\) or projectors). Inside the flat noise bulk the gaps are tiny, so individual vectors there are meaningless.
An eigenvector of the spatial covariance or the time-reversal operator is a focusing law: one significant σ per resolved scatterer (DORT).
2 scatterers → σ 1, 0.47, then 0.002foci −2.08, 2.92 mm (true −2, 3)

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).

SimulationMonochromatic (5 MHz) free-space Green’s functions, 64 elements, two point scatterers at 30 mm, no noise; SVD and refocused fields computed in the page.
Scatterers closer than about a resolution cell (λz/D = 0.5 mm here) mix in the eigenvectors; in speckle there is no dominant scatterer and only a patch average (distortion matrix) restores a rank-1 structure.
Truncated SVD and Tikhonov are spectral filters; truncate where \(\lvert u_{i}^{H}b\rvert\) hits the noise floor (Picard).
\(\kappa = 5.7\times 10^{12}\)best k = 27, Picard rule 26−20 dB noise → k = 31

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.

SimulationCirculant Gaussian blur (N = 64) of a seeded sparse profile, −40 dB white noise; Picard coefficients via FFT in the page.
Assumes white noise and a known forward model; model error acts like structured noise and lowers the useful k. MATLAB's default pinv/rank tolerance (≈ \(10^{-14}\sigma_{1}\)) is a machine-precision rule, not a noise rule.
PCA is the SVD of centered data; removing the temporal mean is a degree-0 wall filter.
\(C = V\Sigma^{2}V^{H}/(N-1)\)scores = \(U\Sigma\)

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.

Simulation150 seeded Gaussian points; top singular vector of the uncentered and centered data (closed-form 2×2 eigen-solve).
Whether to center (and along which axis) changes the answer: centering the Casorati matrix in time removes static tissue before the SVD, so \(\sigma_{1}\) then describes motion, not brightness.

06.9Cheat sheet

ConceptFormulaUltrasound 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}\) unitarychannel covariance, coherence factor, eigenspace MV
Power iterationerror \(\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 tissueuniform 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.

Download the scripts: m06_svd_cyst.m · m06_svd_clutter_filter.m · m06_noise_floor_mp.m · m06_svd_geometry.m · m06_tsvd_picard.m. Base MATLAB R2019b+ or GNU Octave 8, no toolboxes; all scripts in the repository.

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.