diff --git a/README.md b/README.md
index 3bc503a..6e5db84 100644
--- a/README.md
+++ b/README.md
@@ -9,7 +9,7 @@ This package can be added from the Julia REPL by:
using Pkg
Pkg.add(url="https://github.com/Sagnac/Zernike.jl")
```
-or entering the package mode by pressing `]` and entering
+or entering the package mode by pressing `]` and entering:
```
add https://github.com/Sagnac/Zernike.jl
```
@@ -20,7 +20,7 @@ The package provides 3 main functions for modelling Zernike polynomials and wave
* `W(ρ, θ, OPD, n_max)`: Fits wavefront errors up to radial order `n_max` given an input set of data over the pupil, returns the Zernike expansion coefficients & various metrics, and plots the modelled wavefront error using Makie;
-* `S(ε, v)`: Aperture scaling function which takes a scaling factor and a vector of Zernike expansion coefficients and returns the new set of expansion coefficients over the smaller pupil; the clipped wavefront error is also plotted using Makie.
+* `P(v, ε, δ, ϕ, ω)`: Aperture transform function which takes a vector of Zernike expansion coefficients and a set of transformation factors and returns a new set of expansion coefficients over the transformed pupil; the wavefront error over the new pupil is also plotted using Makie.
----
@@ -38,7 +38,7 @@ Returns three values contained within a Zernike.Output type, with fields:
2. `coeffs`: vector of radial polynomial coefficients;
3. `latex`: LaTeX string of the Zernike polynomial.
-The coefficients belong to terms with exponent `n - 2(i - 1)` where `i` is the vector's index.
+The coefficients belong to terms with exponent `n − 2(i − 1)` where `i` is the vector's index.
The radial polynomial coefficients are computed using a fast and accurate algorithm suitable for high orders; it is based on a recursive relation presented by [Honarvar & Paramesran (2013)](https://doi.org/10.1364/OL.38.002487).
@@ -46,11 +46,11 @@ The radial polynomial coefficients are computed using a fast and accurate algori
## `W(ρ, θ, OPD, n_max)`
-Estimates wavefront error by expressing optical aberrations as a linear combination of weighted Zernike polynomials using a linear least squares method. This representation as an expanded series is approximate, especially if the phase field is not sufficiently sampled.
+Estimates wavefront error by expressing optical aberrations as a linear combination of weighted Zernike polynomials using a linear least squares method. The accuracy of this type of wavefront reconstruction represented as an expanded series depends upon a sufficiently sampled phase field and a suitable choice of the fitting order n_max.
`ρ`, `θ`, and `OPD` must be vectors of equal length; at each specific index the values are elements of an ordered triple over the exit pupil.
-* `ρ`: normalized radial exit pupil variable `{0 ≤ ρ ≤ 1}`;
+* `ρ`: normalized radial exit pupil position variable `{0 ≤ ρ ≤ 1}`;
* `θ`: angular exit pupil variable in radians `(mod 2π)`, defined positive counter-clockwise from the horizontal x-axis;
* `OPD`: measured optical path difference in waves;
* `n_max`: maximum radial degree to fit to.
@@ -63,27 +63,42 @@ The phase profile data can also be input as a 3 column matrix.
Returns four values contained within a WavefrontOutput type, with fields:
1. `a`: vector of named tuples containing the Zernike polynomial indices and the corresponding expansion coefficients rounded according to `precision`;
-2. `v`: full vector of Zernike expansion coefficients;
-3. `metrics`: 3-tuple with the peak-to-valley error, RMS wavefront error, and Strehl ratio;
+2. `v`: full vector of Zernike wavefront error expansion coefficients;
+3. `metrics`: named 3-tuple with the peak-to-valley error, RMS wavefront error, and Strehl ratio;
4. `fig`: the plotted Makie figure.
----
-## `S(ε, v)`
+## `P(v, ε, δ, ϕ, ω)`
-Pupil scaling function which computes a new set of Zernike expansion coefficients under aperture down-scaling and plots the result.
+Pupil transform function; computes a new set of Zernike wavefront error expansion coefficients under a given set of transformation factors and plots the result.
+
+Available transformations are scaling, translation, & rotation for circular and elliptical exit pupils. These are essentially coordinate transformations in the pupil plane over the wavefront map.
-* `ε::Float64`: scaling factor `{0 ≤ ε ≤ 1}`;
* `v::Vector{Float64}`: vector of full Zernike expansion coefficients ordered in accordance with the ANSI / OSA single index standard. This is the `v` vector returned by the wavefront error fitting function `W(ρ, θ, OPD, n_max)`.
+* `ε::Float64`: scaling factor `{0 ≤ ε ≤ 1}`;
+* `δ::ComplexF64`: translational complex coordinates (displacement of the pupil center in the complex plane);
+* `ϕ::Float64`: rotation of the pupil in radians `(mod 2π)`, defined positive counter-clockwise from the horizontal x-axis;
+* `ω::Tuple{Float64,Float64}`: elliptical pupil transform parameters; 2-tuple where `ω[1]` is the ratio of the minor radius to the major radius of the ellipse and `ω[2]` is the angle defined positive counter-clockwise from the horizontal coordinate axis of the exit pupil to the minor axis of the ellipse.
-`ε` = `r₂/r₁` where `r₂` is the new radius, `r₁` the original
+The order the transformations are applied is:
+scaling --> translation --> rotation --> elliptical transform.
+
+The translation, rotation, and elliptical arguments are optional.
+
+`ε` = `r₂/r₁` where `r₂` is the new smaller radius, `r₁` the original
In particular the radial variable corresponding to the rescaled exit pupil is normalized such that:
`ρ` = `r/r₂`; `{0 ≤ ρ ≤ 1}`
`r`: radial pupil position, `r₂`: max. radius
-`W₂(ρ₂)` = `W₁(ερ₂)`
+`ΔW₂(ρ₂, θ)` = `ΔW₁(ερ₂, θ)`
+
+For translation the shift must be within the bounds of the scaling applied such that:
+`0.0 ≤ ε + |δ| ≤ 1.0`.
-The rescaled expansion coefficients are computed using a fast and accurate algorithm suitable for high orders; it is based on a formula presented by [Janssen & Dirksen (2007)](https://doi.org/10.2971/jeos.2007.07012).
+For elliptical pupils (usually the result of measuring the wavefront off-axis), the major radius is defined such that it equals the radius of the circle and so `ω[1]` is the fraction of the circular pupil covered by the minor radius (this is approximated well by a cosine projection factor for angles up to 40 degrees); `ω[2]` is then the direction of the stretching applied under transformation in converting the ellipse to a circle before fitting the expansion coefficients.
+
+The transformed expansion coefficients are computed using a fast and accurate algorithm suitable for high orders; it is based on a formulation presented by [Lundström & Unsbo (2007)](https://doi.org/10.1364/JOSAA.24.000569).
----
@@ -91,13 +106,13 @@ The rescaled expansion coefficients are computed using a fast and accurate algor
There are 2 options you can vary using keyword arguments. All 3 main functions support:
-* `scale`: `{1 ≤ scale ≤ 100}`: multiplicative factor determining the size of the plotted matrix; the total number of elements is capped at 1 million.
+* `scale`: `{1 ≤ scale ≤ 100}`: multiplicative factor determining the size of the plotted matrix; the total number of elements is capped at 1 million which should avoid aliasing up to ~317 radially and ~499 azimuthally.
Default: `100` (for `Z`, proportionally scaled according to the number of polynomials for the wavefront errors).
-In creating the plot matrix the step size / length of the variable ranges is automatically chosen such that aliasing is avoided up to order ~317 radially and ~499 azimuthally. The `scale` parameter controls how fine the granularity is subsequently at the expense of performance.
+In creating the plot matrix the step size / length of the variable ranges is automatically chosen such that aliasing is avoided for reasonable orders. The `scale` parameter controls how fine the granularity is subsequently at the expense of performance.
-Additionally, the wavefront error functions `W(ρ, θ, OPD, n_max)` and `S(ε, v)` support:
+Additionally, the wavefront error functions `W(ρ, θ, OPD, n_max)` and `P(v, ε, δ, ϕ, ω)` support:
* `precision`: number of digits to use after the decimal point in computing the expansion coefficients. Results will be rounded according to this precision and any polynomials with zero-valued coefficients will be ignored when pulling in the Zernike functions while constructing the composite wavefront error; this means lower precision values yield faster results.
@@ -114,7 +129,18 @@ Z40 = Z(0, 4, Model())
Z40(0.7, π/4)
```
-For the wavefront errors this is equivalent to `ΔW(ρ, θ)` = `∑aᵢZᵢ(ρ, θ)` where `aᵢ` and `Zᵢ` were determined from the fitting process according to `precision`.
+For wavefront reconstruction this is equivalent to `ΔW(ρ, θ)` = `∑aᵢZᵢ(ρ, θ)` where `aᵢ` and `Zᵢ` were determined from the fitting process according to `precision`.
+
+## Single-Index Ordering Schemes
+
+This package uses the the ANSI Z80.28-2004 standard ordering scheme where applicable, but provides several functions for converting from two other ordering methods, namely `Noll` and `Fringe`. The following functions are available:
+
+* `noll_to_j(noll::Int)`: converts Noll indices to ANSI standard indices;
+* `standardize!(noll::Vector)`: re-orders a Noll specified Zernike expansion coefficient vector according to the ANSI standard; this requires a full ordered vector up to n_max;
+* `fringe_to_j(fringe::Int)`: converts Fringe indices to ANSI standard indices; only indices 1:37 are valid;
+* `standardize(fringe::Vector)`: formats a Fringe specified Zernike expansion coefficient vector according to the ANSI standard.
+
+The last function expects unnormalized coefficients; the input coefficients will be re-ordered and normalized in line with the orthonormal standard. As Fringe is a 37 polynomial subset of the full set of Zernike polynomials any coefficients in the standard order missing a counterpart in the input vector will be set to zero.
## Additional Notes
@@ -128,4 +154,4 @@ For the wavefront errors this is equivalent to `ΔW(ρ, θ)` = `∑aᵢZᵢ(ρ,
```
Zernike.Wf(ρ, θ, OPD, n_max)[1]
```
-Similarly you can do this for the radial polynomial coefficients and the NA scaled wavefront error expansion coefficients by importing the functions `Φ` and `Π`, respectively.
+Similarly you can do this for the radial polynomial coefficients and the NA transformed wavefront error expansion coefficients by importing the functions `Φ` and `S`, respectively.
diff --git a/src/Docstrings.jl b/src/Docstrings.jl
index 64b783e..5942580 100644
--- a/src/Docstrings.jl
+++ b/src/Docstrings.jl
@@ -2,7 +2,11 @@
Z(m, n)
Z(j)
-Plots a Zernike polynomial of azimuthal order `m` and radial degree `n`. The single index `j` begins at zero and follows the ANSI / OSA standard. Returns three values contained within a Zernike.Output type, with fields:
+Plot a Zernike polynomial of azimuthal order `m` and radial degree `n`.
+
+The single index `j` begins at zero and follows the ANSI Z80.28-2004 / ISO 24157:2008 / Optica (OSA) standard.
+
+Returns three values contained within a Zernike.Output type, with fields:
1. `fig`: the Makie figure;
2. `coeffs`: vector of radial polynomial coefficients;
@@ -14,13 +18,15 @@ The coefficients belong to terms with exponent `n - 2(i - 1)` where `i` is the v
The radial polynomial coefficients are computed using a fast and accurate algorithm suitable for high orders; it is based on a recursive relation presented by Honarvar & Paramesran (2013) doi:10.1364/OL.38.002487.
+See also [`W`](@ref), [`P`](@ref).
+
----
# Positional argument options:
Z(m, n, Model())
-Returns the Zernike polynomial function `Z(ρ, θ)` corresponding to indices `m` and `n`.
+Return the Zernike polynomial function `Z(ρ, θ)` corresponding to indices `m` and `n`.
# Keyword argument options:
@@ -34,26 +40,34 @@ Z
W(ρ, θ, OPD, n_max)
W(data::Matrix, n_max; options...)
-Estimates wavefront error by expressing optical aberrations as a linear combination of weighted Zernike polynomials using a linear least squares method. This representation as an expanded series is approximate, especially if the phase field is not sufficiently sampled.
+Fit wavefront errors up to order n_max.
+
+Estimates wavefront error by expressing optical aberrations as a linear combination of weighted Zernike polynomials using a linear least squares method. The accuracy of this type of wavefront reconstruction represented as an expanded series depends upon a sufficiently sampled phase field and a suitable choice of the fitting order n_max.
+
+# Main arguments
`ρ`, `θ`, and `OPD` must be vectors of equal length; at each specific index the values are elements of an ordered triple over the exit pupil.
-* `ρ`: normalized radial exit pupil variable `{0 ≤ ρ ≤ 1}`;
+* `ρ`: normalized radial exit pupil position variable `{0 ≤ ρ ≤ 1}`;
* `θ`: angular exit pupil variable in radians `(mod 2π)`, defined positive counter-clockwise from the horizontal x-axis;
* `OPD`: measured optical path difference in waves;
* `n_max`: maximum radial degree to fit to.
The phase profile data can also be input as a 3 column matrix.
+# Return values
+
Returns four values contained within a WavefrontOutput type, with fields:
1. `a`: vector of named tuples containing the Zernike polynomial indices and the corresponding expansion coefficients rounded according to `precision`;
-2. `v`: full vector of Zernike expansion coefficients;
-3. `metrics`: 3-tuple with the peak-to-valley error, RMS wavefront error, and Strehl ratio;
+2. `v`: full vector of Zernike wavefront error expansion coefficients;
+3. `metrics`: named 3-tuple with the peak-to-valley error, RMS wavefront error, and Strehl ratio;
4. `fig`: the plotted Makie figure.
These can also be accessed through indexing and regular non-property destructuring.
+See also [`Z`](@ref), [`P`](@ref).
+
----
W(x, y, OPD; n_max, options...)
@@ -66,7 +80,7 @@ Method accepting normalized Cartesian coordinate data.
W(ρ, θ, OPD, n_max, Model())
-Returns the wavefront error function `ΔW(ρ, θ)` corresponding to an `n_max` fit.
+Return the wavefront error function `ΔW(ρ, θ)` corresponding to an `n_max` fit.
# Keyword argument options:
@@ -81,39 +95,62 @@ Returns the wavefront error function `ΔW(ρ, θ)` corresponding to an `n_max` f
W
"""
- S(ε::Float64, v::Vector{Float64})
+ P(v::Vector{T}, ε::T, δ::Complex{T}, ϕ::T, ω::Tuple{T,T}) where T <: Float64
-Pupil scaling function which computes a new set of Zernike expansion coefficients under aperture down-scaling and plots the result.
+Compute a new set of Zernike wavefront error expansion coefficients under a given set of transformation factors and plot the result.
+
+Available transformations are scaling, translation, & rotation for circular and elliptical exit pupils. These are essentially coordinate transformations in the pupil plane over the wavefront map.
+
+# Main arguments
-* `ε`: scaling factor `{0 ≤ ε ≤ 1}`;
* `v`: vector of full Zernike expansion coefficients ordered in accordance with the ANSI / OSA single index standard. This is the `v` vector returned by the wavefront error fitting function `W(ρ, θ, OPD, n_max)`.
+* `ε`: scaling factor `{0 ≤ ε ≤ 1}`;
+* `δ`: translational complex coordinates (displacement of the pupil center in the complex plane);
+* `ϕ`: rotation of the pupil in radians `(mod 2π)`, defined positive counter-clockwise from the horizontal x-axis;
+* `ω`: elliptical pupil transform parameters; 2-tuple where `ω[1]` is the ratio of the minor radius to the major radius of the ellipse and `ω[2]` is the angle defined positive counter-clockwise from the horizontal coordinate axis of the exit pupil to the minor axis of the ellipse.
-`ε` = `r₂/r₁` where `r₂` is the new radius, `r₁` the original
+The order the transformations are applied is:\\
+scaling --> translation --> rotation --> elliptical transform.
-In particular the radial variable corresponding to the rescaled exit pupil is normalized such that:\\
-`ρ` = `r/r₂`; `{0 ≤ ρ ≤ 1}`\\
-`r`: radial pupil position, `r₂`: max. radius\\
-`W₂(ρ₂)` = `W₁(ερ₂)`
+The translation, rotation, and elliptical arguments are optional.
+
+See also [`Z`](@ref), [`W`](@ref).
-The rescaled expansion coefficients are computed using a fast and accurate algorithm suitable for high orders; it is based on a formula presented by Janssen & Dirksen (2007) doi:10.2971/jeos.2007.07012.
+----
# Positional argument options:
- S(ε, v, Model())
+ P(v, ε, δ, ϕ, ω, Model())
-Returns the wavefront error function `ΔW(ρ, θ)` corresponding to an `ε` aperture scaling.
+Return the wavefront error function `ΔW(ρ, θ)` corresponding to the input transform parameters.
# Keyword argument options:
- S(ε, v; precision = 3, scale::Int)
+ P(v, ε, δ, ϕ, ω; precision = 3, scale::Int)
* `precision`: number of digits to use after the decimal point in computing the expansion coefficients. Results will be rounded according to this precision and any polynomials with zero-valued coefficients will be ignored when pulling in the Zernike functions while constructing the composite wavefront error; this means lower precision values yield faster results.
\u2063\u2063\u2063\u2063 If you want full 64-bit floating-point precision use `precision = "full"`.
* `scale`: `{1 ≤ scale ≤ 100}`: multiplicative factor determining the size of the plotted matrix; the total number of elements is capped at 1 million.
+
+# Extended help
+
+`ε` = `r₂/r₁` where `r₂` is the new smaller radius, `r₁` the original
+
+In particular the radial variable corresponding to the rescaled exit pupil is normalized such that:\\
+`ρ` = `r/r₂`; `{0 ≤ ρ ≤ 1}`\\
+`r`: radial pupil position, `r₂`: max. radius\\
+`ΔW₂(ρ₂, θ)` = `ΔW₁(ερ₂, θ)`
+
+For translation the shift must be within the bounds of the scaling applied such that:\\
+`0.0 ≤ ε + |δ| ≤ 1.0`.
+
+For elliptical pupils (usually the result of measuring the wavefront off-axis), the major radius is defined such that it equals the radius of the circle and so `ω[1]` is the fraction of the circular pupil covered by the minor radius (this is approximated well by a cosine projection factor for angles up to 40 degrees); `ω[2]` is then the direction of the stretching applied under transformation in converting the ellipse to a circle before fitting the expansion coefficients.
+
+The transformed expansion coefficients are computed using a fast and accurate algorithm suitable for high orders; it is based on a formulation presented by Lundström & Unsbo (2007) doi:10.1364/JOSAA.24.000569.
"""
-S
+P
"""
`Zernike.Polynomial`
@@ -126,6 +163,8 @@ Fields:
2. `N`: normalization factor;
3. `R`: RadialPolynomial callable type: function `R(ρ)`;
4. `M`: Sinusoid callable type: function `M(θ)`.
+
+See also [`Zernike.WavefrontError`](@ref).
"""
Polynomial
@@ -142,5 +181,49 @@ Fields:
2. `n_max`: maximum radial degree fit to;
3. `a`: vector of the Zernike expansion coefficients used in the fit;
4. `Z`: the respective Zernike polynomial functions.
+
+See also [`Zernike.Polynomial`](@ref).
"""
WavefrontError
+
+"""
+ noll_to_j(noll::Int)
+
+Convert Noll indices to ANSI standard indices.
+
+See also [`fringe_to_j`](@ref), [`standardize!`](@ref), [`standardize`](@ref).
+"""
+noll_to_j
+
+"""
+ standardize!(noll::Vector)
+
+Re-order a Noll specified Zernike expansion coefficient vector according to the ANSI standard.
+
+This requires a full ordered vector up to n_max.
+
+See also [`standardize`](@ref), [`noll_to_j`](@ref), [`fringe_to_j`](@ref).
+"""
+standardize!
+
+"""
+ fringe_to_j(fringe::Int)
+
+Convert Fringe indices to ANSI standard indices.
+
+Only indices 1:37 are valid.
+
+See also [`noll_to_j`](@ref), [`standardize`](@ref), [`standardize!`](@ref).
+"""
+fringe_to_j
+
+"""
+ standardize(fringe::Vector)
+
+Format a Fringe specified Zernike expansion coefficient vector according to the ANSI standard.
+
+This function expects unnormalized coefficients; the input coefficients will be re-ordered and normalized in line with the orthonormal standard. As Fringe is a 37 polynomial subset of the full set of Zernike polynomials any coefficients in the standard order missing a counterpart in the input vector will be set to zero.
+
+See also [`standardize!`](@ref), [`fringe_to_j`](@ref), [`noll_to_j`](@ref).
+"""
+standardize
diff --git a/src/ScaleAperture.jl b/src/ScaleAperture.jl
index c5e9043..16e3729 100644
--- a/src/ScaleAperture.jl
+++ b/src/ScaleAperture.jl
@@ -1,4 +1,4 @@
-#= This algorithm is based on a formula presented by Janssen and Dirksen in:
+#= This algorithm is based on a formula presented in:
https://doi.org/10.2971/jeos.2007.07012