Expand description
Zernike ordering conventions: normalization flags and the three single-index schemes.
The polynomials themselves are SpecialMath::zernike
and zernike_r. What lives here is everything
around them, which in practice is where the errors are.
A Zernike mode is named by two integers: the radial degree n >= 0 and the
azimuthal frequency m, with |m| <= n and n - |m| even. Every application
flattens that pair into a single running index, and there are three incompatible
ways to do it, all in current use:
| Scheme | First index | Ordering within a degree | Found in |
|---|---|---|---|
| ANSI Z80.28 / OSA | 0 | m ascending from -n to +n | ophthalmology, most Python tooling |
| Noll | 1 | |m| ascending, sign alternating by n mod 4 | astronomy, Zemax “Standard” coefficients |
| Fringe (Air Force / Arizona) | 1 | by spatial frequency n + |m|, cosine before sine | interferometry, Zemax “Fringe” coefficients |
Handing a Noll-indexed coefficient vector to ANSI-indexed code produces a plausible-looking wavefront that is wrong from the second term on, and nothing in the numbers announces it. Converting explicitly at the boundary is the fix, which is why these are here rather than left to the caller.
Normalization is the second, independent axis. ZERNIKE_UNIT_PEAK leaves the
radial polynomial alone, so every mode has R_n^m(1) = 1 and coefficients read as
peak wavefront amplitude. ZERNIKE_ORTHONORMAL applies
$N_n^m = \sqrt{2(n+1)/(1 + \delta_{m,0})}$, making the modes orthonormal on the
unit disc under the $1/\pi$-weighted inner product, so a coefficient is an RMS
contribution and the total wavefront RMS is the root-sum-square of them. Both the
ANSI and Noll standards specify the orthonormal form, while unit-peak is what most
hand-rolled shader and interferometer code produces. There is no safe default, so
the choice is a required const generic rather than a flag with an opinion.
All conversions here are const fn over plain integers. They are configuration,
evaluated once per mode and not per sample, and never belong in a vector loop.
Constants§
- ZERNIKE_
ORTHONORMAL - Scale each mode by
$\sqrt{2(n+1)/(1 + \delta_{m,0})}$, the ANSI Z80.28 and Noll normalization. - ZERNIKE_
UNIT_ PEAK - Leave the radial polynomial unnormalized:
$R_n^m(1) = 1$for every mode.
Functions§
- ansi_
index - The ANSI Z80.28 / OSA single index of mode
(n, m):$j = (n(n+2) + m)/2$, from 0. - ansi_
to_ nm - The mode
(n, m)carrying ANSI indexj. Inverse ofansi_index. - count_
up_ to_ degree - The number of Zernike modes with radial degree at most
n, i.e.(n+1)(n+2)/2. - fringe_
index - The Fringe (Air Force / Arizona) single index of mode
(n, m), from 1. - fringe_
to_ ansi - The ANSI index of the mode carrying Fringe index
j. - fringe_
to_ nm - The mode
(n, m)carrying Fringe indexj. Inverse offringe_index. - is_
valid - Whether
(n, m)names a real Zernike mode:$|m| \le n$with$n - |m|$even. - noll_
index - The Noll single index of mode
(n, m), from 1. - noll_
to_ ansi - The ANSI index of the mode carrying Noll index
j. - noll_
to_ nm - The mode
(n, m)carrying Noll indexj. Inverse ofnoll_index.