Report an errorErrata
Part II · Module 14

Optimization & automatic differentiation

Sound-speed maps, aberration laws and QUS parameter fits are now computed by iterating on a cost: beamform with the current guess, score the image or the residual, differentiate, step. This module rebuilds the optimizer's side of that loop (step size, conditioning, Newton-type methods, Adam), the reason imaging costs trap optimizers (cycle skipping), and the derivative machinery (dual numbers, reverse mode, complex step, Wirtinger calculus) that differentiable beamforming runs on.

You will be able to

  • Predict the iteration count of gradient descent and momentum from \(\kappa\), and fix slow convergence by scaling rather than by tuning
  • Choose between gradient descent, Gauss–Newton, Levenberg–Marquardt and Adam for a given fit, and set up a line search
  • Quantify cycle skipping (basin \(\pm T/2\), minima every period) and design envelope, low-frequency or multiscale costs that widen the basin
  • Build an autofocus sound-speed estimator: a time-tied ROI, a metric that is actually sensitive to focus, an exact gradient, and a safe ascent
  • Compute exact derivatives with dual numbers, reverse mode or the complex step, and take gradients of real losses of complex IQ data correctly

Assumes

  • Module 05 · Matrices as operators: conditioning \(\kappa\), least squares, QR instead of normal equations
  • Module 07 · Random vectors, covariance & correlation: coherence vs assumed sound speed; Module 11 · Correlation & time-delay estimation: false correlation peaks at multiples of the RF period
  • Module 12 · Estimation theory & the Cramér–Rao bound: CRLB, Fisher information; Module 13 · Inverse problems and regularization: Tikhonov, ISTA, proximal steps
  • Plane-wave DAS on IQ data: delay, interpolate, rotate by \(e^{j\omega_0\tau}\), sum
Exact formulaclosed form plotted as isSimulationnumerical run in this page (optimizer iterations, delay-and-sum of simulated IQ channel data, speckle Monte Carlo, finite differences in floating point) or in the Octave scripts belowApprox. modelsimplified physics; the assumptions are named under the badgeSchematicdrawing for intuition, not computedNo figure on this page comes from k-Wave, Field II or a published differentiable-beamforming code; the autofocus and aberration demos run their own small beamformers in JavaScript, mirrored by m14_autofocus_sound_speed.m.

14.1Gradient descent, the step size and the condition number

Every smooth cost looks quadratic near its minimum, so the quadratic tells you how every gradient method behaves in the end game. Take

\[ f(\mathbf{x}) = \tfrac12\,\mathbf{x}^{T}\mathbf{A}\mathbf{x} - \mathbf{b}^{T}\mathbf{x}, \qquad \nabla f = \mathbf{A}\mathbf{x} - \mathbf{b}, \qquad \mu = \lambda_{\min} \le \dots \le L = \lambda_{\max}, \qquad \kappa = \frac{L}{\mu} \]
(14.1)
\(\mathbf{A}\)
Hessian (symmetric positive definite)
\(\mu,\ L\)
smallest and largest Hessian eigenvalues: strong-convexity constant and gradient Lipschitz constant
\(\kappa\)
condition number of the Hessian, dimensionless
\(f(\mathbf{x})\)
quadratic objective
\(\mathbf{x}\)
parameter vector
\(\mathbf{b}\)
linear term; the minimizer solves \(\mathbf{A}\mathbf{x} = \mathbf{b}\)
\(\nabla f\)
gradient of \(f\)
\(\lambda_{\min},\ \lambda_{\max}\)
smallest and largest eigenvalues of \(\mathbf{A}\)
\(^{T}\)
matrix transpose
For a nonquadratic cost read \(\mu\) and \(L\) off the Hessian at the solution.

Gradient descent \(\mathbf{x}_{k+1} = \mathbf{x}_k - \alpha\nabla f(\mathbf{x}_k)\) acts on the error \(\mathbf{e} = \mathbf{x} - \mathbf{x}^*\) one eigen-direction at a time:

\[ e_{k+1,i} = (1 - \alpha\lambda_i)\, e_{k,i} \;\;\Rightarrow\;\; \text{stable iff } 0 < \alpha < \frac{2}{L}, \qquad \rho(\alpha) = \max\left( \lvert 1 - \alpha\mu \rvert,\ \lvert 1 - \alpha L \rvert \right) \]
(14.2)
\(e_{k,i}\)
error of eigen-mode i after k steps
\(\alpha\)
fixed step size, units of 1/curvature
\(\lambda_i\)
eigenvalue (curvature) of mode i, between \(\mu\) and \(L\)
\(\mu,\ L\)
as in (14.1)
\(\rho(\alpha)\)
worst-case contraction factor per iteration
\(\lvert\cdot\rvert\)
absolute value
Each mode shrinks by its own factor. The stiff mode (\(\lambda = L\)) sets the largest usable step; the flat mode (\(\lambda = \mu\)) then crawls at \(1 - \alpha\mu\).
\[ \alpha^* = \frac{2}{L + \mu}, \qquad \rho^* = \frac{\kappa - 1}{\kappa + 1}, \qquad k(\varepsilon) = \frac{\ln(1/\varepsilon)}{\ln\frac{\kappa+1}{\kappa-1}} \approx \frac{\kappa}{2}\ln\frac{1}{\varepsilon} \]
(14.3)
\(\alpha^*\)
optimal fixed step, in units of 1/curvature
\(\rho^*\)
error contraction factor per iteration
\(\varepsilon\)
target error reduction, e.g. \(10^{-6}\)
\(k(\varepsilon)\)
iterations to reduce the error by \(\varepsilon\)
\(\kappa,\ \mu,\ L\)
as in (14.1)
\(\ln\)
natural logarithm
The optimal fixed step equalizes the two extreme modes, \(\lvert 1 - \alpha^*\mu\rvert = \lvert 1 - \alpha^* L\rvert\). \(\kappa = 100\) and \(\varepsilon = 10^{-6}\): \(\rho^* = 0.980\), 691 iterations. The safe default \(\alpha = 1/L\) gives \(\rho = 1 - 1/\kappa = 0.990\) and up to 1375.

Momentum adds a fraction of the previous step. Both classical forms reach a rate in \(\sqrt{\kappa}\) instead of \(\kappa\):

\[ \begin{gathered} \text{heavy ball (Polyak):}\quad \mathbf{x}_{k+1} = \mathbf{x}_k - \alpha\nabla f(\mathbf{x}_k) + \beta(\mathbf{x}_k - \mathbf{x}_{k-1}), \\ \alpha = \frac{4}{(\sqrt{L} + \sqrt{\mu})^{2}},\ \ \beta = \left(\frac{\sqrt{\kappa} - 1}{\sqrt{\kappa} + 1}\right)^{2},\ \ \rho = \frac{\sqrt{\kappa} - 1}{\sqrt{\kappa} + 1} \end{gathered} \]
(14.4)
\(\mathbf{x}_k\)
iterate after k steps
\(\nabla f\)
gradient, as in (14.1)
\(\alpha\)
step size, units of 1/curvature
\(\beta\)
momentum coefficient, dimensionless
\(\mu,\ L,\ \kappa\)
as in (14.1)
\(\rho\)
asymptotic contraction factor per iteration
\[ \text{Nesterov:}\quad \mathbf{y} = \mathbf{x}_k + \beta(\mathbf{x}_k - \mathbf{x}_{k-1}),\ \ \mathbf{x}_{k+1} = \mathbf{y} - \alpha\nabla f(\mathbf{y}), \quad \alpha = \frac{1}{L},\ \ \beta = \frac{\sqrt{\kappa} - 1}{\sqrt{\kappa} + 1},\ \ \rho = 1 - \frac{1}{\sqrt{\kappa}} \]
(14.5)
\(\beta\)
momentum coefficient, dimensionless, \(0 \le \beta < 1\)
\(\mathbf{y}\)
look-ahead point where Nesterov evaluates the gradient
\(\mathbf{x}_k\)
iterate after k steps
\(\nabla f\)
gradient, as in (14.1)
\(\alpha\)
step size, \(1/L\)
\(L,\ \kappa\)
as in (14.1)
\(\rho\)
asymptotic contraction factor per iteration
Per mode, each method is a 2 × 2 linear recursion with characteristic polynomial \(r^2 - (1 + \beta - \alpha\lambda)r + \beta\) (heavy ball) or \(r^2 - (1 + \beta)(1 - \alpha\lambda)r + \beta(1 - \alpha\lambda)\) (Nesterov). The tuned values put a double root on the slowest mode, so the error decays as \(k\rho^k\): at \(\kappa = 100\) the measured counts are 93 and 155 against rate-only predictions of 69 and 131. Gradient descent needs 691.
Demo 14.1

Gradient descent and momentum on a quadratic

SimulationIterations of each method run in JS on a 2-D quadratic; the pink reference curve is the exact spectral radius of the 2 × 2 recursions.
iterates / measured errorpredicted ρk from the exact spectral radiuscontours of f
Try: with gradient descent press Optimal and raise \(\kappa\): iterations grow linearly (69, 691, 6908 at \(\kappa\) = 10, 100, 1000). Push \(\alpha L\) past 2: the stiff mode flips sign and grows. Switch to heavy ball, press Optimal: the path spirals and the count scales with \(\sqrt{\kappa}\) (27, 93, 315). The pink line is \(\rho^k\) from the exact spectral radius of the 2 × 2 recursions, valid for any \(\alpha\) and \(\beta\).
Ultrasound link: scale before you tune

A joint fit of sound speed (≈ 1540 m/s, sensitivity per m/s) and an amplitude or attenuation term (order 1) mixes column norms that differ by \(10^3\), so \(\kappa(\mathbf{J}^{T}\mathbf{J}) \approx 10^6\): the MATLAB lab gets \(1.22 \times 10^6\), which would cost gradient descent about \(8 \times 10^6\) iterations. Dividing each column by its norm (Jacobi scaling, a diagonal change of variables) drops it to 1.17. The Gaussian-pulse fit of m14_gauss_newton_lm.m has \(\kappa = 1.8 \times 10^3\) in (1, µs, µs, MHz) units, \(2 \times 10^{22}\) in SI units, and 3.7 after scaling. Units are a preconditioner whether you choose them or not.

Pitfall: a small gradient is not a small error

\(\lVert\mathbf{x} - \mathbf{x}^*\rVert \le \lVert\nabla f(\mathbf{x})\rVert/\mu\). With \(\kappa = 10^4\), stopping at \(\lVert\nabla f\rVert = 10^{-6} L\) can leave an error of \(10^{-2}\) in the flat direction. Stop on the relative change of the parameters you care about (m/s, dB/cm/MHz) and report it in those units.

14.2Line search, Newton, Gauss–Newton and Levenberg–Marquardt

Without \(L\) you cannot pick \(\alpha\) in advance. A backtracking line search finds a step that makes enough progress along a descent direction \(\mathbf{d}\) (\(\nabla f^{T}\mathbf{d} < 0\)):

\[ \text{Armijo: accept } \alpha \text{ if } f(\mathbf{x} + \alpha\mathbf{d}) \le f(\mathbf{x}) + c_1\,\alpha\,\nabla f^{T}\mathbf{d}, \quad c_1 = 10^{-4}; \quad \text{otherwise } \alpha \leftarrow \alpha/2 \]
(14.6)
\(f\)
objective function, as in (14.1)
\(\mathbf{x}\)
current iterate
\(\mathbf{d}\)
descent direction (\(\nabla f^{T}\mathbf{d} < 0\))
\(\alpha\)
trial step length along \(\mathbf{d}\); halved until accepted
\(c_1\)
sufficient-decrease fraction, dimensionless
\(\nabla f\)
gradient at \(\mathbf{x}\)
\(\leftarrow\)
assignment: replace \(\alpha\) by \(\alpha/2\)
The right-hand side is the tangent line tilted up by the factor \(c_1\): the step must deliver a fixed fraction of the decrease predicted by the gradient. Adding the curvature (Wolfe) condition \(\nabla f(\mathbf{x}+\alpha\mathbf{d})^{T}\mathbf{d} \ge c_2\nabla f^{T}\mathbf{d}\) rules out steps that are too short (Nocedal & Wright, ch. 3).

Newton's method uses the curvature itself, which makes it affine invariant: scaling the parameters changes nothing, and \(\kappa\) disappears from the rate.

\[ \mathbf{d} = -\mathbf{H}^{-1}\nabla f, \qquad \lVert \mathbf{e}_{k+1} \rVert \le C\,\lVert \mathbf{e}_k \rVert^{2} \ \text{ near } \mathbf{x}^* \]
(14.7)
\(\mathbf{d}\)
Newton step
\(\mathbf{H}\)
Hessian matrix \(\nabla^2 f\) at the current iterate
\(\nabla f\)
gradient, as in (14.1)
\(\mathbf{e}_k\)
error \(\mathbf{x}_k - \mathbf{x}^*\) after k steps
\(\mathbf{x}^*\)
minimizer
\(C\)
constant set by the third derivative and the Hessian
\(\lVert\cdot\rVert\)
Euclidean norm
Quadratic convergence: the number of correct digits roughly doubles per step. Far from \(\mathbf{x}^*\) the Hessian \(\mathbf{H}\) can be indefinite and the step can go uphill; damping, a line search or a trust region fixes that.

Most estimation problems in ultrasound are nonlinear least squares: echo-model fits, backscatter and attenuation spectra (Module 27), delay and phase-screen fits. Write the residual \(\mathbf{r}(\mathbf{\theta})\) = model − data and \(f = \tfrac12\lVert\mathbf{r}\rVert^2\):

\[ \nabla f = \mathbf{J}^{T}\mathbf{r}, \qquad \nabla^{2} f = \mathbf{J}^{T}\mathbf{J} + \sum_i r_i\, \nabla^{2} r_i \]
(14.8)
\(\mathbf{r}\)
residual vector, model minus data, in data units
\(\mathbf{J}\)
Jacobian \(\partial r_i/\partial\theta_j\)
\(\mathbf{\theta}\)
parameter vector
\(f\)
least-squares objective, \(\tfrac12\lVert\mathbf{r}\rVert^2\)
\(r_i\)
element i of \(\mathbf{r}\)
\(\nabla^{2}\)
Hessian (matrix of second derivatives) with respect to \(\mathbf{\theta}\)
\(^{T}\)
matrix transpose
The second term is small when the residuals are small or nearly linear in \(\mathbf{\theta}\). Dropping it gives Gauss–Newton, whose matrix is always positive semidefinite.
\[ \text{Gauss–Newton: } \mathbf{J}\mathbf{\delta} \approx -\mathbf{r} \ \ (\text{least squares, QR}), \qquad \text{LM: } \left(\mathbf{J}^{T}\mathbf{J} + \lambda\,\mathrm{diag}(\mathbf{J}^{T}\mathbf{J})\right)\mathbf{\delta} = -\mathbf{J}^{T}\mathbf{r}, \qquad \mathrm{cov}(\hat{\mathbf{\theta}}) \approx \sigma^{2}(\mathbf{J}^{T}\mathbf{J})^{-1} \]
(14.9)
\(\mathbf{\delta}\)
parameter update
\(\lambda\)
Levenberg–Marquardt damping, dimensionless
\(\sigma^2\)
noise variance per data sample
\(\mathrm{cov}(\hat{\mathbf{\theta}})\)
linearized covariance of the estimate at convergence
\(\mathbf{J},\ \mathbf{r},\ \mathbf{\theta}\)
as in (14.8)
\(\hat{\mathbf{\theta}}\)
estimate at convergence
\(\mathrm{diag}(\cdot)\)
matrix keeping only the diagonal
\(\mathrm{cov}\)
covariance matrix
\(^{T},\ ^{-1}\)
matrix transpose, matrix inverse
\(\lambda \to 0\) recovers Gauss–Newton; \(\lambda \to \infty\) gives a short step along the (diagonally scaled) negative gradient. Divide \(\lambda\) by 10 after a successful step, multiply by 10 after a failed one (Levenberg 1944, Marquardt 1963). At the solution, \(\sigma^2(\mathbf{J}^{T}\mathbf{J})^{-1}\) is the Gaussian-noise CRLB of Module 12 evaluated at the estimate: the optimizer hands you the error bars.

The MATLAB lab fits \(A\,e^{-(t-t_0)^2/2\sigma^2}\cos\!\left(2\pi f(t - t_0)\right)\) to a noisy 4.5 MHz echo (peak SNR 26 dB). From a start 40 ns and 0.3 MHz off, Gauss–Newton converges in 13 iterations and LM in 12; gradient descent with Armijo needs 10 828 in raw units and 51 after Jacobi scaling. The linearized standard deviation of \(t_0\) at the solution is 0.69 ns. From a start 100 ns off (more than a quarter period, 56 ns) scaled gradient descent, Gauss–Newton and LM all land at \(t_0\) = 2.106 µs with \(A < 0\): half a period late with the polarity flipped, a local minimum whose residual is 2.6 times the noise level. Small gradient steps from the same start happen to follow the valley back to the right answer: basins of attraction belong to the algorithm, not only to the cost.

14.3Curved valleys, stochastic gradients and Adam

The Rosenbrock function \(f = (1 - x)^2 + 100(y - x^2)^2\) is the standard caricature of a fit with strongly coupled parameters (delay and frequency, sound speed and depth). Its minimum at (1, 1) has a Hessian \(\begin{bmatrix} 802 & -400 \\ -400 & 200 \end{bmatrix}\) with \(\kappa \approx 2508\), and the valley floor curves, so no fixed linear rescaling straightens it. It is a sum of squares with \(\mathbf{r} = \left(10(y - x^2),\ 1 - x\right)\), so Gauss–Newton applies.

When the cost is an average over many samples (pixels, frames, training images), the gradient of a random subset is an unbiased but noisy estimate. With a constant step the iterates do not converge; they settle into a noise ball. For one mode of curvature \(\lambda\) and gradient-noise variance \(\sigma^2\):

\[ e_{k+1} = (1 - \alpha\lambda)\,e_k - \alpha\, n_k \;\;\Rightarrow\;\; \mathrm{E}\!\left[e_\infty^{2}\right] = \frac{\alpha\sigma^{2}}{\lambda(2 - \alpha\lambda)} \approx \frac{\alpha\sigma^{2}}{2\lambda} \]
(14.10)
\(n_k\)
gradient noise, zero mean, variance \(\sigma^2\)
\(\lambda\)
curvature of the mode
\(e_k\)
error of one mode after k steps
\(\alpha\)
step size, units of 1/curvature
\(\sigma^{2}\)
variance of \(n_k\)
\(\mathrm{E}[\cdot]\)
expected value
\(e_\infty\)
error after the iteration has reached steady state
Halving \(\alpha\) halves the floor and halves the speed; a mini-batch of size \(B\) divides \(\sigma^2\) by \(B\). Convergence needs a decaying step (\(\sum\alpha_k = \infty\), \(\sum\alpha_k^2 < \infty\), Robbins–Monro).

Adam (Kingma & Ba, 2015) keeps exponential averages of the gradient and of its square, per parameter:

\[ m_k = \beta_1 m_{k-1} + (1-\beta_1)\,g_k, \qquad v_k = \beta_2 v_{k-1} + (1-\beta_2)\,g_k^{2}, \qquad x_{k+1} = x_k - \eta\,\frac{\hat m_k}{\sqrt{\hat v_k} + \epsilon} \]
(14.11)
\(g_k\)
gradient (or stochastic gradient) at step \(k\)
\(\hat m_k,\ \hat v_k\)
bias-corrected averages \(m_k/(1 - \beta_1^k)\), \(v_k/(1 - \beta_2^k)\)
\(\eta\)
learning rate, in parameter units per step
\(\beta_1, \beta_2, \epsilon\)
defaults 0.9, 0.999, \(10^{-8}\)
\(m_k,\ v_k\)
running averages of the gradient and of its square
\(x_k\)
parameter after k steps
\(g_k^{2}\)
element-wise square of the gradient
\(\sqrt{\cdot}\)
element-wise square root
For a steady gradient \(\hat m/\sqrt{\hat v} = \mathrm{sign}(g)\): every parameter moves by about \(\eta\) per step whatever the size of its gradient. Adam is invariant to a diagonal rescaling of the gradient (Kingma & Ba), not to a rotation; it is not invariant to a change of parameter units, since a step of \(\eta\) means a different physical change in each unit.
Demo 14.2

Six optimizers in the Rosenbrock valley

SimulationGradient descent with Armijo, heavy ball, Adam, Newton, Gauss–Newton and LM iterated in JS on the exact Rosenbrock function.
Try: from the classic start, Gauss–Newton needs 2 steps (the first sets \(x = 1\) exactly because \(r_2 = 1 - x\) is linear), Newton 5, LM 22 accepted steps; first-order methods need thousands: heavy ball 3301, Adam (\(\eta = 0.02\)) 3034, gradient descent with Armijo 7283. Heavy ball with \(\beta = 0.9\) converges up to \(\alpha \approx 0.0034\) and diverges at 0.0035, a little below the bound \(2(1 + \beta)/L = 0.0038\) at the minimum (\(L \approx 1002\)) because the curvature along the path is higher; with \(\beta = 0\) the limit is near \(2/L = 0.002\). Start at (−1.2, 1.5), where the Hessian is indefinite: the first Newton and Gauss–Newton steps go uphill (both recover here), while LM, which rejects uphill steps, never does. Click the map to start anywhere.
Ultrasound link: which optimizer for which job

A QUS fit with 2–6 smooth parameters (attenuation slope, BSC intercept, effective scatterer size) is a job for Gauss–Newton or LM with scaled parameters: a few iterations, and the error bars come free from \((\mathbf{J}^{T}\mathbf{J})^{-1}\). A differentiable beamformer with \(10^3\)–\(10^5\) sound-speed or phase parameters, a reverse-mode gradient and a cost averaged over patches is where Adam and its relatives are used: the Hessian is too large to form and the per-parameter normalization handles mixed sensitivities. Neural-network beamformers are the same machinery with millions of weights.

14.4Convexity, and why oscillatory data skip cycles

A function is convex if \(f(\theta\mathbf{a} + (1-\theta)\mathbf{b}) \le \theta f(\mathbf{a}) + (1-\theta)f(\mathbf{b})\) for \(0 \le \theta \le 1\); then every local minimum is global and any descent method with a sane step finds it. Least squares with a linear model, Tikhonov, L1 and TV regularizers (Module 13) are convex. As soon as the unknown sits inside the phase of an oscillating signal (a delay, a sound speed, an aberration law), the cost is not.

Fit a delay \(\tau\) to an echo \(d(t) = s(t)\) with the model \(s(t - \tau)\). Expanding the square:

\[ \mathcal{L}(\tau) = \int \left(d(t) - s(t - \tau)\right)^{2} dt = 2E - 2R_{ss}(\tau) \]
(14.12)
\(E\)
pulse energy \(\int s^2\,dt\)
\(R_{ss}(\tau)\)
autocorrelation of the pulse at lag \(\tau\)
\(\mathcal{L}(\tau)\)
loss as a function of the delay error
\(d(t),\ s(t)\)
measured echo and reference pulse, arbitrary units
\(t\)
time, µs
\(\tau\)
trial delay, ns
\(\int\)
integral over the whole record
Minimizing the misfit is maximizing the correlation, so every false correlation peak of Module 11 is a local minimum here.
\[ s(t) = e^{-t^{2}/(2\sigma^{2})}\cos(2\pi f_0 t) \;\;\Rightarrow\;\; \frac{R_{ss}(\tau)}{R_{ss}(0)} \approx e^{-\tau^{2}/(4\sigma^{2})}\cos(2\pi f_0\tau) \]
(14.13)
\(\sigma\)
envelope standard deviation, µs (0.125 µs here)
\(f_0\)
centre frequency, MHz
\(\tau\)
delay error, ns
\(T_0 = 1/f_0\)
carrier period, 200 ns at 5 MHz
\(s(t)\)
Gaussian-windowed cosine pulse
\(t\)
time, µs
\(R_{ss}(0)\)
pulse energy \(E\), as in (14.12)
\(R_{ss}(\tau)\)
pulse autocorrelation, as in (14.12)
\(e\)
exponential function
Exact up to a term \(e^{-(2\pi f_0\sigma)^2} \approx 2 \times 10^{-7}\) for \(f_0\) = 5 MHz, \(\sigma\) = 0.125 µs (−6 dB bandwidth 3 MHz, 60 %). Local minima sit just inside multiples of \(T_0\): at ±194, ±388, ±583 ns. The maxima between them, at ±97 ns, bound the basin of the true minimum: start within about \(T_0/2\) or converge to the wrong cycle.

Three ways to widen the basin, each with a price:

\[ \text{envelope:}\quad \mathcal{L}_{\mathrm{env}}(\tau) \propto 1 - e^{-\tau^{2}/(4\sigma^{2})} \qquad \left(\text{one minimum; convex for } \lvert\tau\rvert < \sqrt{2}\,\sigma = 177\ \mathrm{ns}\right) \]
(14.14)
\(\mathcal{L}_{\mathrm{env}}(\tau)\)
loss computed on the envelope instead of the RF
\(\tau\)
delay error, ns
\(\sigma\)
envelope standard deviation, as in (14.13)
\(\propto\)
proportional to (scale set by the signal energy)
The gradient vanishes in the tails. Curvature at the minimum, relative to the signal energy, is lower than for RF by the factor \(1 + 2(2\pi f_0\sigma)^2 = 31.8\) here: the envelope finds the basin, the RF gives the precision.
\[ \text{low-pass } e^{-f^{2}/(2f_l^{2})} \text{ on a Gaussian spectrum:}\quad f_c = \frac{f_0\, f_l^{2}}{\sigma_f^{2} + f_l^{2}}, \qquad \sigma_f = \frac{1}{2\pi\sigma} = 1.27\ \mathrm{MHz} \]
(14.15)
\(f_l\)
Gaussian low-pass corner (standard deviation), MHz
\(\sigma_f\)
standard deviation of the pulse amplitude spectrum, MHz
\(f_c\)
centre frequency of the filtered (still Gaussian) pulse, MHz
\(f\)
frequency, MHz
\(f_0\)
centre frequency, as in (14.13), MHz
\(\sigma\)
envelope standard deviation, µs, as in (14.13)
\(f_l\) = 1.5 MHz: \(f_c\) = 2.91 MHz, basin about ±160 ns, but only −29 dB of the pulse energy survives; \(f_l\) = 1 MHz: \(f_c\) = 1.91 MHz, basin ±240 ns at −43.5 dB. You cannot low-pass energy that the transducer never transmitted, which is why full-waveform inversion acquires low frequencies on purpose.
\[ \text{multiscale:}\quad \hat\tau_1 = \arg\min_\tau \mathcal{L}_{\mathrm{env}}(\tau) \;\;\longrightarrow\;\; \hat\tau = \arg\min_\tau \mathcal{L}_{\mathrm{RF}}(\tau) \ \text{ started from } \hat\tau_1 \]
(14.16)
\(\hat\tau_1,\ \hat\tau\)
coarse (envelope) and final (RF) delay estimates, ns
\(\mathcal{L}_{\mathrm{env}}\)
envelope loss, as in (14.14)
\(\mathcal{L}_{\mathrm{RF}}\)
RF loss, as in (14.12)
\(\tau\)
trial delay, ns
\(\arg\min\)
the \(\tau\) that minimizes the loss
\(\longrightarrow\)
result of the first stage used as the starting point of the second
The FWI recipe (Bunks et al., 1995; Virieux & Operto, 2009): a coarse cost (envelope or lowest band) to land in the right basin, then the oscillatory cost for resolution. In the MATLAB lab, envelope → RF converges from all 121 starts in ±600 ns; RF alone from 19 (\(\lvert\tau_0\rvert \le\) 90 ns).
Demo 14.3

Cycle skipping in a delay fit

Exact formulaClosed-form misfits of a Gaussian-modulated pulse (checked against sampled signals in the MATLAB script); the descent path is iterated on them.
RF misfitenvelope misfitlow-pass RF misfitgradient-descent iterates
Model: Gaussian-modulated pulse with \(\sigma\) = 0.125 µs, true delay 0, closed-form misfits (verified against sampled signals in m14_cycle_skipping.m), gradient descent with step \(1/\mathcal{L}''(0)\). Try: RF from 150 ns lands on the 194 ns minimum; the staircase below shows every start at once. Lower \(f_0\) to 2.5 MHz: the steps widen to 400 ns. Choose envelope, then RF: one flat step through 0. Lower \(f_l\) and watch the readout: the basin grows while the surviving energy collapses.
Ultrasound link: the same criterion in travel-time units

In transmission tomography and full-waveform inversion the data are traces across a path of length \(L\). A starting model that predicts the travel time to within half a period, \(\lvert\Delta t\rvert = L\lvert\Delta c\rvert/c^2 < 1/(2f)\), stays in the basin: \(\lvert\Delta c\rvert/c < \lambda/(2L)\). Breast-scale USCT (\(L\) = 200 mm, \(c\) = 1500 m/s) at 0.5 MHz tolerates 11 m/s, at 1 MHz 5.6 m/s. That is why ultrasound FWI starts from a travel-time (bent-ray) tomogram and from the lowest usable frequency. Pulse-echo autofocus has its own version, in Section 14.5.

Pitfall: a free polarity halves the basin

If the model amplitude may change sign, \(A\cos(2\pi f(t - t_0))\) and \(-A\cos(2\pi f(t - t_0 - T/2))\) are the same curve: false minima appear every \(T/2\), and the basin shrinks to \(\pm T/4\). The MATLAB echo fit shows it: a 100 ns start (\(T/4\) = 56 ns) converges to \(t_0\) + 106 ns with \(A < 0\). Constrain the sign, or give the model a free carrier phase so that \(t_0\) is set by the envelope alone (the free-phase fit recovers \(t_0\) = 1.994 µs from the same start).

14.5Autofocus: sound speed by gradient ascent on a focus metric

Module 07 showed that coherence peaks at the true sound speed. Turning that into an estimator means choosing what to maximize, over which pixels, and how to climb. The beamformer is a differentiable function of the assumed speed \(\hat c\). For plane-wave angle \(\theta\), element \(e\) and a pixel placed in time coordinates \((x, t)\), with depth \(\hat z = \hat c t/2\):

\[ \tau_{\theta e}(\hat c) = \frac{t}{2}\cos\theta + \frac{x\sin\theta}{\hat c} + \sqrt{\frac{(x - x_e)^{2}}{\hat c^{2}} + \frac{t^{2}}{4}}, \qquad b(\hat c) = \sum_{\theta}\sum_{e} \mathrm{IQ}_{\theta e}(\tau_{\theta e})\, e^{j\omega_0\tau_{\theta e}} \]
(14.17)
\(\hat c\)
assumed sound speed, m/s
\(x,\ t\)
pixel lateral position (m) and two-way time (s)
\(x_e\)
lateral position of receive element \(e\), m
\(\theta\)
plane-wave steering angle
\(\mathrm{IQ}_{\theta e}\)
baseband channel signal of transmit \(\theta\), element \(e\)
\(\omega_0\)
demodulation angular frequency \(2\pi f_0\), rad/s
\(b\)
beamformed complex pixel value
\(\tau_{\theta e}\)
two-way delay for transmit angle \(\theta\), receive element e, s
\(\sum_\theta\sum_e\)
sum over transmit angles and receive elements
\(j\)
imaginary unit
\[ \frac{db}{d\hat c} = \sum_{\theta, e} \left[ \mathrm{IQ}'_{\theta e}(\tau) + j\omega_0\, \mathrm{IQ}_{\theta e}(\tau) \right] e^{j\omega_0\tau}\, \frac{\partial\tau}{\partial\hat c}, \qquad \frac{\partial\tau}{\partial\hat c} = -\frac{x\sin\theta}{\hat c^{2}} - \frac{(x - x_e)^{2}}{\hat c^{3}\sqrt{(x - x_e)^{2}/\hat c^{2} + t^{2}/4}} \]
(14.18)
\(b,\ \hat c,\ \mathrm{IQ}_{\theta e},\ \tau,\ \omega_0,\ x,\ x_e,\ t,\ \theta\)
as in (14.17)
\(\mathrm{IQ}'_{\theta e}\)
derivative of the baseband signal with respect to its time argument, 1/s
\(\partial\tau/\partial\hat c\)
sensitivity of the delay to the assumed sound speed, s per m/s
\(\frac{db}{d\hat c}\)
sensitivity of the beamformed pixel to \(\hat c\)
\(j\omega_0\mathrm{IQ}\)
derivative of the phase rotation \(e^{j\omega_0\tau}\); dominates over \(\mathrm{IQ}^{\prime}\) for a narrowband signal
This is forward-mode differentiation by hand: one extra multiply-add per sample. \(\mathrm{IQ}'\) is the slope of the interpolator. The demo and m14_autofocus_sound_speed.m check it against central differences (ratio 1.000000).

Candidate metrics, all functions of \(\hat c\):

MetricDefinitionBehaviour (c = 1480 m/s, z = 30 mm, 5 MHz, 64 elements)
Compounded energy\(\sum_{\mathrm{ROI}} \lvert b\rvert^2\), ROI fixed in two-way time, 5 angles (−8° to 8°)one peak over 1350–1750 m/s, at 1482–1488 m/s over scenes and depths; every start converges there
Energy, one anglesame, 0° onlynearly flat, peaks at 1540–1570 m/s: useless (see below)
Sharpness\(P \sum I^2 / \left(\sum I\right)^2\), \(I = \lvert b\rvert^2\), \(P\) pixelswithin about 20 m/s with a point target (mostly low, worst at 40 mm); erratic on pure speckle (peaks 1590–1660 m/s)
Envelope at fixed depth\(\lvert b(x{=}0, z)\rvert^2\), pixel tied to depthright peak, basin roughly ±20 m/s; only where a bright scatterer sits
RF at fixed depth\(\mathrm{Re}\, b(x{=}0, z)\)oscillates with period \(\hat c^2/(2zf_0)\) = 7.3 m/s: cycle skips from every start
\[ \text{fixed-depth pixel: } t(\hat c) = \frac{2z}{\hat c} \;\Rightarrow\; \Delta t = \frac{2z\,\Delta\hat c}{\hat c^{2}} \;\Rightarrow\; \text{one carrier period per } \Delta\hat c = \frac{\hat c^{2}}{2 z f_0} \]
(14.19)
\(z\)
pixel depth, m
\(f_0\)
centre frequency, Hz
\(\Delta\hat c\)
sound-speed change that slides the echo by one period, m/s: 7.9 m/s at 1540 m/s, 30 mm, 5 MHz
\(t(\hat c)\)
two-way time of the echo from depth z, s
\(\Delta t\)
echo time shift caused by \(\Delta\hat c\), s
\(\hat c\)
assumed sound speed, m/s
Tying the pixel to depth turns a sound-speed error into a bulk time shift of the echo through the pixel, so the RF value oscillates exactly like the delay misfit of Section 14.4. Tying the ROI to two-way time removes the bulk shift: what remains is defocus, which varies slowly (Module 07: edge phase \(\approx (\pi D^2/(2\lambda z))(\Delta c/c)\), 1.6 rad for 40 m/s at F/1.6).

Why a single plane wave fails on energy: receive-only DAS over a region is close to an energy-preserving (unitary-like) migration of the channel data, so \(\sum\lvert b\rvert^2\) barely changes when the focusing law is wrong; the energy just moves between pixels. Sharpness, which rewards concentrating energy, and coherent compounding across angles, which rewards angles that agree, both break that invariance. This is the ultrasound version of Muller & Buffington's result for telescope image sharpening (JOSA, 1974): \(\int I\) is invariant to the aberration, \(\int I^2\) is maximized by the correct correction.

Demo 14.4

Autofocus: gradient ascent on a focus metric

SimulationPlane-wave IQ channel data of random point scatterers synthesized and beamformed by DAS in JS (straight rays, homogeneous medium); exact chain-rule gradient, Armijo ascent.
metric (normalized)gradient-ascent iterates, one row per starttrue cassumed ĉ (slider)
Model: 64 elements, pitch 0.3 mm, 5 MHz Gaussian pulse (\(\sigma\) = 0.125 µs), IQ sampled at 40 MHz, linear interpolation; 500 complex Gaussian scatterers in 8 × 3 mm plus a point with 12 times the rms scatterer amplitude (21.6 dB). Ascent: step along \(\mathrm{sign}(dM/d\hat c)\) with Armijo backtracking from a metric-specific trial step (40 m/s for ROI metrics, 8 and 1.5 m/s for fixed-depth ones), projected onto [1350, 1750] m/s, starts 1380, 1440, 1540, 1620, 1720 m/s. Try: RF at fixed depth: every start stalls on its own ripple. Compounded energy with 5 angles: all starts meet within 6 m/s of the truth. Switch to 1 angle: the same metric goes flat and wrong. Speckle only with sharpness: the peak wanders, because fully developed speckle has \(\overline{I^2}/\bar I^2 \approx 2\) at any focus.
Pitfall: integrated metrics are biased

In this simulation the compounded energy peaks 2–10 m/s above the true speed and sharpness up to about 20 m/s below it (0.1–1.3 %); the bias comes from the finite ROI and the angle geometry (it does not change with finer sampling), not from noise. The bias is small next to the ±20–40 m/s spread of tissue speeds, but it is a systematic error: calibrate the estimator on phantoms of known speed, and report the bias next to the precision.

Ultrasound link: from one global ĉ to a map

Pulse-echo estimation of the average sound speed from the received wavefronts goes back at least to Anderson & Trahey (JASA, 1998); sweeping \(\hat c\) to maximize a focus or coherence metric is the common global form. Differentiable-beamforming autofocus (Simson, Dahl, Hyun and colleagues, MICCAI 2023) parameterizes a slowness map, computes delays by integrating slowness along straight rays, scores focus with an image-quality loss, and back-propagates through the beamformer to every map parameter with reverse-mode AD; a 2024 follow-up uses a common-midpoint phase-error loss and reports in vivo liver results (see Figures from the literature). The lessons above carry over unchanged: tie the patches to time, use metrics that are not energy-invariant, start from a sensible global \(\hat c\), regularize the map (Module 13), and expect a path-averaged answer in layered media.

SchematicDrawing for intuition; the boxes are the operations of a differentiable plane-wave DAS autofocus, the numbers are those of Section 14.6. slowness map s(x, z) 10³–10⁴ parameters τ_θe = ∫ s dl straight rays per pixel IQ_θe(τ)·e^(jω₀τ) interpolate, rotate b = Σ_θ Σ_e (·) coherent sum per pixel focus metric M patches tied to time loss L = −M + R(s) R: TV or ‖∇s‖² (M13) R(s) forward reverse ∂L/∂τ = Re Σ (∂L/∂b)* (IQ′ + jω₀IQ) e^(jω₀τ) ∂L/∂s: back-project ∂L/∂τ along each ray one reverse pass ≈ small multiple of one forward pass, for any number of parameters tape: 256² pixels × 128 elements × 11 angles = 9.2×10⁷ delays = 0.74 GB (float64) checkpointing: recompute τ on the backward pass instead of storing it

Differentiable-beamforming autofocus as a computational graph. Forward (blue): slowness map → ray-integrated delays → interpolated, phase-rotated IQ → coherent sum → patch focus metric → loss with a map regularizer. Reverse (pink): the adjoint of the sum is a broadcast, the adjoint of the delay step needs IQ′ + jω₀IQ (the hand-derived db/dĉ of this section), and the adjoint of the ray integral back-projects ∂L/∂τ along each ray onto the map.

14.6Automatic differentiation

Four ways to get \(f'(x)\), in increasing order of reliability:

\[ \text{forward difference: } \frac{f(x+h) - f(x)}{h}, \qquad \text{error} \approx \frac{h\lvert f''\rvert}{2} + \frac{2\varepsilon\lvert f\rvert}{h} \;\Rightarrow\; h^* \approx 2\sqrt{\varepsilon\left\lvert f/f''\right\rvert} \sim 10^{-8},\ \ \text{error} \sim 10^{-8} \]
(14.20)
\(h\)
step, in units of \(x\)
\(\varepsilon\)
machine epsilon, \(2.2 \times 10^{-16}\) in double precision
\(f(x)\)
function to differentiate
\(x\)
evaluation point
\(f^{\prime\prime}\)
second derivative
\(h^*\)
step that minimizes the total error (truncation plus round-off)
\(\lvert\cdot\rvert\)
absolute value
Truncation error falls with \(h\); round-off from the subtraction of nearly equal numbers grows as \(\varepsilon/h\). You keep about half the digits.
\[ \begin{gathered} \text{central difference: } \frac{f(x+h) - f(x-h)}{2h}, \qquad \text{error } O(h^{2}) + O(\varepsilon/h) \\ \Rightarrow\; h^* \sim \varepsilon^{1/3} \approx 6 \times 10^{-6},\ \ \text{error} \sim \varepsilon^{2/3} \approx 4 \times 10^{-11} \end{gathered} \]
(14.21)
\(f(x)\)
function to differentiate
\(x\)
evaluation point
\(h\)
step, in units of \(x\), as in (14.20)
\(\varepsilon\)
machine epsilon, as in (14.20)
\(h^*\)
step that minimizes the total error
\(O(\cdot)\)
error scales as the given power
\[ \text{complex step: } f'(x) \approx \frac{\mathrm{Im}\, f(x + ih)}{h}, \qquad f(x+ih) = f(x) + ih f'(x) - \frac{h^{2}}{2}f''(x) - \frac{ih^{3}}{6}f'''(x) + \dots \]
(14.22)
\(i\)
imaginary unit
\(h\)
imaginary step; any \(h \le 10^{-8}\), even \(10^{-20}\) or \(10^{-100}\)
\(f\)
real-analytic function implemented with complex-safe operations
\(\mathrm{Im}\)
imaginary part
\(x\)
real evaluation point
\(f^{\prime},\ f^{\prime\prime},\ f^{\prime\prime\prime}\)
first, second and third derivatives at \(x\)
No subtraction, so no cancellation: \(h = 10^{-20}\) gives full machine precision (Lyness & Moler, 1967; Squire & Trapp, 1998). It needs a real-analytic implementation: abs, conj, the ' operator in MATLAB, max/min branches and comparisons break it silently, and it cannot be used on code that already computes with complex IQ data.
\[ \text{dual numbers (forward-mode AD): } x + \epsilon\dot x \ \text{ with } \epsilon^{2} = 0, \qquad f(x + \epsilon\dot x) = f(x) + \epsilon\, f'(x)\,\dot x \ \text{ exactly} \]
(14.23)
\(\epsilon\)
dual unit, nilpotent (\(\epsilon^2 = 0\)); not machine epsilon
\(\dot x\)
tangent (seed direction) carried with the value
\(x\)
value (real number)
\(f(x),\ f^{\prime}(x)\)
function value and its derivative at \(x\)
Overload every elementary operation: \((a + \epsilon\dot a)(b + \epsilon\dot b) = ab + \epsilon(a\dot b + \dot a b)\), \(\sin(a + \epsilon\dot a) = \sin a + \epsilon\cos a\,\dot a\). One pass gives one directional derivative (a Jacobian–vector product \(\mathbf{J}\mathbf{v}\)) at a small constant multiple of the cost of \(f\).

Reverse mode records the computation (the tape) on a forward sweep, then propagates adjoints \(\bar v = \partial y/\partial v\) backwards with the chain rule. The standard example (Baydin et al., 2018), \(y = \ln x_1 + x_1x_2 - \sin x_2\) at (2, 5):

Forward sweep (primal)valueForward tangent (\(\dot x_1 = 1,\ \dot x_2 = 0\))valueReverse sweep (adjoint, \(\bar y = 1\))value
\(v_1 = \ln x_1\)0.6931\(\dot v_1 = \dot x_1/x_1\)0.5\(\bar v_4 = \bar y,\ \bar v_3 = -\bar y\)1, −1
\(v_2 = x_1x_2\)10\(\dot v_2 = \dot x_1x_2 + x_1\dot x_2\)5\(\bar v_1 = \bar v_4,\ \bar v_2 = \bar v_4\)1, 1
\(v_3 = \sin x_2\)−0.9589\(\dot v_3 = \cos x_2\,\dot x_2\)0\(\bar x_1 = \bar v_1/x_1 + \bar v_2x_2\)5.5
\(v_4 = v_1 + v_2\)10.6931\(\dot v_4 = \dot v_1 + \dot v_2\)5.5\(\bar x_2 = \bar v_2x_1 + \bar v_3\cos x_2\)1.7163
\(y = v_4 - v_3\)11.6521\(\dot y = \dot v_4 - \dot v_3\)5.5 = ∂y/∂x₁one sweep gives both partials(5.5, 1.7163)
Figure 14.6

The computational graph, forward values and reverse adjoints

SchematicGraph layout drawn for intuition; the node values and adjoints printed on it are exact.
Forward sweep (left to right, blue): each node stores its value. Reverse sweep (right to left, pink): each node's adjoint is the sum over its consumers of consumer adjoint × local partial; \(x_1\) feeds two nodes, so its adjoint sums two paths, 1/2 + 5 = 5.5.
\[ \begin{gathered} \text{cost of a Jacobian } \mathbf{J} \in \mathbb{R}^{m\times n}: \\ \text{forward mode } n \text{ passes (one per input)}, \qquad \text{reverse mode } m \text{ passes (one per output)} \end{gathered} \]
(14.24)
\(\mathbf{J}\)
Jacobian matrix, as in (14.8)
\(m\)
number of outputs
\(n\)
number of inputs
\(\mathbb{R}^{m\times n}\)
real matrices with m rows and n columns
A scalar loss of \(10^4\) sound-speed parameters: one reverse pass, a small constant multiple of one loss evaluation, against \(10^4\) forward passes or \(2 \times 10^4\) central differences. The price is memory: the tape holds every intermediate (Griewank & Walther, 2008). Checkpointing trades recomputation for memory.
Demo 14.5

Derivative error versus step: differences, complex step, dual numbers

SimulationEach method evaluated in double-precision JS arithmetic and compared with the analytic derivative; the error is real floating-point behaviour, not a model.
forward differencecentral differencecomplex stepdual number (exact, no h)
Try: the V shapes are truncation (right side, slope 1 or 2 per decade) meeting round-off (left side, slope −1). The complex step keeps falling to \(10^{-16}\) and stays there. Pick \(x\lvert x - 1\rvert\): the complex step is now confidently wrong for every \(h\) (0.5 instead of 2 at \(x_0\) = 1.5) because abs returns a real modulus, while the dual number, which overloads abs by its sign rule, is exact. The default function and point are those of Martins, Sturdza & Alonso's Fig. 1 (see Figures from the literature).
Pitfall: complex-step bugs hide in harmless-looking code

Writing this demo, a textbook complex square root, \(\mathrm{Im}\sqrt{z} = \sqrt{(\lvert z\rvert - \mathrm{Re}\,z)/2}\), returned an imaginary part of exactly 0 for \(z = a + 10^{-20}i\): \(\lvert z\rvert - \mathrm{Re}\,z\) cancels. The fix is \(\mathrm{Im}\sqrt{z} = \mathrm{Im}\,z / (2\,\mathrm{Re}\sqrt{z})\), with \(\mathrm{Re}\sqrt{z} = \sqrt{(\lvert z\rvert + \mathrm{Re}\,z)/2}\). Every elementary function in the chain must be implemented without cancellation in the imaginary part, which MATLAB's built-ins are, except abs and the ' operator (the MATLAB lab shows x'*x giving a derivative of 0).

14.7Complex parameters, Wirtinger calculus and constraints

IQ data, focusing laws and aberration estimates are complex, but losses are real. A real \(\mathcal{L}(z)\) is never complex-differentiable (unless constant), so use the Wirtinger derivatives, treating \(z\) and \(z^*\) as independent:

\[ \frac{\partial}{\partial z} = \frac12\left(\frac{\partial}{\partial x} - i\frac{\partial}{\partial y}\right), \qquad \frac{\partial}{\partial z^*} = \frac12\left(\frac{\partial}{\partial x} + i\frac{\partial}{\partial y}\right), \qquad \frac{\partial\mathcal{L}}{\partial x} + i\frac{\partial\mathcal{L}}{\partial y} = 2\,\frac{\partial\mathcal{L}}{\partial z^*} \]
(14.25)
\(z = x + iy\)
complex parameter (IQ weight, focusing-law entry)
\(z^*\)
complex conjugate, treated as an independent variable
\(\mathcal{L}\)
real-valued loss
\(x,\ y\)
real and imaginary parts of \(z\)
\(i\)
imaginary unit
\(\partial/\partial z,\ \partial/\partial z^*\)
Wirtinger derivatives
The steepest-descent direction in \(\mathbb{C}^N\) (viewed as \(\mathbb{R}^{2N}\)) is \(-\partial\mathcal{L}/\partial\mathbf{z}^*\), not \(-\partial\mathcal{L}/\partial\mathbf{z}\) (Brandwood, 1983).
\[ \mathcal{L} = \lvert z - a\rvert^{2} \to \frac{\partial\mathcal{L}}{\partial z^*} = z - a; \qquad \mathcal{L} = \lVert\mathbf{y} - \mathbf{A}\mathbf{w}\rVert^{2} \to \frac{\partial\mathcal{L}}{\partial\mathbf{w}^*} = -\mathbf{A}^{H}(\mathbf{y} - \mathbf{A}\mathbf{w}); \qquad \mathcal{L} = \mathbf{w}^{H}\mathbf{R}\mathbf{w} \to \frac{\partial\mathcal{L}}{\partial\mathbf{w}^*} = \mathbf{R}\mathbf{w} \]
(14.26)
\(\mathcal{L},\ z\)
as in (14.25)
\(a\)
complex target value
\(\lvert\cdot\rvert\)
complex magnitude
\(\mathbf{y}\)
complex data vector
\(\mathbf{A}\)
complex model matrix
\(\mathbf{w}\)
complex weight vector (unknown)
\(\mathbf{R}\)
Hermitian matrix (covariance)
\(\lVert\cdot\rVert\)
Euclidean norm
\(^{H}\)
conjugate (Hermitian) transpose
\(\partial\mathcal{L}/\partial\mathbf{w}^*\)
Wirtinger gradient with respect to the conjugate weights
Stepping along the conjugate, \(-\partial\mathcal{L}/\partial z = -(\partial\mathcal{L}/\partial z^*)^*\), flips the imaginary part of every step. On the least-squares problem of the MATLAB lab it diverges (\(\mathcal{L} = 2.4 \times 10^{62}\) after 200 steps) while the correct step reaches the optimum.

Aberration correction as optimization: find element phases \(\theta_e\) that maximize the coherent energy of the beamformed sum, \(b = \mathbf{w}^{H}\mathbf{s}\) with \(w_e = e^{j\theta_e}\), averaged over \(K\) speckle realizations, \(\mathcal{L}(\mathbf{\theta}) = \mathbf{w}^{H}\mathbf{R}\mathbf{w}\), \(\mathbf{R} = \mathbf{S}\mathbf{S}^{H}/K\):

\[ d\mathcal{L} = 2\,\mathrm{Re}\!\left[\frac{\partial\mathcal{L}}{\partial w_e}\, dw_e\right], \quad \frac{\partial\mathcal{L}}{\partial w_e} = (\mathbf{R}\mathbf{w})_e^*, \quad dw_e = j\,w_e\, d\theta_e \;\;\Rightarrow\;\; \frac{\partial\mathcal{L}}{\partial\theta_e} = 2\,\mathrm{Im}\!\left( w_e^*\, (\mathbf{R}\mathbf{w})_e \right) \]
(14.27)
\(\mathbf{w}\)
unit-modulus focusing law, one entry per element
\(\mathbf{S}\)
element signals (columns = \(K\) realizations)
\(\mathbf{R}\)
sample covariance across elements
\(\mathcal{L}\)
coherent output energy to be maximized
\(w_e\)
weight of element e, \(e^{j\theta_e}\)
\(\theta_e\)
phase correction of element e, rad
\((\mathbf{R}\mathbf{w})_e\)
element e of the vector \(\mathbf{R}\mathbf{w}\)
\(\mathrm{Re},\ \mathrm{Im}\)
real and imaginary parts
\(^*\)
complex conjugate
\(j\)
imaginary unit
Phase-only ascent \(\mathbf{\theta} \leftarrow \mathbf{\theta} + \mu\, 2\,\mathrm{Im}(\mathbf{w}^* \odot \mathbf{R}\mathbf{w})\). Dropping the unit-modulus constraint, the normalized Wirtinger ascent \(\mathbf{w} \leftarrow \mathbf{w} + \mu\mathbf{R}\mathbf{w}\) is a power iteration (Module 06) that converges to the top eigenvector of \(\mathbf{R}\), the time-reversal focusing law.

Constraints enter through projection or a proximal step. Projected gradient keeps \(\hat c\) inside physical bounds (the autofocus demo projects onto [1350, 1750] m/s); the proximal gradient step \(\mathbf{x} \leftarrow \mathrm{prox}_{\alpha g}(\mathbf{x} - \alpha\nabla f)\) handles a nonsmooth regularizer \(g\), e.g. soft thresholding for L1 (ISTA, Module 13).

Demo 14.6

Aberration law by Wirtinger gradient ascent

SimulationApprox. modelNarrowband focal-plane model, thin phase screen at the array on transmit and receive, K = 64 speckle realizations.
phase-only ascent, 2Im(w*⊙Rw)Wirtinger ascent, w += μRw (normalized)bug: w += μ conj(Rw)true screen
Model: narrowband focal-plane model as in Module 07 (64 elements, 0.3 mm pitch, 5 MHz, focus 30 mm), a thin phase screen at the array applied on transmit and receive, \(K\) = 64 speckle realizations, optional point target at the focus with the given target-to-speckle power ratio; 300 iterations, \(\mu = 0.5/\lambda_{\max}(\mathbf{R})\). Coherent energy is normalized by its value for the true conjugate law; phase errors exclude piston and tilt. Try: speckle only: both correct rules converge, yet the energy ends above 1 while the phase error stays near 0.14 rad: with \(K\) = 64 snapshots they fit the sample covariance, not the screen. Raise the point target to 10 dB: the error falls to about 0.02 rad. The conjugated update lowers the energy and leaves 1.5 rad of error.

14.8Visual summary

Each card is a question you should answer in five seconds, the answer with its key number, and the picture to keep in mind. Every curve is computed from the formula in the answer; the badge says whether it is a closed form, a numerical run or a simplified model.

14.9How experts think about it

Near a solution every cost is a quadratic, so \(\kappa\) of the Hessian decides how first-order methods converge and scaling or curvature (Newton, Gauss–Newton) is the cure. Far from the solution the shape of the basin decides everything: oscillatory data (RF, phase, a fixed-depth pixel) cut the basin to half a period, and the remedy is a cost whose basin is wider (envelope, low frequency, time-tied ROI, compounding) used first, then the precise cost. Derivatives are exact or they are suspect: write them by hand or by AD, check them against central differences once, and for complex parameters step along \(-\partial\mathcal{L}/\partial z^*\).

Gradient descent converges at (κ − 1)/(κ + 1) per step with the best fixed step: about κ/2 iterations per factor e.
\(\alpha^* = 2/(L + \mu)\)κ = 100 → 691 its to 10⁻⁶

In the Hessian's eigenbasis each error component is multiplied by \(1 - \alpha\lambda\). The best fixed \(\alpha\) makes the extreme factors equal and opposite, \(\lvert 1 - \alpha\mu\rvert = \lvert 1 - \alpha L\rvert\), giving \(\rho = (\kappa-1)/(\kappa+1)\), (14.3). Iterations to \(\varepsilon\): \(\ln(1/\varepsilon)/\ln\frac{\kappa+1}{\kappa-1} \approx (\kappa/2)\ln(1/\varepsilon)\): 69, 691, 6908 at \(\kappa\) = 10, 100, 1000, matched exactly by the MATLAB lab.

Exact formula
Strongly convex quadratic, or the end game of a smooth cost near a nondegenerate minimum; the constant depends on how the start loads the slow mode.
A step above 2/L diverges; 1/L is the safe default.
\(\lvert 1 - \alpha L\rvert < 1\)α = 2.05/L → ×1.05 per step

The stiff mode is multiplied by \(1 - \alpha L\), which leaves the unit circle when \(\alpha > 2/L\), (14.2). At \(\alpha = 2.05/L\) it grows by 1.05 per step, \(1.05^{50} = 11.5\) after 50 steps (MATLAB lab). With \(\alpha = 1/L\) the stiff mode is killed in one step and the flat mode decays as \(1 - 1/\kappa\): slower than \(\alpha^*\) by a factor of about 2, but robust when \(L\) is only estimated (power iteration on the Hessian, Module 06).

Exact formula
\(L\) must bound the curvature along the whole path, not only at the solution; momentum changes the limit (heavy ball is stable for \(\alpha L < 2(1 + \beta)\)).
Momentum turns κ into √κ.
\(\rho = \frac{\sqrt{\kappa} - 1}{\sqrt{\kappa} + 1}\)κ = 100: 93 vs 691 its

Heavy ball with \(\alpha = 4/(\sqrt{L} + \sqrt{\mu})^2\), \(\beta = \left(\frac{\sqrt\kappa-1}{\sqrt\kappa+1}\right)^2\) has per-mode characteristic roots of modulus \(\sqrt\beta\), so \(\rho = (\sqrt\kappa-1)/(\sqrt\kappa+1) = 0.818\) at \(\kappa\) = 100 against 0.980 for gradient descent, (14.4). The tuned parameters create a double root, so the error decays as \(k\rho^k\): 93 measured iterations against 69 from the rate alone. Nesterov (\(\alpha = 1/L\), \(\beta = (\sqrt\kappa-1)/(\sqrt\kappa+1)\)) gives \(1 - 1/\sqrt\kappa\), 155 iterations.

Exact formula
Heavy ball's rate is a quadratic result; on general strongly convex functions it can fail to converge, while Nesterov's method keeps an accelerated guarantee. Both need \(\mu\) and \(L\); with noisy gradients momentum amplifies the noise.
Scale your parameters before you tune your optimizer.
\(\kappa\): \(1.2 \times 10^6 \to 1.17\)SI units: \(\kappa \approx 10^{22}\)

Mixing m/s with order-1 parameters makes the Jacobian columns differ by \(10^3\), so \(\kappa(\mathbf{J}^{T}\mathbf{J}) \approx 10^6\) and gradient descent needs ~\(10^7\) iterations. Dividing each column by its norm is a diagonal change of variables (Jacobi preconditioning): the MATLAB lab drops \(\kappa\) from \(1.22 \times 10^6\) to 1.17. The echo fit has \(\kappa = 1.8 \times 10^3\) in (1, µs, µs, MHz), \(2 \times 10^{22}\) in SI units, 3.7 scaled; scaled gradient descent needs 51 iterations instead of 10 828.

Exact formula
Diagonal scaling cannot remove correlation between parameters (a rotated valley); that needs curvature information (Newton, Gauss–Newton, quasi-Newton).
Near the solution Newton doubles the correct digits every step, whatever the units.
\(\lVert e_{k+1}\rVert \le C\lVert e_k\rVert^2\)Rosenbrock: 5 steps

Newton's step minimizes the local quadratic model exactly, so the error after a step is set by the third-derivative term: \(e_{k+1} \propto e_k^2\), (14.7). \(10^{-2}\) becomes \(10^{-4}\), then \(10^{-8}\). Because \(\mathbf{d} = -\mathbf{H}^{-1}\nabla f\) transforms with the parameters, rescaling \(\mathbf{\theta}\) changes nothing (affine invariance). On Rosenbrock from (−1.2, 1), 5 steps against thousands for first-order methods.

Simulation
Needs the Hessian (\(n^2\) storage, \(n^3\) solve) and a positive-definite one: far from the minimum the step can head for a saddle or a maximum; damp it, line-search it or use a trust region.
Gauss–Newton is Newton without the residual curvature, and at the solution it hands you the error bars.
\(\nabla^2 f \approx \mathbf{J}^{T}\mathbf{J}\)\(\mathrm{cov} \approx \sigma^2(\mathbf{J}^{T}\mathbf{J})^{-1}\)

For \(f = \tfrac12\lVert\mathbf{r}\rVert^2\), \(\nabla^2 f = \mathbf{J}^{T}\mathbf{J} + \sum_i r_i\nabla^2 r_i\) (14.8); the second term is small for small or nearly linear residuals, and \(\mathbf{J}^{T}\mathbf{J}\) is positive semidefinite, so the Gauss–Newton step is always a descent direction. Solve \(\mathbf{J}\mathbf{\delta} \approx -\mathbf{r}\) by QR (Module 05), not via \(\mathbf{J}^{T}\mathbf{J}\). At convergence \(\sigma^2(\mathbf{J}^{T}\mathbf{J})^{-1}\) is the Gaussian CRLB at the estimate (Module 12): 0.69 ns on \(t_0\) for the 26 dB echo fit.

Simulation
Large-residual or strongly nonlinear problems lose the quadratic rate (convergence becomes linear); rank-deficient \(\mathbf{J}\) (unidentifiable parameters) needs damping or regularization.
Levenberg–Marquardt: shrink λ when a step works, grow it when it fails.
\((\mathbf{J}^{T}\mathbf{J} + \lambda\mathbf{D})\mathbf{\delta} = -\mathbf{J}^{T}\mathbf{r}\)λ ÷ 10 / × 10

Small \(\lambda\) gives the Gauss–Newton step; large \(\lambda\) gives a short step along the scaled negative gradient, \(-(\lambda\mathbf{D})^{-1}\nabla f\), which always decreases \(f\) for \(\lambda\) large enough, (14.9). The accept/reject rule makes LM a trust-region method in disguise: it never accepts an uphill step. With \(\mathbf{D} = \mathrm{diag}(\mathbf{J}^{T}\mathbf{J})\) (Marquardt) the method is insensitive to parameter units. Rosenbrock: 22 accepted steps from \(\lambda_0 = 10^{-3}\).

Exact formula
It converges to a local minimum: the polarity-flipped echo fit (\(A < 0\), \(t_0\) + 106 ns) is a perfectly converged LM answer. Multistart or a coarse grid is still your job.
Accept a step only if it buys a fixed fraction of the predicted decrease.
\(c_1 = 10^{-4}\)halve α until accepted

Armijo (14.6): \(f(\mathbf{x} + \alpha\mathbf{d}) \le f(\mathbf{x}) + c_1\alpha\nabla f^{T}\mathbf{d}\). For small \(\alpha\) the condition holds whenever \(\mathbf{d}\) is a descent direction, so backtracking terminates; requiring a fraction of the linear prediction rules out the vanishing gains that stall naive "accept any decrease" rules. It replaces the unknown \(L\): the autofocus demo uses it with a sign step, so the same code works for metrics whose curvature differs by \(10^3\).

Exact formula
Does not prevent steps that are too short (add the Wolfe curvature condition), and on a nonconvex cost a long trial step can jump into a different basin.
Adam is sign-like gradient descent with a per-parameter step of about η.
steady \(g\): \(\Delta x = -\eta\,\mathrm{sign}(g)\)β₁ 0.9, β₂ 0.999

\(\hat m\) estimates \(\mathrm{E}[g]\) and \(\hat v\) estimates \(\mathrm{E}[g^2]\); for a steady gradient \(\hat m/\sqrt{\hat v} = \mathrm{sign}(g)\), so each parameter moves by \(\eta\) whatever its units, (14.11): invariant to diagonal rescaling of the gradient, which is why it tolerates mixed sensitivities in large models. On Rosenbrock (\(\eta\) = 0.02) it needs 3034 iterations, close to heavy ball with \(\alpha = 5 \times 10^{-4}\), \(\beta\) = 0.9 (3301): it is not a curvature method.

Exact formula
Not rotation invariant; with a constant \(\eta\) it hovers within about \(\eta\) of the minimum; for small smooth least-squares fits Gauss–Newton or LM is orders of magnitude faster and gives error bars.
Constant-step SGD stalls in a noise ball proportional to the step.
\(\mathrm{E}\,e^2 \to \frac{\alpha\sigma^2}{\lambda(2 - \alpha\lambda)}\)batch \(B\): \(\sigma^2 \to \sigma^2/B\)

With noisy gradients, \(e_{k+1} = (1 - \alpha\lambda)e_k - \alpha n_k\); the variance recursion settles where shrinkage balances injected noise: \(\alpha\sigma^2/(\lambda(2 - \alpha\lambda)) \approx \alpha\sigma^2/(2\lambda)\), (14.10). Halve \(\alpha\): half the floor, half the speed. Decay the step (\(\sum\alpha = \infty\), \(\sum\alpha^2 < \infty\)) or grow the batch to converge.

Exact formula
Assumes independent gradient noise of fixed variance; with finite data the noise vanishes at the optimum of an interpolating model (overparameterized networks), changing the picture.
An L2 misfit on RF has a minimum every period: start within half a period or skip a cycle.
basin ±T₀/2 = ±97 ns at 5 MHzminima at 194, 388 ns

\(\mathcal{L}(\tau) = 2E - 2R(\tau)\) and \(R(\tau) \approx E\,e^{-\tau^2/4\sigma^2}\cos(2\pi f_0\tau)\), (14.12)–(14.13): the cosine creates minima at nearly every multiple of \(T_0\) (the envelope pulls them in to 194, 388 ns) separated by maxima near \(\pm T_0/2\). It is Module 11's false correlation peak seen from the optimizer's side. In the MATLAB lab RF converges only from \(\lvert\tau_0\rvert \le\) 90 ns (19 of 121 starts).

Exact formula
If the amplitude may change sign the minima are every \(T/2\) and the basin is \(\pm T/4\) (56 ns at 4.5 MHz); noise and wider bandwidth change the depth of the false minima, not their spacing.
In travel-time terms, the starting model must predict arrivals to within half a period: Δc/c < λ/(2L).
L = 200 mm, 0.5 MHz → 11 m/sat 5 MHz, 50 mm → 4.5 m/s

A speed error \(\Delta c\) on a path \(L\) shifts the arrival by \(\Delta t = L\Delta c/c^2\). The cycle-skipping bound \(\lvert\Delta t\rvert < T/2\) gives \(\lvert\Delta c\rvert/c < \lambda/(2L)\), one over twice the path length in wavelengths. \(c\) = 1500 m/s: 11.2 m/s at 0.5 MHz over 200 mm, 1.1 m/s at 5 MHz. Hence FWI's travel-time starting models and low starting frequencies.

Exact formula
A single-arrival, transmission criterion; multiple arrivals, strong scattering and amplitude errors make it optimistic.
Find the basin with the envelope or the low band, then polish with the RF.
RF/envelope curvature 31.8LP 1.5 MHz: −29 dB

The envelope misfit \(1 - e^{-\tau^2/4\sigma^2}\) has one minimum (convex for \(\lvert\tau\rvert < \sqrt2\sigma\) = 177 ns), but relative to signal energy its curvature at the minimum is lower than the RF one by \(1 + 2(2\pi f_0\sigma)^2 = 31.8\), and curvature is what sets precision in noise, (14.14). A low-pass widens the RF basin (1.5 MHz corner: ±160 ns) but keeps only −29 dB of a 5 MHz, 60 % pulse, (14.15). Envelope then RF: all 121 starts converge.

Exact formula
Envelope costs ignore the phase information you eventually need; low-frequency content must exist in the data above the noise; each stage can still land in a wrong basin if the coarse cost is biased.
For autofocus, tie the image to time, not depth: a fixed-depth RF pixel ripples every ĉ²/(2zf₀).
7.9 m/s at 1540 m/s, 30 mm, 5 MHztime ROI: one peak over ±200 m/s

A pixel at fixed depth \(z\) is sampled at \(t = 2z/\hat c\), so changing \(\hat c\) slides the echo through the pixel: \(\Delta t = 2z\Delta\hat c/\hat c^2\), one carrier period per \(\hat c^2/(2zf_0)\), (14.19). Its RF value cycle-skips with ripples every 7–8 m/s; its envelope has a ±20 m/s basin. An ROI fixed in two-way time removes the bulk shift, leaving only defocus, and the compounded energy over it has one peak over 1350–1750 m/s.

Approx. modelBulk time shift of a Gaussian-envelope echo through a depth-tied pixel; defocus ignored.
Homogeneous-medium reasoning; in layered or aberrating media the peak is a path average and is biased by the aberration (Module 07).
Total image energy is not a focus metric: receive beamforming moves energy, it does not create it.
\(\int I\) invariant, \(\int I^2\) maximal at focus1 angle: argmax 1540–1570 for c = 1480

Receive DAS over a region is close to an energy-preserving migration of the channel data, so \(\sum\lvert b\rvert^2\) over an ROI is nearly independent of the focusing law; in the demo a single plane wave gives a flat energy curve peaking 60–100 m/s high. Sharpness \(\sum I^2/(\sum I)^2\) rewards concentration (Muller & Buffington, 1974), and coherent compounding over angles rewards agreement between transmits, which is focus: with 5 angles the energy peaks within 2–10 m/s of the truth.

Exact formula
Sharpness fails on fully developed speckle (\(\overline{I^2}/\bar I^2 \approx 2\) at any focus); compounded energy needs several transmits; any ROI-integrated metric carries a small geometric bias.
Forward mode costs one pass per input, reverse mode one pass per output: gradients of a scalar loss are cheap, but the tape is not.
\(\mathbf{J} \in \mathbb{R}^{m\times n}\): \(n\) vs \(m\) passes256²·128·11 delays ≈ 0.74 GB (float64)

Dual numbers propagate one tangent (\(\mathbf{J}\mathbf{v}\)); reverse mode propagates one adjoint (\(\mathbf{v}^{T}\mathbf{J}\)), (14.24). A scalar autofocus loss of \(10^4\) slowness parameters needs one reverse pass at a small constant multiple of the loss cost, against \(2 \times 10^4\) loss evaluations for central differences. The tape stores intermediates: one float64 per pixel–element–angle for a 256 × 256 image, 128 elements and 11 angles is \(9.2 \times 10^7\) values, 0.74 GB per stored quantity.

Exact formula
Memory, not arithmetic, limits reverse mode: use checkpointing, recompute delays on the backward pass, or float32. Forward mode wins when inputs are few (a global \(\hat c\)).
Finite differences lose half the digits; the complex step keeps them all.
forward: \(h \approx 10^{-8}\), error ≈ \(10^{-8}\)complex step: \(h = 10^{-20}\), error ≈ \(10^{-16}\)

Forward differences balance truncation \(h\lvert f''\rvert/2\) against round-off \(2\varepsilon\lvert f\rvert/h\): optimum \(h \sim \sqrt\varepsilon\), error \(\sim\sqrt\varepsilon \approx 10^{-8}\), (14.20). Central differences reach \(\varepsilon^{2/3}\) (\(6 \times 10^{-12}\) at \(h = 3 \times 10^{-6}\) in the MATLAB lab). The complex step \(\mathrm{Im}\,f(x + ih)/h\) involves no subtraction, so any \(h \le 10^{-8}\) gives machine precision (\(2.2 \times 10^{-16}\) at \(h = 10^{-20}\) and \(10^{-100}\)), (14.22).

Simulation
Real-analytic code only: abs, conj, MATLAB's ' operator, branches on comparisons and code that already uses complex arithmetic (IQ beamformers) break it silently.
For a real loss of complex IQ parameters, step along −∂L/∂z*, never −∂L/∂z.
\(\partial_x\mathcal{L} + i\,\partial_y\mathcal{L} = 2\,\partial\mathcal{L}/\partial z^*\)\(\lVert\mathbf{y} - \mathbf{A}\mathbf{w}\rVert^2\): \(-\mathbf{A}^{H}(\mathbf{y} - \mathbf{A}\mathbf{w})\)

Treat \(z\) and \(z^*\) as independent; for real \(\mathcal{L}\) the gradient in (Re, Im) packed as a complex number is \(2\,\partial\mathcal{L}/\partial z^*\), (14.25). For \(\mathcal{L} = \mathbf{w}^{H}\mathbf{R}\mathbf{w}\), \(\partial\mathcal{L}/\partial\mathbf{w}^* = \mathbf{R}\mathbf{w}\), and the normalized ascent is a power iteration toward the time-reversal focusing law. The conjugate, \(\partial\mathcal{L}/\partial\mathbf{w} = (\mathbf{R}\mathbf{w})^*\), flips every imaginary part: in the demo it lowers the coherent energy and leaves 1.5 rad of phase error; on least squares it diverges.

Exact formula
Holds for real-valued losses; a complex-valued loss must first be made real (\(\lvert\cdot\rvert^2\), Re). Check once against central differences on Re and Im separately (the MATLAB lab agrees to \(2 \times 10^{-10}\)).

14.10Cheat sheet

ConceptFormulaUltrasound use
GD stability and rate\(0 < \alpha < 2/L\); \(\rho(\alpha) = \max_i\lvert 1 - \alpha\lambda_i\rvert\); \(\alpha^* = 2/(L+\mu)\), \(\rho^* = (\kappa-1)/(\kappa+1)\)Iteration budgets for any first-order fit or reconstruction
Iterations to \(\varepsilon\)GD \(\approx (\kappa/2)\ln(1/\varepsilon)\); heavy ball \(\approx (\sqrt\kappa/2)\ln(1/\varepsilon)\)κ = 100: 691 vs 69 (93 measured)
Heavy ball / Nesterov\(\alpha = 4/(\sqrt L+\sqrt\mu)^2\), \(\beta = \left(\frac{\sqrt\kappa-1}{\sqrt\kappa+1}\right)^2\); Nesterov \(\alpha = 1/L\), \(\beta = \frac{\sqrt\kappa-1}{\sqrt\kappa+1}\), \(\rho = 1 - 1/\sqrt\kappa\)Accelerated iterative reconstruction (FISTA is Nesterov on a proximal step)
Jacobi scaling\(\tilde{\mathbf{\theta}} = \mathbf{D}\mathbf{\theta}\), \(\mathbf{D} = \mathrm{diag}(\lVert\mathbf{J}_{:,j}\rVert)\)Mixing m/s, dB/cm/MHz, µm in one parameter vector
Armijo\(f(\mathbf{x}+\alpha\mathbf{d}) \le f(\mathbf{x}) + c_1\alpha\nabla f^{T}\mathbf{d}\), \(c_1 = 10^{-4}\), \(\alpha \leftarrow \alpha/2\)Step size without knowing \(L\); robust autofocus ascent
Newton\(\mathbf{d} = -\mathbf{H}^{-1}\nabla f\); \(e_{k+1} \propto e_k^2\); affine invariantSmall, smooth problems near the answer
Gauss–Newton\(\mathbf{J}\mathbf{\delta} \approx -\mathbf{r}\) (QR); \(\nabla^2 f \approx \mathbf{J}^{T}\mathbf{J}\); \(\mathrm{cov} \approx \sigma^2(\mathbf{J}^{T}\mathbf{J})^{-1}\)BSC, attenuation, echo-model fits with error bars
Levenberg–Marquardt\((\mathbf{J}^{T}\mathbf{J} + \lambda\,\mathrm{diag}\,\mathbf{J}^{T}\mathbf{J})\mathbf{\delta} = -\mathbf{J}^{T}\mathbf{r}\); λ ÷10 success, ×10 failureDefault for 2–10 parameter QUS fits
SGD noise floor\(\mathrm{E}\,e^2 \to \alpha\sigma^2/(\lambda(2 - \alpha\lambda))\); \(\sigma^2 \propto 1/B\)Training learned beamformers; patch-averaged autofocus
Adam\(x \mathrel{-}= \eta\,\hat m/(\sqrt{\hat v} + \epsilon)\); steady \(g\) → step \(\eta\,\mathrm{sign}(g)\)Large differentiable beamformers and networks
RF misfit\(\mathcal{L}(\tau) = 2E - 2R(\tau)\), \(R \approx E\,e^{-\tau^2/4\sigma^2}\cos 2\pi f_0\tau\)Delay, phase-screen and waveform fits
Cycle-skipping basin\(\lvert\Delta\tau\rvert < T/2\) (\(T/4\) with free polarity); \(\lvert\Delta c\rvert/c < \lambda/(2L)\)Starting models for FWI and USCT
Envelope vs RF curvatureratio \(1 + 2(2\pi f_0\sigma)^2\) (31.8 at 5 MHz, σ = 0.125 µs)Coarse-to-fine (multiscale) schedules
Fixed-depth autofocus ripple\(\Delta\hat c = \hat c^2/(2zf_0)\)7.9 m/s at 30 mm: use time-tied ROIs
Beamformer derivative\(db/d\hat c = \sum (\mathrm{IQ}' + j\omega_0\mathrm{IQ})\,e^{j\omega_0\tau}\,\partial\tau/\partial\hat c\)Exact gradients for sound-speed autofocus
Finite differencesforward \(h \sim \sqrt\varepsilon\), error \(\sim\sqrt\varepsilon\); central \(h \sim \varepsilon^{1/3}\), error \(\sim\varepsilon^{2/3}\)Gradient checks, not production gradients
Complex step\(f' \approx \mathrm{Im}\,f(x+ih)/h\), \(h = 10^{-20}\)Exact derivatives of real MATLAB code
Forward vs reverse AD\(\mathbf{J} \in \mathbb{R}^{m\times n}\): \(n\) vs \(m\) passes; reverse stores the tapeReverse for scalar losses of SoS maps
Wirtinger\(\partial/\partial z^* = \tfrac12(\partial_x + i\partial_y)\); descend along \(-\partial\mathcal{L}/\partial z^*\)Gradients w.r.t. IQ weights, focusing and aberration laws
Phase-only gradient\(\partial(\mathbf{w}^{H}\mathbf{R}\mathbf{w})/\partial\theta_e = 2\,\mathrm{Im}\left(w_e^*(\mathbf{R}\mathbf{w})_e\right)\)Aberration correction by coherence maximization

14.11Interview and qualifying-exam questions

I1Your gradient-descent reconstruction converges painfully slowly. Diagnose it and give the rate. · screen

Slow linear convergence means a large condition number of the Hessian. With the optimal fixed step \(2/(L + \mu)\) the error contracts by \((\kappa - 1)/(\kappa + 1)\) per iteration, about \((\kappa/2)\ln(1/\varepsilon)\) iterations: 691 for \(\kappa\) = 100 and \(\varepsilon = 10^{-6}\). First check the scaling (parameters in mixed units inflate \(\kappa\) by orders of magnitude; Jacobi scaling fixed \(1.2 \times 10^6 \to 1.17\) in the lab), then add momentum or use conjugate gradients (\(\sqrt\kappa\) dependence), or switch to Gauss–Newton if it is a least-squares problem. Follow-up: why does momentum help? Per mode it is a second-order recursion; tuned, its roots have modulus \((\sqrt\kappa-1)/(\sqrt\kappa+1)\), so iterations scale with \(\sqrt\kappa\).

I2How do you choose the step size when you do not know L? · screen

Backtracking with the Armijo condition: try \(\alpha\) (or 2× the last accepted \(\alpha\)), halve until \(f(\mathbf{x} + \alpha\mathbf{d}) \le f(\mathbf{x}) + 10^{-4}\alpha\nabla f^{T}\mathbf{d}\). Alternatively estimate \(L\) by a few power iterations on Hessian–vector products and use \(1/L\). For least squares, Gauss–Newton or LM chooses the step from curvature and needs no \(\alpha\). Follow-up: what can go wrong? Too short steps (add the Wolfe curvature condition) and, on nonconvex costs, long trial steps that jump basins; cap the trial step at a physically meaningful size (40 m/s in the autofocus demo).

I3You fit a backscatter or attenuation model with 3–5 parameters. GD, Gauss–Newton, LM or Adam? · onsite

LM: it behaves like Gauss–Newton (quadratic convergence for small residuals, about 10 iterations in the lab's echo fit) near the answer and like scaled gradient descent far from it, and never accepts an uphill step. Solve the subproblem with QR or with the scaled normal equations at this size, and scale parameters. At convergence \(\sigma^2(\mathbf{J}^{T}\mathbf{J})^{-1}\) gives the CRLB-type error bars (0.69 ns on \(t_0\)). Adam would take thousands of iterations and give no covariance. Follow-up: when does Gauss–Newton degrade? Large residuals (model error) or strong nonlinearity make the neglected \(\sum r_i\nabla^2 r_i\) term matter; convergence becomes linear.

I4Explain cycle skipping and quantify it for a 5 MHz pulse. · onsite

The L2 misfit between an echo and a delayed model is \(2E - 2R(\tau)\); for an RF pulse \(R(\tau) \approx E\,e^{-\tau^2/4\sigma^2}\cos 2\pi f_0\tau\), so local minima appear near every period (194, 388 ns for \(f_0\) = 5 MHz, \(\sigma\) = 0.125 µs) and the basin of the true minimum ends near \(\pm T_0/2\) = ±97 ns. A start beyond that converges to the wrong cycle. In travel-time form the starting model must satisfy \(\lvert\Delta c\rvert/c < \lambda/(2L)\). Remedies: envelope or correlation-based costs, low frequencies, multiscale schedules, better starting models. Follow-up: why not just low-pass the data? The energy is not there: a 1.5 MHz Gaussian low-pass keeps −29 dB of a 5 MHz, 60 % pulse, so noise dominates; you must transmit low frequencies.

I5Design a gradient-based global sound-speed estimator for a linear array. · research

Acquire several plane-wave angles; beamform IQ data on an ROI fixed in two-way time (pixel depth \(\hat ct/2\)) so that \(\hat c\) only changes focusing; maximize the coherently compounded energy or a coherence metric over ROIs with bright, diffuse echoes; get \(dM/d\hat c\) exactly (chain rule through delays and the interpolator, or AD), check it once by central differences; climb with a line search and a box constraint, from a coarse sweep or several starts. Report bias (calibrate on phantoms: the demo shows +2 to +10 m/s geometric bias) and precision across ROIs. Follow-up: why not maximize the energy of a single plane-wave image, or the RF value at the target depth? The first is nearly invariant to focusing (receive migration preserves energy); the second cycle-skips every \(\hat c^2/(2zf_0) \approx\) 8 m/s.

I6Forward or reverse mode for a differentiable beamformer with a 100 × 100 slowness map and a scalar loss? What limits it? · onsite

Reverse mode: \(10^4\) inputs, 1 output, so one backward pass at a small constant multiple of the forward cost, against \(10^4\) forward-mode passes. The limit is memory: the tape stores delays, interpolation indices and weights per pixel, element and transmit; for 256 × 256 pixels, 128 elements and 11 angles that is \(9.2 \times 10^7\) values, 0.74 GB per float64 quantity. Use checkpointing (recompute delays on the backward pass), float32 and patch-wise losses. Follow-up: when is forward mode better? Few parameters (a single \(\hat c\), a handful of layer speeds): one dual-number pass per parameter, no tape.

I7What is the complex-step derivative, why can h be 10⁻²⁰, and when does it fail? · screen

\(f'(x) \approx \mathrm{Im}\,f(x + ih)/h\). The Taylor series gives \(\mathrm{Im}\,f(x + ih) = hf'(x) - h^3f'''/6 + \dots\), with no subtraction of nearly equal numbers, so round-off does not grow as \(h\) shrinks and \(h = 10^{-20}\) yields machine precision (\(2.2 \times 10^{-16}\) in the lab) against ~\(10^{-8}\) for forward differences. It fails for non-analytic operations (abs, conj, MATLAB's ', max/min branches) and for code that already uses complex numbers, such as an IQ beamformer. Follow-up: what would you use for the IQ beamformer? Dual numbers or reverse-mode AD, or the hand-derived chain rule, verified once by central differences.

I8Derive the gradient of ‖y − Aw‖² with respect to complex w, and say how you would test it. · research

\(\mathcal{L} = (\mathbf{y} - \mathbf{A}\mathbf{w})^{H}(\mathbf{y} - \mathbf{A}\mathbf{w})\). Treating \(\mathbf{w}\) and \(\mathbf{w}^*\) as independent, \(\partial\mathcal{L}/\partial\mathbf{w}^* = -\mathbf{A}^{H}(\mathbf{y} - \mathbf{A}\mathbf{w})\); the steepest-descent update is \(\mathbf{w} \leftarrow \mathbf{w} + \mu\mathbf{A}^{H}(\mathbf{y} - \mathbf{A}\mathbf{w})\), which is the LMS/Landweber step. Test: perturb \(\mathrm{Re}\,w_k\) and \(\mathrm{Im}\,w_k\) separately by \(\pm h\); \(d\mathcal{L}/d\mathrm{Re} + i\,d\mathcal{L}/d\mathrm{Im}\) must equal \(2\,\partial\mathcal{L}/\partial w_k^*\) (agreement \(2 \times 10^{-10}\) in the lab). Follow-up: what happens with the conjugate direction? The imaginary parts of all steps flip sign; the lab's run diverges to \(10^{62}\).

I9Adam converged to a slightly different answer each run and never quite settles. Why? · onsite

With a constant learning rate \(\eta\), Adam moves each parameter by about \(\eta\) per step (\(\hat m/\sqrt{\hat v} \approx \mathrm{sign}\,g\)), so it hovers in a band of order \(\eta\) around the minimum; with stochastic gradients there is also a noise floor proportional to the step (\(\alpha\sigma^2/(2\lambda)\) for SGD). Decay \(\eta\), increase the batch, or finish with a deterministic second-order method on the full cost. Follow-up: is Adam scale invariant? To a diagonal rescaling of the gradient yes (though a step of η still means different physical changes in different parameter units), to rotations no: a rotated narrow valley still slows it (Rosenbrock: 3034 iterations).

I10You maximize coherent energy over element phases on speckle. The optimizer converges, the energy exceeds that of the true correction, but the estimated screen is off by 0.14 rad rms. Explain. · research

The cost is the sample coherent energy \(\mathbf{w}^{H}\hat{\mathbf{R}}\mathbf{w}\) with \(\hat{\mathbf{R}}\) from \(K\) = 64 realizations. Speckle has no unique focal point: \(\hat{\mathbf{R}}\) is far from rank one (\(\lambda_1/\lambda_2 \approx 2.4\) in the demo, against about 80 with a point 10 dB above the speckle) and its top eigenvector fits the sampling fluctuations of \(\hat{\mathbf{R}}\), so the optimizer finds a law that beats the true one on this data set yet differs from it. A point-like target (guide star) makes \(\hat{\mathbf{R}}\) nearly rank one: at 10 dB target-to-speckle ratio the error drops to about 0.02 rad. More independent realizations, isoplanatic averaging or the distortion-matrix approach (Module 06) also help. Follow-up: why remove tilt before scoring? A linear phase only steers the beam (Module 07); it is not identifiable from coherence.

14.12MATLAB 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.

Download the scripts: m14_gd_conditioning.m · m14_gauss_newton_lm.m · m14_cycle_skipping.m · m14_complex_step_ad.m · m14_autofocus_sound_speed.m. Base MATLAB R2019b+ or GNU Octave 8, no toolboxes; all scripts in the repository.

m14_gd_conditioning.mIterations to 10⁻⁶ for GD (2/(L+μ) and 1/L), heavy ball and Nesterov vs the rate formulas at κ = 10, 100, 1000; divergence above 2/L; Jacobi scaling of an m/s + amplitude problem · change kappa_list, th · runtime ≈ 2 s
%% m14_gd_conditioning.m  --  gradient descent, momentum and the condition number
% Purpose : minimize the quadratic f(x) = 1/2 x'*A*x (minimum at 0) with eigenvalues
%           mu = 1 and L = kappa, and count iterations to reduce the error norm by 1e-6.
%           Compares gradient descent with the optimal fixed step 2/(L+mu), with step 1/L,
%           Polyak heavy-ball with its optimal (alpha, beta), and Nesterov's method
%           (step 1/L, momentum (sqrt(kappa)-1)/(sqrt(kappa)+1)) against the rate formulas.
%           Then shows that diagonal rescaling of badly scaled parameters (here a sound
%           speed in m/s and a dimensionless amplitude) removes most of kappa.
% Change  : kappa_list, tol, the rotation angle th, the momentum settings.
% Expect  : kappa = 100: GD(2/(L+mu)) 691 iterations (theory 691), GD(1/L) 1341 (1375; this
%           start puts only 1/sqrt(2) of the error on the slow mode), heavy ball 93 and
%           Nesterov 155 (rate-only predictions 69 and 131: both tuned iterations have a
%           double root, so the error decays as k*rho^k, not rho^k). Jacobi scaling of a
%           (m/s, amplitude) problem drops kappa(J'J) from about 1e6 to about 1.
% Base MATLAB only; runs in MATLAB R2019b+ and GNU Octave 8.
rng(1);

%% 1. Iterations to tolerance vs kappa
tol = 1e-6;  kappa_list = [10 100 1000];  maxit = 1e5;
th = pi/6;  Q = [cos(th) -sin(th); sin(th) cos(th)];          % rotate so the axes are not the eigenvectors
fprintf('kappa | GD 2/(L+mu)  theory | GD 1/L  theory | heavy ball  theory | Nesterov  theory\n');
hist100 = {};
for kappa = kappa_list
    mu = 1;  L = kappa;  A = Q * diag([mu L]) * Q.';
    x0 = Q * [1; 1];
    sk = sqrt(kappa);
    cfg = { 2/(L+mu), 0, 'hb';                                  % {alpha, beta, type}
            1/L,      0, 'hb';
            4/(sqrt(L)+sqrt(mu))^2, ((sk-1)/(sk+1))^2, 'hb';
            1/L,      (sk-1)/(sk+1), 'nest' };
    its = zeros(1, 4);
    for m = 1:4
        a = cfg{m,1};  b = cfg{m,2};  x = x0;  xp = x0;  e = zeros(1, maxit);
        for k = 1:maxit
            e(k) = norm(x) / norm(x0);
            if e(k) < tol, break; end
            if strcmp(cfg{m,3}, 'nest')
                y = x + b*(x - xp);  xn = y - a*(A*y);
            else
                xn = x - a*(A*x) + b*(x - xp);
            end
            xp = x;  x = xn;
        end
        its(m) = k - 1;
        if kappa == 100, hist100{m} = e(1:k); end
    end
    th_gd = log(1/tol) / log((kappa+1)/(kappa-1));
    th_1L = log(1/tol) / -log(1 - 1/kappa);
    th_hb = log(1/tol) / log((sk+1)/(sk-1));
    th_ne = log(1/tol) / -log(1 - 1/sk);
    fprintf('%5d | %6d  %6.0f     | %6d  %6.0f | %6d  %6.0f     | %6d  %6.0f\n', ...
        kappa, its(1), th_gd, its(2), th_1L, its(3), th_hb, its(4), th_ne);
end

%% 2. Divergence threshold: step just above 2/L
kappa = 100;  A = Q * diag([1 kappa]) * Q.';  x = Q * [1; 1];
for k = 1:50, x = x - (2.05/kappa) * (A*x); end
fprintf('step 2.05/L after 50 iterations: |x| = %.3g (diverges; factor |1 - 2.05| = 1.05 per step)\n', norm(x));

%% 3. Badly scaled parameters: sound speed (m/s) and amplitude (unitless)
% Linearized model y = J*[dc; dA] with column sensitivities that differ by 3 orders.
J = [randn(50,1) * 1e-3, randn(50,1)];          % d y / d c (per m/s) and d y / d A
H = J.' * J;  D = diag(1 ./ sqrt(diag(H)));     % Jacobi (diagonal) preconditioner
fprintf('kappa(J''J) raw %.3g  ->  after column scaling %.3g\n', cond(H), cond(D*H*D));
kr = cond(H);  ks = cond(D*H*D);
fprintf('GD iterations to 1e-6 (optimal step): raw %.3g, scaled %.0f\n', ...
    log(1e6)/log((kr+1)/(kr-1)), log(1e6)/log((ks+1)/(ks-1)));

%% 4. Figures: error histories (kappa = 100) and paths on the contours
figure('Position', [100 100 1050 420]);
subplot(1,2,1);
cl = {[0 0.3 0.8], [0.6 0.6 0.6], [0.8 0.2 0.5], [0 0.55 0.4]};  hh = zeros(1,6);
for m = 1:4
    hh(m) = semilogy(0:numel(hist100{m})-1, hist100{m}, 'Color', cl{m}, 'LineWidth', 1.5); hold on;
end
kk = 0:700;
hh(5) = semilogy(kk, ((100-1)/(100+1)).^kk, '--', 'Color', cl{1});
hh(6) = semilogy(kk, ((10-1)/(10+1)).^kk, '--', 'Color', cl{3});
grid on; ylim([1e-7 2]); xlim([0 700]); xlabel('iteration k'); ylabel('||x_k|| / ||x_0||');
legend(hh, {'GD 2/(L+\mu)', 'GD 1/L', 'heavy ball', 'Nesterov', '((\kappa-1)/(\kappa+1))^k', '((\surd\kappa-1)/(\surd\kappa+1))^k'}, 'Location', 'northeast');
title('\kappa = 100: measured error vs rate formulas');
subplot(1,2,2);
kappa = 30;  A = Q * diag([1 kappa]) * Q.';
[g1, g2] = meshgrid(linspace(-1.6, 1.6, 200), linspace(-1.6, 1.6, 200));
F = 0.5 * (A(1,1)*g1.^2 + 2*A(1,2)*g1.*g2 + A(2,2)*g2.^2);
contour(g1, g2, log10(F + 1e-3), 14); hold on; colormap(gray);
x0 = Q * [1.2; 0.25];  hp = zeros(1,2);
for m = 1:2
    if m == 1, a = 2/(kappa+1); b = 0; col = [0 0.3 0.8]; else, sk = sqrt(kappa); a = 4/(sk+1)^2; b = ((sk-1)/(sk+1))^2; col = [0.8 0.2 0.5]; end
    x = x0; xp = x0; P = x0;
    for k = 1:60, xn = x - a*(A*x) + b*(x - xp); xp = x; x = xn; P(:, end+1) = x; end
    hp(m) = plot(P(1,:), P(2,:), '.-', 'Color', col, 'LineWidth', 1.2, 'MarkerSize', 10);
end
axis image; xlabel('x_1'); ylabel('x_2'); title('\kappa = 30: GD zig-zags, heavy ball spirals in');
legend(hp, {'GD 2/(L+\mu)', 'heavy ball (optimal \alpha, \beta)'}, 'Location', 'southoutside');

What to look for: GD with \(2/(L + \mu)\) matches theory exactly (69, 691, 6908); \(1/L\) gives 1341 at \(\kappa\) = 100 (theory 1375 for an error fully on the slow mode); heavy ball 27, 93, 315 and Nesterov 43, 155, 508 against rate-only 21, 69, 218 and 36, 131, 430 (the double root adds a \(k\) factor); \(\alpha = 2.05/L\) reaches \(\lvert x\rvert\) = 11.5 after 50 steps; \(\kappa(\mathbf{J}^{T}\mathbf{J})\) \(1.22 \times 10^6 \to 1.17\).

m14_gauss_newton_lm.mGaussian-pulse echo fit by GD + Armijo (raw and scaled), Gauss–Newton and LM; error bars from (JᵀJ)⁻¹; a start beyond T/4 that lands half a period late; free-phase fix · change th_true, sn, starts · runtime ≈ 7 s
%% m14_gauss_newton_lm.m  --  gradient descent vs Gauss-Newton vs Levenberg-Marquardt
% Purpose : fit a Gaussian-pulse echo model to a noisy RF echo by nonlinear least squares
%             s(t; A, t0, sg, f) = A exp(-(t-t0)^2/(2 sg^2)) cos(2 pi f (t - t0))
%           (units: t, t0, sg in us; f in MHz) and compare
%             GD + Armijo backtracking, Gauss-Newton (J'J d = -J'r), and
%             Levenberg-Marquardt ((J'J + lam diag(J'J)) d = -J'r, lam /10 on success, x10 on failure).
%           Prints the iterations, the estimates, the linearized standard deviations
%           sqrt(diag(sn^2 (J'J)^-1)) (the Gaussian-noise CRLB of Module 12 evaluated at the
%           solution), kappa(J'J) before and after column scaling, and shows that a start
%           more than half a period off in t0 converges to the wrong cycle unless the model
%           has a free carrier phase.
% Change  : theta_true, sn (noise), the starts, lam0.
% Expect  : good start: GN and LM about 10 iterations, GD + Armijo about 10^4 in raw units
%           and tens after Jacobi scaling; bad start (t0 off by 100 ns, more than T/4 = 56 ns):
%           LM lands half a period late with the polarity flipped (A < 0, t0 near 2.11 us,
%           |r| three times the noise level); the free-phase model recovers t0 = 2.00 us.
% Base MATLAB only; runs in MATLAB R2019b+ and GNU Octave 8. Runtime about 2 s.
rng(1);

%% 1. Data
fs = 50;                          % sampling rate (MHz) -> dt = 0.02 us
t = (1:1/fs:3).';                 % time axis (us), 101 samples
th_true = [1, 2.00, 0.15, 4.5];   % [A, t0 (us), sg (us), f (MHz)]
sn = 0.05;                        % noise std (peak SNR = 20 log10(1/0.05) = 26 dB)
model = @(p) p(1) * exp(-(t-p(2)).^2/(2*p(3)^2)) .* cos(2*pi*p(4)*(t-p(2)));
y = model(th_true) + sn * randn(size(t));
% analytic Jacobian of the residual r = model - y (columns: A, t0, sg, f)
jac = @(p) [exp(-(t-p(2)).^2/(2*p(3)^2)) .* cos(2*pi*p(4)*(t-p(2))), ...
     p(1)*exp(-(t-p(2)).^2/(2*p(3)^2)) .* ((t-p(2))/p(3)^2 .* cos(2*pi*p(4)*(t-p(2))) + 2*pi*p(4)*sin(2*pi*p(4)*(t-p(2)))), ...
     p(1)*exp(-(t-p(2)).^2/(2*p(3)^2)) .* cos(2*pi*p(4)*(t-p(2))) .* (t-p(2)).^2/p(3)^3, ...
    -p(1)*exp(-(t-p(2)).^2/(2*p(3)^2)) .* sin(2*pi*p(4)*(t-p(2))) .* 2*pi.*(t-p(2))];
cost = @(p) 0.5 * sum((model(p) - y).^2);
% check the Jacobian against central differences
p = [0.9 2.03 0.13 4.8];  Jn = zeros(numel(t), 4);
for k = 1:4, e = zeros(1,4); e(k) = 1e-6; Jn(:,k) = (model(p+e) - model(p-e)) / 2e-6; end
fprintf('Jacobian check: max |analytic - numeric| / max|J| = %.1e\n', max(max(abs(jac(p)-Jn))) / max(abs(Jn(:))));

%% 2. Solvers from a good start and from a start beyond a quarter period
% GD+Armijo in raw units (step capped at 0.01), GD+Armijo after Jacobi (column) scaling,
% Gauss-Newton (least-squares solve of J d = -r) and Levenberg-Marquardt.
starts = {[0.8, 2.04, 0.12, 4.8], [0.8, 2.10, 0.12, 4.5]};
labels = {'good start (dt0 = +40 ns, df = +0.3 MHz)', 'bad start (dt0 = +100 ns > T/4)'};
nm = {'GD+Armijo', 'GD+Armijo+scale', 'Gauss-Newton', 'LM'};
hist = cell(2, 4);
for s = 1:2
    fprintf('\n%s; period T = %.0f ns\n', labels{s}, 1e3/th_true(4));
    for meth = 1:4
        p = starts{s};  lam = 1e-3;  al = 1e-2;  h = cost(p);  it = 0;
        if meth == 2, Dsc = 1 ./ sqrt(sum(jac(p).^2, 1)); amax = 1; else, Dsc = ones(1,4); amax = 1e-2; end
        while it < 20000
            r = model(p) - y;  J = jac(p);  g = (J.' * r).';
            if meth <= 2                                  % (scaled) GD + Armijo backtracking
                d = -(Dsc.^2) .* g;  al = min(amax, 2*al);
                while cost(p + al*d) > cost(p) + 1e-4*al*(g*d.'), al = al/2; end
                pn = p + al*d;
            elseif meth == 3                              % Gauss-Newton
                pn = p - (J \ r).';                       % least-squares solve, J'J never formed
            else                                          % Levenberg-Marquardt
                H = J.'*J;
                while true
                    pn = p - ((H + lam*diag(diag(H))) \ g.').';
                    if cost(pn) < cost(p), lam = lam/10; break; end
                    lam = lam*10;  if lam > 1e12, pn = p; break; end
                end
            end
            it = it + 1;  step = norm(pn - p);  p = pn;  h(end+1) = cost(p);
            if step < 1e-9, break; end
        end
        hist{s, meth} = h;
        fprintf('%-16s %5d its  A = %7.4f  t0 = %.4f us  sg = %.4f us  f = %.4f MHz  |r| = %.4f\n', ...
            nm{meth}, it, p(1), p(2), abs(p(3)), abs(p(4)), sqrt(2*cost(p)));
        if s == 1 && meth == 4, p_hat = p; end
    end
end
fprintf('expected |r| for a correct fit: sn*sqrt(n) = %.3f\n', sn*sqrt(numel(t)));

%% 3. Precision at the solution and conditioning
J = jac(p_hat);  H = J.'*J;  sd = sqrt(diag(sn^2 * (H \ eye(4))));
fprintf('\nlinearized std (CRLB at the fit): A %.4f, t0 %.2f ns, sg %.2f ns, f %.4f MHz\n', sd(1), 1e3*sd(2), 1e3*sd(3), sd(4));
Dg = diag(1 ./ sqrt(diag(H)));
fprintf('kappa(J''J) = %.3g in (1, us, us, MHz) units; %.3g after column scaling\n', cond(H), cond(Dg*H*Dg));
Hs = diag([1 1e-6 1e-6 1e6]) * H * diag([1 1e-6 1e-6 1e6]);
fprintf('kappa(J''J) = %.3g if the same fit is written in SI units (1, s, s, Hz)\n', cond(Hs));

%% 4. Free carrier phase removes the cycle ambiguity in t0
modelp = @(q) q(1) * exp(-(t-q(2)).^2/(2*q(3)^2)) .* cos(2*pi*q(4)*(t-q(2)) + q(5));
costp = @(q) 0.5 * sum((modelp(q) - y).^2);
q = [starts{2} 0];  lam = 1e-3;
for it = 1:200
    r = modelp(q) - y;  Jq = zeros(numel(t), 5);
    for k = 1:5, e = zeros(1,5); e(k) = 1e-7; Jq(:,k) = (modelp(q+e) - modelp(q-e)) / 2e-7; end
    H = Jq.'*Jq;  g = Jq.'*r;
    while true
        qn = q - ((H + lam*diag(diag(H))) \ g).';
        if costp(qn) < costp(q), lam = lam/10; break; end
        lam = lam*10;  if lam > 1e12, qn = q; break; end
    end
    if norm(qn - q) < 1e-10, q = qn; break; end
    q = qn;
end
fprintf('free-phase LM from the bad start: t0 = %.4f us, phase = %.3f rad, |r| = %.4f (%d its)\n', q(2), angle(exp(1j*q(5))), sqrt(2*costp(q)), it);

%% 5. Figure
figure('Position', [100 100 1050 420]);
subplot(1,2,1);
cols = {[0.6 0.6 0.6], [0.85 0.55 0], [0 0.3 0.8], [0.8 0.2 0.5]};  hh = zeros(1,4);
for meth = 1:4
    hh(meth) = semilogy(1:numel(hist{1,meth}), hist{1,meth} - min(hist{1,4}) + 1e-12, 'Color', cols{meth}, 'LineWidth', 1.5); hold on;
end
set(gca, 'XScale', 'log'); grid on; xlim([1 2e4]);
xlabel('iteration'); ylabel('cost - final cost');
legend(hh, {'GD + Armijo (raw units)', 'GD + Armijo (Jacobi scaled)', 'Gauss-Newton', 'Levenberg-Marquardt'}, 'Location', 'southwest');
title('good start: linear vs quadratic convergence');
subplot(1,2,2);
plot(t, y, 'Color', [0.6 0.6 0.6]); hold on;
plot(t, model(p_hat), 'b', 'LineWidth', 1.5);
plot(t, model(starts{2}), 'r--');
xlabel('time (\mus)'); ylabel('amplitude'); grid on; xlim([1.4 2.6]);
legend('data', 'LM fit (good start)', 'bad start model', 'Location', 'southwest');
title('echo, fit, and a start that lands half a period late');

What to look for: good start: GD 10 828 iterations raw, 51 scaled, Gauss–Newton 13, LM 12, all at \(t_0\) = 1.9997 µs with \(\lvert\mathbf{r}\rvert\) = 0.520 (noise level 0.502); linearized std of \(t_0\) 0.69 ns; \(\kappa = 1.82 \times 10^3\) raw, 3.73 scaled, \(2.1 \times 10^{22}\) in SI units. Bad start (+100 ns): scaled GD, Gauss–Newton and LM all converge to \(A\) = −0.75, \(t_0\) = 2.106 µs, \(\lvert\mathbf{r}\rvert\) = 1.29; unscaled small-step GD happens to reach the right answer; the free-phase model recovers \(t_0\) = 1.994 µs.

m14_cycle_skipping.mRF, envelope and low-passed misfits of a 5 MHz pulse from sampled signals; local minima; GD from 121 starts; envelope-then-RF schedule; the FWI travel-time criterion · change f0, sg, fl · runtime ≈ 3 s
%% m14_cycle_skipping.m  --  why RF misfits trap gradient descent, and how to widen the basin
% Purpose : delay estimation by minimizing L(tau) = sum (d(t) - s(t - tau))^2 for a 5 MHz
%           Gaussian pulse (60 % bandwidth). Compares three misfits computed numerically
%           on sampled signals: RF, envelope (|analytic signal|, FFT Hilbert), and RF after
%           a Gaussian low-pass at 1.5 or 1.0 MHz. Lists the local minima, runs gradient
%           descent from 121 starting delays, and shows that a multiscale schedule (envelope
%           first, then RF) converges from starts the RF misfit alone cannot handle. Ends with
%           the travel-time form of the criterion used in full-waveform inversion.
% Change  : f0, sg, the low-pass corner fl, the starting delays.
% Expect  : RF local minima at 0, +-194, +-388 ns (just inside multiples of T0 = 200 ns);
%           RF basin |tau0| < 97 ns; envelope converges from every start (no local minima);
%           low-pass at 1.5 MHz: basin about +-160 ns at -29 dB of the pulse energy;
%           envelope first, then RF: converges from every start with RF curvature (32x
%           the envelope curvature at the minimum).
% Base MATLAB only; runs in MATLAB R2019b+ and GNU Octave 8. Runtime about 5 s.
rng(1);

%% 1. Signals
f0 = 5e6; sg = 0.125e-6;           % centre frequency (Hz), envelope std (s)
fs = 1e9; t = (-3e-6:1/fs:3e-6).';  % fine grid so delays are continuous (1 ns)
nT = numel(t);  nf = 2^nextpow2(2*nT);
fax = [0:nf/2-1, -nf/2:-1].' * fs / nf;              % FFT frequency axis (Hz)
pulse = @(tau) exp(-(t-tau).^2/(2*sg^2)) .* cos(2*pi*f0*(t-tau));
fl = 1.5e6;                                           % Gaussian low-pass corner (Hz)
lowp  = @(x) real(ifft(fft(x, nf) .* exp(-fax.^2/(2*fl^2))));
H     = @(x) ifft(fft(x, nf) .* (1 + sign(fax)));     % analytic signal (x + j Hilbert x)
crop  = @(x) x(1:nT);
envl  = @(x) abs(crop(H(x)));
d = pulse(0);                                          % data: true delay 0
fprintf('low-pass at %.1f MHz keeps %.1f dB of the pulse energy\n', fl/1e6, 10*log10(sum(crop(lowp(d)).^2)/sum(d.^2)));

%% 2. Misfit curves, computed numerically from the sampled signals
% L(tau) = sum (a - b_tau)^2 = sum a^2 + sum b^2 - 2 R_ab(tau): all shifts at once by FFT
% correlation (a shift commutes with the low-pass filter and with taking the envelope).
xc = @(a, b) real(ifft(fft(a, nf) .* conj(fft(b, nf))));
lagk = -600:600;  taus = lagk * 1e-9;                  % 1 ns lags
mis = @(a, b) sum(a.^2) + sum(b.^2) - 2 * subsref(xc(b, a), struct('type', '()', 'subs', {{mod(lagk, nf) + 1}})).';
dE = envl(d);  dL = crop(lowp(d));
fl2 = 1.0e6;  lowp2 = @(x) real(ifft(fft(x, nf) .* exp(-fax.^2/(2*fl2^2))));  dL2 = crop(lowp2(d));
L = [mis(d, d); mis(dE, dE); mis(dL, dL); mis(dL2, dL2)];
L = L ./ (2*[sum(d.^2); sum(dE.^2); sum(dL.^2); sum(dL2.^2)]);   % normalize by 2 x energy: L = 1 - R(tau)/R(0)
fprintf('low-pass at %.1f MHz keeps %.1f dB of the pulse energy\n', fl2/1e6, 10*log10(sum(dL2.^2)/sum(d.^2)));
names = {'RF', 'envelope', 'LP 1.5 MHz', 'LP 1.0 MHz'};
for m = 1:4
    loc = find(L(m,2:end-1) < L(m,1:end-2) & L(m,2:end-1) < L(m,3:end)) + 1;
    fprintf('%-11s local minima (ns): %s\n', names{m}, sprintf('%g ', round(taus(loc)*1e9)));
end
mx = find(L(1,2:end-1) > L(1,1:end-2) & L(1,2:end-1) > L(1,3:end)) + 1;
fprintf('RF local maxima nearest 0 (basin edges): %s ns; T0/2 = %.0f ns\n', sprintf('%g ', round(taus(mx(abs(taus(mx)) < 150e-9))*1e9)), 0.5e9/f0);

%% 3. Gradient descent from many starts on the tabulated misfits
% dL/dtau by central differences on the 1 ns table; step = 1/L''(0) (Newton step at the minimum)
dLdt = zeros(size(L));  dLdt(:,2:end-1) = (L(:,3:end) - L(:,1:end-2)) / 2e-9;
curv = (L(:,602) - 2*L(:,601) + L(:,600)) / 1e-18;    % L'' at tau = 0
fprintf('curvature at the minimum, RF / envelope = %.1f (theory 1 + 2 (2 pi f0 sg)^2 = %.1f)\n', curv(1)/curv(2), 1 + 2*(2*pi*f0*sg)^2);
starts = (-600:10:600) * 1e-9;
plan = {1, 2, 3, 4, [2 1]};                           % misfits used in sequence
lbl = {'RF', 'envelope', 'LP 1.5 MHz', 'LP 1.0 MHz', 'envelope -> RF'};
final = zeros(numel(plan), numel(starts));
for m = 1:numel(plan)
    tau = starts;
    for q = plan{m}
        for it = 1:400
            g = interp1(taus, dLdt(q,:), min(max(tau, taus(2)), taus(end-1)));
            tau = min(max(tau - g / curv(q), taus(1)), taus(end));   % stay on the table
        end
    end
    final(m, :) = tau;
end
ok = abs(final) < 2e-9;
for m = 1:numel(plan)
    k0 = find(starts == 0);  lo = k0;  hi = k0;
    while lo > 1 && ok(m, lo-1), lo = lo - 1; end
    while hi < numel(starts) && ok(m, hi+1), hi = hi + 1; end
    fprintf('%-15s converges to 0 from %3d of %d starts; contiguous basin [%4.0f, %4.0f] ns\n', ...
        lbl{m}, sum(ok(m,:)), numel(starts), starts(lo)*1e9, starts(hi)*1e9);
end

%% 4. Travel-time form of the criterion (transmission FWI / tomography)
% the starting model must predict the travel time within T/2: |dt| = L |dc| / c^2 < 1/(2 f)
fprintf('\nmax tolerable starting error |dc| (m/s) for c = 1500 m/s\n   f (MHz) | L = 50 mm | L = 100 mm | L = 200 mm\n');
for f = [0.5 1 2 5]
    fprintf('   %5.1f   | %8.1f  | %9.1f  | %9.1f\n', f, 1500^2./(2*f*1e6*[0.05 0.1 0.2]));
end

%% 5. Figures
figure('Position', [100 100 1050 420]);
subplot(1,2,1);
h = plot(taus*1e9, L(1,:), 'b', taus*1e9, L(2,:), 'r', taus*1e9, L(3,:), 'g');
set(h(3), 'Color', [0 0.55 0.4]); set(h, 'LineWidth', 1.4); grid on;
xlabel('trial delay \tau (ns), true delay 0'); ylabel('misfit / (2 x signal energy)');
xlim([-600 600]); legend(h, names(1:3), 'Location', 'southeast'); title('RF misfit: a minimum every period');
subplot(1,2,2);
h2 = plot(starts*1e9, final(1,:)*1e9, 'b.-', starts*1e9, final(3,:)*1e9, 'g.-', starts*1e9, final(5,:)*1e9 + 8, 'k.-');
set(h2(2), 'Color', [0 0.55 0.4]); grid on; xlim([-600 600]); xlabel('starting delay (ns)'); ylabel('converged delay (ns)');
legend(h2, {'RF', 'LP 1.5 MHz', 'envelope -> RF (offset +8 ns)'}, 'Location', 'northwest');
title('where gradient descent ends');

What to look for: RF minima at 0, ±194, ±388, ±583 ns and basin edges at ±97 ns; low-pass at 1.5 MHz keeps −29.2 dB, at 1.0 MHz −43.5 dB, with minima at ±327 and ±486 ns; RF converges from 19 of 121 starts (±90 ns), LP 1.5 MHz from 33 (±160 ns), LP 1.0 MHz from 49 (±240 ns), envelope and envelope → RF from all 121; curvature ratio 31.8 against theory 31.8; the \(\lvert\Delta c\rvert\) table (11.2 m/s at 0.5 MHz over 200 mm).

m14_complex_step_ad.mFinite-difference vs complex-step error vs h; dual-number forward mode; reverse mode by hand; two silent complex-step failures; Wirtinger gradient check and the conjugate-step bug · change x0, the test functions · runtime ≈ 1 s
%% m14_complex_step_ad.m  --  finite differences, complex step, dual numbers, reverse mode, Wirtinger
% Purpose : 1) relative error of forward/central differences and of the complex-step
%              derivative Im f(x + i h)/h versus h, for f(x) = e^x / sqrt(sin^3 x + cos^3 x)
%              at x0 = 1.5 (a standard test function in the complex-step literature);
%           2) forward-mode AD with dual numbers [value, derivative] built from anonymous
%              functions; 3) reverse mode by hand on y = ln(x1) + x1 x2 - sin(x2) at (2, 5);
%           4) two ways the complex step silently fails (abs and the ' operator);
%           5) Wirtinger gradient dL/dw* = -A^H (y - A w) for L = ||y - A w||^2 checked
%              against finite differences, and what happens if you step along its conjugate.
% Change  : x0, the step list, the test functions.
% Expect  : best forward difference 1e-8 to 1e-9 relative error near h = 1e-8; best central
%           about 1e-11 near h = 3e-6; complex step at machine precision for every
%           h <= 1e-8 (including 1e-20 and 1e-100); dual number exact; reverse-mode
%           gradient (5.5, 1.7163); Wirtinger check about 1e-9; the conjugate step diverges.
% Base MATLAB only; runs in MATLAB R2019b+ and GNU Octave 8. Runtime about 1 s.
rng(1);

%% 1. Finite differences vs complex step
f  = @(x) exp(x) ./ sqrt(sin(x).^3 + cos(x).^3);
x0 = 1.5;
df_exact = f(x0) * (1 - (3*sin(x0)^2*cos(x0) - 3*cos(x0)^2*sin(x0)) / (2*(sin(x0)^3 + cos(x0)^3)));
fprintf('f(1.5) = %.6f, exact f''(1.5) = %.12f\n', f(x0), df_exact);
hs = 10.^(-1:-0.25:-20);
f0v = f(x0 + 0*hs);                       % same vector code path as f(x0+hs): avoids a 1-ulp mismatch
efd = abs((f(x0+hs) - f0v) ./ hs - df_exact) / abs(df_exact);
ecd = abs((f(x0+hs) - f(x0-hs)) ./ (2*hs) - df_exact) / abs(df_exact);
ecs = abs(imag(f(x0 + 1i*hs)) ./ hs - df_exact) / abs(df_exact);
pfd = max(efd, 1e-17);  pcd = max(ecd, 1e-17);  pcs = max(ecs, 1e-17);       % floor zeros for the log plot
fprintf('     h     | forward diff | central diff | complex step\n');
for h = [1e-2 1e-4 1e-6 1e-8 1e-10 1e-12 1e-16 1e-20]
    k = find(abs(log10(hs) - log10(h)) < 1e-9);
    fprintf('  %7.0e  |   %8.1e   |   %8.1e   |   %8.1e\n', h, efd(k), ecd(k), ecs(k));
end
[m1, i1] = min(efd);  [m2, i2] = min(ecd);
fprintf('best forward h = %.0e (err %.1e; sqrt(eps) = %.1e); best central h = %.0e (err %.1e; eps^(1/3) = %.1e)\n', ...
    hs(i1), m1, sqrt(eps), hs(i2), m2, eps^(1/3));
fprintf('complex step with h = 1e-100: relative error %.1e\n', abs(imag(f(x0 + 1e-100i))/1e-100 - df_exact)/df_exact);

%% 2. Forward mode with dual numbers  a = [value, derivative]
dmul = @(a, b) [a(1)*b(1), a(1)*b(2) + a(2)*b(1)];
ddiv = @(a, b) [a(1)/b(1), (a(2)*b(1) - a(1)*b(2)) / b(1)^2];
dadd = @(a, b) a + b;
dexp = @(a) [exp(a(1)), exp(a(1))*a(2)];
dsin = @(a) [sin(a(1)), cos(a(1))*a(2)];
dcos = @(a) [cos(a(1)), -sin(a(1))*a(2)];
dsqrt = @(a) [sqrt(a(1)), a(2) / (2*sqrt(a(1)))];
dcube = @(a) dmul(dmul(a, a), a);
fdual = @(a) ddiv(dexp(a), dsqrt(dadd(dcube(dsin(a)), dcube(dcos(a)))));
r = fdual([x0, 1]);                                      % seed dx/dx = 1
fprintf('\ndual number: f = %.12f, f'' = %.15f, relative error %.1e\n', r(1), r(2), abs(r(2) - df_exact)/df_exact);

%% 3. Reverse mode by hand: y = ln(x1) + x1*x2 - sin(x2) at (2, 5)
x1 = 2; x2 = 5;
v1 = log(x1); v2 = x1*x2; v3 = sin(x2); v4 = v1 + v2; y = v4 - v3;       % forward sweep (the tape)
yb = 1;                                                                   % reverse sweep: adjoints
v4b = yb;  v3b = -yb;  v1b = v4b;  v2b = v4b;
x1b = v1b/x1 + v2b*x2;  x2b = v2b*x1 + v3b*cos(x2);
fprintf('reverse mode: y = %.4f, grad = (%.4f, %.4f); analytic (1/x1 + x2, x1 - cos x2) = (%.4f, %.4f)\n', ...
    y, x1b, x2b, 1/x1 + x2, x1 - cos(x2));
fprintf('  one reverse sweep gave both partials; forward mode needs one sweep per input (2 here)\n');

%% 4. Silent failures of the complex step
g1 = @(x) x .* abs(x - 1);                % abs is not analytic: abs(z) returns |z|, a real number
fprintf('\nx|x-1| at 1.5: exact 2.0, complex step %.4f, dual %.4f\n', imag(g1(1.5 + 1e-20i))/1e-20, ...
    subsref(dmul([1.5 1], [abs(0.5), sign(0.5)*1]), struct('type', '()', 'subs', {{2}})));
g2 = @(x) x' * x;                         % ' is the CONJUGATE transpose: x'*x = |x|^2 for complex x
fprintf('x''*x at 1.5: exact 3.0, complex step %.4f;   with .'' : %.4f\n', imag(g2(1.5 + 1e-20i))/1e-20, ...
    imag((1.5 + 1e-20i).' * (1.5 + 1e-20i))/1e-20);

%% 5. Wirtinger gradient for a real loss of complex parameters
A = (randn(8,4) + 1i*randn(8,4)) / sqrt(2);  y = (randn(8,1) + 1i*randn(8,1)) / sqrt(2);
L = @(w) real((y - A*w)' * (y - A*w));
w = (randn(4,1) + 1i*randn(4,1)) / sqrt(2);
g = -A' * (y - A*w);                      % dL/dw*  (the steepest-ascent direction is 2*g in R^8)
h = 1e-6;  gfd = zeros(4,1);
for k = 1:4
    e = zeros(4,1); e(k) = h;
    gfd(k) = (L(w+e) - L(w-e))/(2*h) + 1i*(L(w+1i*e) - L(w-1i*e))/(2*h);    % dL/dRe + i dL/dIm
end
fprintf('\nWirtinger check: max |(dL/dRe + i dL/dIm) - 2 dL/dw*| / max|.| = %.1e\n', max(abs(gfd - 2*g))/max(abs(gfd)));
mu = 0.5 / max(eig(A'*A));  wa = zeros(4,1);  wb = zeros(4,1);
for it = 1:200
    wa = wa - mu * (-A' * (y - A*wa));            % correct: step along -dL/dw*
    wb = wb - mu * conj(-A' * (y - A*wb));        % bug: step along -dL/dw = -conj(dL/dw*)
end
wls = A \ y;
fprintf('after 200 steps: L(correct) = %.4f (LS optimum %.4f); L(conjugated step) = %.4g\n', L(wa), L(wls), L(wb));

%% 6. Figure
figure('Position', [100 100 640 440]);
loglog(hs, pfd, 'b.-', hs, pcd, 'r.-', hs, pcs, 'k.-'); hold on;
loglog([1e-20 1e-1], [1 1]*eps, 'k:');
set(gca, 'XDir', 'reverse'); grid on; ylim([1e-17 10]);
xlabel('step h'); ylabel('relative error of f''(1.5)');
legend('forward difference', 'central difference', 'complex step', 'machine epsilon', 'Location', 'northwest');
title('truncation error falls with h, round-off grows as eps/h; the complex step has no subtraction');

What to look for: best forward difference at \(h = 10^{-8}\) (error \(2.6 \times 10^{-9}\) here; typically ~\(10^{-8}\)), best central at \(h = 3 \times 10^{-6}\) (\(6.4 \times 10^{-12}\)), complex step 0 to \(2.2 \times 10^{-16}\) for every \(h \le 10^{-8}\) including \(10^{-100}\); dual number exact; reverse-mode gradient (5.5000, 1.7163); complex step gives 0.5 instead of 2 for \(x\lvert x - 1\rvert\) and 0 instead of 3 for x'*x; Wirtinger check \(2.2 \times 10^{-10}\); the conjugated step reaches \(\mathcal{L} = 2.4 \times 10^{62}\).

m14_autofocus_sound_speed.mPlane-wave IQ channel data at c = 1480 m/s; four focus metrics vs assumed ĉ with exact chain-rule derivatives; projected gradient ascent from five starts; 1 vs 5 angles · change c_true, z, angle_sets · runtime ≈ 15 s
%% m14_autofocus_sound_speed.m  --  sound speed by gradient ascent on a focus metric
% Purpose : simulate plane-wave IQ channel data (64 elements, 5 MHz) from a point
%           target in speckle in a medium with c_true = 1480 m/s, beamform at an
%           assumed speed ch, and estimate c by gradient ascent on four metrics:
%             energy : sum of |b|^2 over an ROI fixed in two-way time (coherently compounded)
%             sharp  : P*sum(I.^2)/sum(I)^2 over the same ROI
%             envz   : |b|^2 at a pixel fixed in depth (x = 0, z = 30 mm)
%             rfz    : real part of b (the RF value) at that fixed pixel
%           The derivative dM/dch is computed exactly by the chain rule (forward mode):
%           d/dch [IQ(tau) e^{j w0 tau}] = (IQ'(tau) + j w0 IQ(tau)) e^{j w0 tau} dtau/dch.
% Change  : c_true, z, angles_deg (try a single 0 deg plane wave), starts, the scene.
% Expect  : 5 angles: energy peaks at 1484-1486 m/s (bias about +5 m/s) and every start
%           in 1380-1720 converges there; rfz oscillates with period ch^2/(2 z f0)
%           (7.3 m/s here) and every start stops on its nearest local maximum (cycle
%           skipping). 1 angle: energy is nearly flat and peaks far from c_true.
% Base MATLAB only; runs in MATLAB R2019b+ and GNU Octave 8. Runtime about 10 s.
rng(1);

%% 1. Geometry, pulse and scatterers
c_true = 1480;            % true sound speed (m/s)
z      = 30e-3;           % target depth (m)
f0 = 5e6; w0 = 2*pi*f0;   % centre frequency (Hz)
sig = 0.125e-6;           % Gaussian envelope std (s): -6 dB bandwidth 3 MHz (60 %)
fs = 40e6;                % IQ sampling rate (Hz)
N = 64; pitch = 0.3e-3;   % elements, pitch (m): aperture 19.2 mm, F/1.56 at 30 mm
xe = ((0:N-1) - (N-1)/2) * pitch;                   % 1 x N element positions (m)
K = 500;                                            % speckle scatterers
sx = [0; (rand(K,1) - 0.5) * 8e-3];                 % lateral (m), first one is the point
sz = [z; z + (rand(K,1) - 0.5) * 3e-3];             % depth (m)
amp = [3; 0.25 * (randn(K,1) + 1j*randn(K,1)) / sqrt(2)];
angle_sets = {0, (-8:4:8)};                         % plane-wave angles (deg)

for set_id = 1:2
th = angle_sets{set_id} * pi/180;  A = numel(th);

%% 2. IQ channel data: IQ(t) = sum_k a_k g(t - t_k) e^{-j w0 t_k}
tk = zeros(K+1, N, A);
for a = 1:A
    tk(:,:,a) = (sz*cos(th(a)) + sx*sin(th(a)))/c_true + sqrt((sx - xe).^2 + sz.^2)/c_true;
end
t0 = min(tk(:)) - 1.5e-6;  T = ceil((max(tk(:)) + 1.5e-6 - t0) * fs);
tg = t0 + (0:T-1).' / fs;                            % T x 1 fast time (s)
IQ = zeros(T, N, A);
for a = 1:A
    for e = 1:N
        tt = tk(:, e, a).';                          % 1 x (K+1)
        IQ(:, e, a) = exp(-(tg - tt).^2 / (2*sig^2)) * (amp .* exp(-1j*w0*tt.'));
    end
end

%% 3. Beamformer with exact derivative (anonymous functions only)
% ROI in time coordinates: pixel (x, t), depth at assumed speed = ch*t/2
nx = 21; nt = 25;
[PX, PT] = meshgrid(((0:nx-1) - (nx-1)/2) * 0.15e-3, 2*z/c_true + ((0:nt-1) - (nt-1)/2) * 50e-9);
Px = PX(:); Pt = PT(:); P = numel(Px);
U   = @(tau) (tau - t0) * fs;
I0  = @(tau) min(max(floor(U(tau)), 0), T-2);
% core: q0 = IQ at the sample before tau, dq = next minus q0, fr = fraction, E = e^{j w0 tau}
core = @(q0, dq, fr, E, dt) [sum((q0 + dq.*fr) .* E, 2), sum((dq*fs + 1j*w0*(q0 + dq.*fr)) .* E .* dt, 2)];
bfi  = @(k, fr, tau, dt) core(IQ(k), IQ(k+1) - IQ(k), fr, exp(1j*w0*tau), dt);   % k = linear index
bfa  = @(tau, dt, a) bfi(I0(tau) + 1 + (0:N-1)*T + (a-1)*T*N, U(tau) - I0(tau), tau, dt);
% time-ROI delays and d tau / d ch
tauT  = @(ch, a) Pt/2*cos(th(a)) + Px*sin(th(a))/ch + sqrt((Px - xe).^2/ch^2 + (Pt/2).^2);
dtauT = @(ch, a) -Px*sin(th(a))/ch^2 - ((Px - xe).^2/ch^3) ./ sqrt((Px - xe).^2/ch^2 + (Pt/2).^2);
% fixed-depth pixel (x = 0, z)
tauZ  = @(ch, a) (z*cos(th(a)) + sqrt(xe.^2 + z^2)) / ch;
BT = @(ch) cell2mat(arrayfun(@(a) bfa(tauT(ch,a), dtauT(ch,a), a), 1:A, 'UniformOutput', false));
BZ = @(ch) cell2mat(arrayfun(@(a) bfa(tauZ(ch,a), -tauZ(ch,a)/ch, a), 1:A, 'UniformOutput', false));
bsum = @(Bm) [sum(Bm(:,1:2:end), 2), sum(Bm(:,2:2:end), 2)];       % compound angles: [b, db]
% metrics: each returns [M, dM/dch]
mE = @(bd) [sum(abs(bd(:,1)).^2), sum(2*real(conj(bd(:,1)).*bd(:,2)))];
mS = @(bd) P * [sum(abs(bd(:,1)).^4) / sum(abs(bd(:,1)).^2)^2, ...
     (sum(4*abs(bd(:,1)).^2 .* real(conj(bd(:,1)).*bd(:,2))) * sum(abs(bd(:,1)).^2) ...
      - 2*sum(abs(bd(:,1)).^4) * sum(2*real(conj(bd(:,1)).*bd(:,2)))) / sum(abs(bd(:,1)).^2)^3];
metric = {@(ch) mE(bsum(BT(ch))), @(ch) mS(bsum(BT(ch))), ...
          @(ch) mE(bsum(BZ(ch))), @(ch) real(bsum(BZ(ch)))};
names = {'energy', 'sharp', 'envz', 'rfz'};
S0 = [40 40 8 1.5];       % initial trial step of the line search (m/s)
cmin = 1350; cmax = 1750; % box constraint: every step is projected onto [cmin, cmax]

%% 4. Derivative check at 1540 m/s (exact chain rule vs central difference)
if set_id == 2
    for m = 1:4
        r = metric{m}(1540);  h = 1e-3;
        fd = (metric{m}(1540+h) - metric{m}(1540-h)) / (2*h);
        fprintf('dM/dc check %-6s  chain rule / central difference = %.6f\n', names{m}, r(2)/fd(1));
    end
end

%% 5. Sweep and gradient ascent from several starts
fprintf('\n%d plane wave(s): c_true = %d m/s, z = %d mm\n', A, c_true, round(z*1e3));
fprintf('metric | argmax (m/s) | gradient ascent: start -> end (iterations)\n');
starts = [1380 1440 1540 1620 1720];
cs_roi = 1350:5:1750;  cs_pix = 1350:1:1750;
curves = cell(1,4);  ends = zeros(4, numel(starts));
for m = 1:4
    if m <= 2, cs = cs_roi; else, cs = cs_pix; end
    M = zeros(size(cs));  for i = 1:numel(cs), r = metric{m}(cs(i)); M(i) = r(1); end
    curves{m} = [cs; M];  [~, im] = max(M);
    s_out = '';
    for j = 1:numel(starts)
        c = starts(j);  r = metric{m}(c);  n = 0;
        while n < 60
            g = r(2);  if g == 0, break; end
            s = S0(m);  ok = false;
            while s > 0.05
                cn = min(max(c + sign(g)*s, cmin), cmax);  rn = metric{m}(cn);   % projected step
                if cn ~= c && rn(1) >= r(1) + 1e-4*abs(cn-c)*abs(g), c = cn; r = rn; ok = true; break; end
                s = s/2;
            end
            if ~ok, break; end
            n = n + 1;
        end
        ends(m, j) = c;
        s_out = [s_out sprintf('%d->%.1f(%d)  ', starts(j), c, n)];
    end
    fprintf('%-6s | %7.1f      | %s\n', names{m}, cs(im), s_out);
end
fprintf('RF-at-fixed-depth period predicted ch^2/(2 z f0) = %.1f m/s at ch = c_true\n', c_true^2/(2*z*f0));
if set_id == 1, curves1 = curves; ends1 = ends; else, curves5 = curves; ends5 = ends; end
end

%% 6. Figures
figure('Position', [80 80 1100 460]);
cols = {[0 0.3 0.8], [0.8 0.2 0.5], [0.85 0.55 0], [0 0.55 0.4]};
for set_id = 1:2
    subplot(1,2,set_id);
    if set_id == 1, cv = curves1; en = ends1; ttl = '1 plane wave (0 deg)'; else, cv = curves5; en = ends5; ttl = '5 plane waves (-8:4:8 deg)'; end
    h = zeros(1,4);
    for m = 1:4
        y = cv{m}(2,:);  y = y / max(abs(y));
        h(m) = plot(cv{m}(1,:), y, 'Color', cols{m}, 'LineWidth', 1.3); hold on;
        yi = interp1(cv{m}(1,:), y, en(m,:));
        plot(en(m,:), yi, 'o', 'Color', cols{m}, 'MarkerSize', 7, 'LineWidth', 1.5);
    end
    plot([c_true c_true], [-1 1.05], 'k--');
    xlim([1350 1750]); ylim([-1 1.05]); grid on;
    xlabel('assumed sound speed c_h (m/s)'); ylabel('metric / max |metric|');
    title([ttl ': circles = gradient-ascent end points']);
    legend(h, {'energy (time ROI)', 'sharpness (time ROI)', '|b|^2 at fixed depth', 'Re b at fixed depth'}, 'Location', 'southwest');
end

What to look for: derivative check ratios 1.000000; with 5 angles the compounded energy peaks at 1485 m/s and all five starts end at 1484.1 m/s, sharpness at 1482.5 m/s except the 1720 start; with 1 angle the energy peaks at 1550 m/s (wrong) while sharpness still works for this point-in-speckle scene; RF at fixed depth stops near every start (1380.7, 1445.9, 1541.5, …), period 7.3 m/s; envelope at fixed depth only helps within about ±20 m/s.

14.13Self-check

Q1κ = 400, tolerance 10⁻⁶. How many iterations for GD with the optimal step, and for tuned heavy ball (rate only)?

GD: \(\ln(10^6)/\ln(401/399)\) = 2763. Heavy ball: \(\sqrt\kappa\) = 20, \(\ln(10^6)/\ln(21/19)\) = 138 (expect somewhat more from the double-root transient). Ratio \(\approx\sqrt\kappa\) = 20.

Q2You run GD with α = 2.05/L. What happens to the stiff mode after 50 steps?

Its factor is \(1 - 2.05 = -1.05\): it alternates sign and grows by \(1.05^{50}\) = 11.5. Any \(\alpha > 2/L\) diverges, however small the excess.

Q3At 3 MHz, what is the RF delay basin, and how far apart are the ripples of an RF-at-fixed-depth autofocus metric at 30 mm (ĉ = 1540 m/s)?

Basin \(\approx \pm T_0/2\) = ±167 ns. Ripple period \(\hat c^2/(2zf_0) = 1540^2/(2 \times 0.03 \times 3 \times 10^6)\) = 13.2 m/s. Lower frequency widens both, which is the multiscale idea.

Q4A transmission path of 200 mm, c = 1500 m/s, f = 0.5 MHz. What starting-model error in c avoids cycle skipping?

\(\lambda\) = 3 mm, \(L/\lambda\) = 66.7, so \(\lvert\Delta c\rvert/c < 1/(2 \times 66.7)\) = 0.75 %: \(\lvert\Delta c\rvert\) < 11.25 m/s. Equivalently \(\lvert\Delta t\rvert = L\Delta c/c^2 < T/2\) = 1 µs.

Q5The complex step applied to g(x) = x·|x − 1| at x = 1.5 returns what, and what is the true derivative?

abs(z − 1) returns the real modulus, so \(\mathrm{Im}\,g(x + ih)/h = \lvert x - 1\rvert\) = 0.5. The true derivative is \(2x - 1\) = 2. A dual number (or AD) with abs overloaded as \(\mathrm{sign}(a)\,\dot a\) returns 2.

Q6L(z) = |z − a|². Which step μ in z ← z − μ ∂L/∂z* lands on a in one step, and what does the conjugated update do?

\(\partial\mathcal{L}/\partial z^* = z - a\), so \(\mu\) = 1 lands exactly on \(a\) (in real coordinates the gradient is \(2(z - a)\) and the Newton step is 1/2 of it). The conjugated update \(z \leftarrow z - (z - a)^*\) moves the imaginary part the wrong way: from \(z = a + i\) it goes to \(a + 2i\).

Q7Why does the total energy of a single plane-wave image fail as an autofocus metric while the compounded energy over five angles works?

Receive DAS over a region nearly preserves the channel energy whatever the focusing law, so \(\sum\lvert b\rvert^2\) is almost flat in \(\hat c\) (the demo's 1-angle curve peaks 60–100 m/s high). Summing angles coherently before squaring adds cross terms that are maximal only when the angle images align, which happens at the right \(\hat c\): the 5-angle energy peaks within 2–10 m/s of the truth.

14.14Figures from the literature

Published figures with real data or benchmark runs that show the claims of this module outside a toy model. Links only; no figures are reproduced.

Differentiable-beamforming autofocus in vivo. Fig. 5 shows CMPE autofocusing on rat liver (B-modes before and after, phase-error maps, channel data and coherence factor), with the mean common-midpoint phase error falling from 55.8 to 42.1 mrad; Fig. 7 compares estimated with calibrated sound speeds in simulation, bilayer and commercial phantoms. Look for the residual bias in Fig. 7: it is the "integrated metrics are biased" pitfall of 14.5 on real data.

W. Simson, L. Zhuang, B. N. Frey, S. J. Sanabria, J. J. Dahl, D. Hyun, "Ultrasound autofocusing: common midpoint phase error optimization via differentiable beamforming," arXiv:2410.03008 (2024, revised 2025; published in IEEE Trans. Med. Imaging, 2025, doi:10.1109/TMI.2025.3607875), Figs. 5 and 7 (arXiv numbering). doi:10.48550/arXiv.2410.03008

The complex step against finite differences. Fig. 1 plots the relative derivative error versus step size for forward, central and complex-step differences on \(f(x) = e^x/\sqrt{\sin^3x + \cos^3x}\) at \(x\) = 1.5, the default of Demo 14.5. Compare the V-shaped finite-difference curves and the flat complex-step floor with the demo.

J. R. R. A. Martins, P. Sturdza, J. J. Alonso, "The complex-step derivative approximation," ACM Trans. Math. Softw. 29(3):245–262, 2003, Fig. 1. doi:10.1145/838250.838251

Forward and reverse mode on the same example. Fig. 4 is the computational graph of \(y = \ln x_1 + x_1x_2 - \sin x_2\); Tables 2 and 3 evaluate the forward tangent and reverse adjoint sweeps at (2, 5). Figure 14.6 and the table in 14.6 reproduce the same numbers (5.5, 1.7163).

A. G. Baydin, B. A. Pearlmutter, A. A. Radul, J. M. Siskind, "Automatic differentiation in machine learning: a survey," J. Mach. Learn. Res. 18:1–43, 2018, Fig. 4 and Tables 2–3. jmlr.org/papers/v18/17-468

Adam on benchmark training curves. Fig. 3 shows the training cost of a convolutional network on CIFAR-10 for Adam against AdaGrad and SGD with Nesterov momentum (with and without dropout); Fig. 1 does the same for logistic regression on MNIST and IMDB. Note that the advantage is in large stochastic problems, the regime where 14.3 recommends Adam, not in small smooth least-squares fits.

D. P. Kingma, J. Ba, "Adam: a method for stochastic optimization," ICLR 2015, arXiv:1412.6980, Figs. 1 and 3. doi:10.48550/arXiv.1412.6980

14.15Go deeper

  • J. Nocedal & S. J. Wright, Numerical Optimization, 2nd ed., Springer, 2006. Line searches (ch. 3), Newton and quasi-Newton, Gauss–Newton and Levenberg–Marquardt (ch. 10).
  • S. Boyd & L. Vandenberghe, Convex Optimization, Cambridge University Press, 2004. Convexity, gradient and Newton methods with convergence proofs.
  • B. T. Polyak, "Some methods of speeding up the convergence of iteration methods," USSR Comput. Math. Math. Phys., 1964 (heavy ball); Y. Nesterov, Soviet Math. Dokl., 1983 (accelerated gradient).
  • D. P. Kingma & J. Ba, "Adam: A method for stochastic optimization," ICLR, 2015.
  • A. G. Baydin, B. A. Pearlmutter, A. A. Radul & J. M. Siskind, "Automatic differentiation in machine learning: a survey," JMLR, 2018.
  • A. Griewank & A. Walther, Evaluating Derivatives, 2nd ed., SIAM, 2008. Reverse mode, its cost and checkpointing.
  • W. Squire & G. Trapp, "Using complex variables to estimate derivatives of real functions," SIAM Review, 1998; J. R. R. A. Martins, P. Sturdza & J. J. Alonso, "The complex-step derivative approximation," ACM TOMS, 2003.
  • D. H. Brandwood, "A complex gradient operator and its application in adaptive array theory," IEE Proc., 1983. The basis of \(\partial/\partial z^*\) gradients.
  • C. Bunks, F. M. Saleck, S. Zaleski & G. Chavent, "Multiscale seismic waveform inversion," Geophysics, 1995; J. Virieux & S. Operto, "An overview of full-waveform inversion in exploration geophysics," Geophysics, 2009. Cycle skipping and multiscale strategies.
  • R. A. Muller & A. Buffington, "Real-time correction of atmospherically degraded telescope images through image sharpening," JOSA, 1974.
  • M. E. Anderson & G. E. Trahey, "The direct estimation of sound speed using pulse–echo ultrasound," JASA, 1998.
  • W. Simson, L. Zhuang, S. J. Sanabria, N. Antil, J. J. Dahl & D. Hyun, "Differentiable beamforming for ultrasound autofocusing," in MICCAI 2023, Lecture Notes in Computer Science 14229, Springer, 2023 (doi:10.1007/978-3-031-43999-5_41; code: github.com/waltsims/dbua). Gradient-based sound-speed maps through a differentiable beamformer.