pyzernike.xy_zernike_polynomial_up_to_order#

pyzernike.xy_zernike_polynomial_up_to_order(x: ndarray, y: ndarray, order: Integral, Rx: Real = 1.0, Ry: Real = 1.0, x0: Real = 0.0, y0: Real = 0.0, alpha: Real = 0.0, h: Real = 0.0, x_derivative: array | Sequence[Integral] | None = None, y_derivative: array | Sequence[Integral] | None = None, default: Real = nan, precompute: bool = True) List[ndarray][source]#

Computes all the Zernike polynomial \(Z_{n}^{m}(\rho_{eq}, \theta_{eq})\) for given cartesian coordinates \((x, y)\) on an elliptic annulus domain up to a given order.

See also

See also

For the mathematical development of the method, see the paper Generalization of Zernike polynomials for regular portions of circles and ellipses by Rafael Navarro, José L. López, José Rx. Díaz, and Ester Pérez Sinusía. The associated paper is available in the resources folder of the package.

Download the PDF : PDF

Lets consider the extended elliptic annulus domain defined by the following parameters:

../_images/elliptic_annulus_domain.png

The parameters to define the extended domain of the Zernike polynomial.#

The parameters are:

  • \(R_x\) and \(R_y\) are the lengths of the semi-axis of the ellipse.

  • \(x_0\) and \(y_0\) are the coordinates of the center of the ellipse.

  • \(\alpha\) is the rotation angle of the ellipse in radians.

  • \(h=\frac{a}{R_x}=\frac{b}{R_y}\) defining the inner boundary of the ellipse.

The Zernike polynomial \(Z_{n}^{m}(\rho_{eq}, \theta_{eq})\) is computed for the equivalent polar coordinates.

This function allows to compute Zernike polynomials at once for different sets of derivative orders given as sequences, which can be more efficient than calling the function multiple times for each set of derivative orders.

  • The parameters x and y must be numpy arrays of the same shape.

  • The parameters x_derivative and y_derivative must be sequences of integers with the same length.

The \(x\) and \(y\) values are the same for all the polynomials. The output output[k][j] is the Zernike polynomial of order n[j] and azimuthal frequency m[j] (OSA/ANSI ordering) with same shape as x and for the radial derivative of order x_derivative[k] and the angular derivative of order y_derivative[k].

Note

If the input x or y are not floating point numpy arrays, it is converted to one with numpy.float64 dtype. If the input x or y are floating point numpy arrays (ex: numpy.float32), the computation will be done in numpy.float32. If the input x and y are not of the same dtype, they are both converted to numpy.float64.

Warning

The only available derivatives are the first and second order derivatives with respect to x or y independently (jacobian and hessian matrix). For more complex derivatives, please implement the Faa di Bruno’s formula using the standard Zernike polynomial function with polar coordinates.

  • Available derivatives (:math:(dx, dy)): (0, 0), (1, 0), (0, 1), (2, 0), (0, 2), (1, 1).

Parameters:
  • x (numpy.ndarray) – The x coordinates in Cartesian system with shape (…,).

  • y (numpy.ndarray) – The y coordinates in Cartesian system with shape (…,).

  • order (int) – The maximum order of the Zernike polynomials to compute. It must be a positive integer.

  • Rx (Real, optional) – The length of the semi-axis of the ellipse along x axis. Must be strictly positive. The default is 1.0, which corresponds to the unit circle.

  • Ry (Real, optional) – The length of the semi-axis of the ellipse along y axis. Must be strictly positive. The default is 1.0, which corresponds to the unit circle.

  • x0 (Real, optional) – The x coordinate of the center of the ellipse. Can be any real number. The default is 0.0, which corresponds to an ellipse centered at the origin.

  • y0 (Real, optional) – The y coordinate of the center of the ellipse. Can be any real number. The default is 0.0, which corresponds to an ellipse centered at the origin.

  • alpha (Real, optional) – The rotation angle of the ellipse in radians. Can be any real number. The default is 0.0, such as \(x\) and \(y\) axis are aligned with the ellipse axes.

  • h (Real, optional) – The ratio of the inner semi-axis to the outer semi-axis. Must be in the range [0, 1). The default is 0.0, which corresponds to a filled ellipse.

  • x_derivative (Optional[Union[Sequence[Integral], numpy.array]], optional) – A sequence (List, Tuple) or 1D numpy array of the order(s) of the x derivative(s) to compute. Must be non-negative integers. If None, is it assumed that x_derivative is 0 for all polynomials.

  • y_derivative (Optional[Union[Sequence[Integral], numpy.array]], optional) – A sequence (List, Tuple) or 1D numpy array of the order(s) of the y derivative(s) to compute. Must be non-negative integers. If None, is it assumed that y_derivative is 0 for all polynomials.

  • default (Real, optional) – The default value to use for points outside the elliptic annulus domain. Must be a real number. The default is numpy.nan.

  • precompute (bool, optional) – If True, precomputes the useful terms for better performance when computing multiple polynomials with the same rho values. If False, computes the useful terms on the fly for each polynomial to avoid memory overhead. The default is True.

Returns:

A list of numpy arrays containing the Zernike polynomial values for each order and azimuthal frequency. Each array has the same shape as x.

Return type:

List[numpy.ndarray]

Raises:
  • TypeError – If the x or y values can not be converted to a numpy array of floating points values. If x_derivative or y_derivative (if not None) are not sequences of integers.

  • ValueError – If the x and y do not have the same shape. If the lengths of x_derivative and y_derivative (if not None) are not the same. If Rx or Ry are not strictly positive. If h is not in the range [0, 1[. If the derivative orders are higher than 2 or mixed (ex: (1, 1)).

Examples

Compute all the Zernike polynomials up to order 3 for a cartesian grid of points in the domain defined by a circle with radius sqrt(2) centered at (0, 0):

import numpy
from pyzernike import xy_zernike_polynomial_up_to_order, zernike_index_to_order

# Create a grid of points
x = numpy.linspace(-1, 1, 100)
y = numpy.linspace(-1, 1, 100)
x, y = numpy.meshgrid(x, y)  # Create a 2D grid

# Compute the Zernike polynomials up to order 3
result = xy_zernike_polynomial_up_to_order(x, y, order=3, Rx=numpy.sqrt(2), Ry=numpy.sqrt(2), x0=0, y0=0)
polynomials = result[0]  # Get the first set of polynomials (for x_derivative=0, y_derivative=0)

# Extract the values:
indices = list(range(len(polynomials)))
n, m = zernike_index_to_order(indices)  # Get the orders and azimuthal frequencies from the indices

for i, (n_i, m_i) in enumerate(zip(n, m)):
    print(f"Zernike polynomial Z_{n_i}^{m_i} for the given x and y values is: {polynomials[i]}")

To compute the polynomials and their first derivatives with respect to x:

import numpy
from pyzernike import xy_zernike_polynomial_up_to_order, zernike_index_to_order

# Create a grid of points
x = numpy.linspace(-1, 1, 100)
y = numpy.linspace(-1, 1, 100)
x, y = numpy.meshgrid(x, y)  # Create a 2D grid

# Compute the Zernike polynomials up to order 3 with x derivatives
result = xy_zernike_polynomial_up_to_order(x, y, order=3, x_derivative=[0, 1], Rx=numpy.sqrt(2), Ry=numpy.sqrt(2), x0=0, y0=0)
polynomials = result[0]  # Get the first set of polynomials (for x_derivative=0, y_derivative=0)
derivatives_x = result[1]  # Get the first set of derivatives (for x_derivative=1, y_derivative=0)

The output will contain the Zernike polynomials and their derivatives for the specified orders and azimuthal frequencies.