30#ifndef math_zernike_hpp
31#define math_zernike_hpp
37#include "../mxlib.hpp"
38#include "../math/func/bessel.hpp"
39#include "../math/func/jinc.hpp"
40#include "../math/func/factorial.hpp"
41#include "../math/func/sign.hpp"
42#include "../math/constants.hpp"
100template <
typename realT>
102 std::vector<realT> &c,
116 if( ( n - m ) % 2 > 0 )
122 int ul = 0.5 * ( n - m ) + 1;
126 for(
int k = 0; k < ul; ++k )
128 c[k] = pow( -1.0, k ) * math::func::factorial<realT>( n - k ) /
129 ( math::func::factorial<realT>( k ) * math::func::factorial<realT>( 0.5 * ( n + m ) - k ) *
130 math::func::factorial<realT>( 0.5 * ( n - m ) - k ) );
137extern template int zernikeRCoeffs<float>( std::vector<float> &c,
int n,
int m );
139extern template int zernikeRCoeffs<double>( std::vector<double> &c,
int n,
int m );
141extern template int zernikeRCoeffs<long double>( std::vector<long double> &c,
int n,
int m );
144extern template int zernikeRCoeffs<__float128>( std::vector<__float128> &c,
int n,
int m );
156template <
typename realT,
typename calcRealT>
160 std::vector<calcRealT> &c
167 if( ( n - m ) % 2 > 0 )
173 if( c.size() != 0.5 * ( n - m ) + 1 )
180 for(
size_t k = 0; k < c.size(); ++k )
182 R += c[k] * pow( rho, n - 2 * k );
188extern template float zernikeR<float, double>(
float rho,
int n,
int m, std::vector<double> &c );
190extern template double zernikeR<double, double>(
double rho,
int n,
int m, std::vector<double> &c );
192extern template long double
193zernikeR<long double, long double>(
long double rho,
int n,
int m, std::vector<long double> &c );
196extern template __float128 zernikeR<__float128, __float128>( __float128 rho,
int n,
int m, std::vector<__float128> &c );
207template <
typename realT,
typename calcRealT>
216 if( ( n - m ) % 2 > 0 )
221 std::vector<calcRealT> c;
226 return zernikeR<realT, calcRealT>( rho, n, m, c );
229extern template float zernikeR<float, double>(
float rho,
int n,
int m );
231extern template double zernikeR<double, double>(
double rho,
int n,
int m );
233extern template long double zernikeR<long double, long double>(
long double rho,
int n,
int m );
236extern template __float128 zernikeR<__float128, __float128>( __float128 rho,
int n,
int m );
247template <
typename realT,
typename calcRealT>
252 std::vector<calcRealT> &c
258 if( n == 0 && m == 0 )
276 return sqrt( (realT)n + 1 ) * zernikeR<realT, calcRealT>( rho, n, m, c ) * azt;
279extern template float zernike<float, double>(
float rho,
float phi,
int n,
int m, std::vector<double> &c );
281extern template double zernike<double, double>(
double rho,
double phi,
int n,
int m, std::vector<double> &c );
283extern template long double
284zernike<long double, long double>(
long double rho,
long double phi,
int n,
int m, std::vector<long double> &c );
287extern template __float128
288zernike<__float128, __float128>( __float128 rho, __float128 phi,
int n,
int m, std::vector<__float128> &c );
300template <
typename realT,
typename calcRealT>
308 std::vector<calcRealT> c;
310 if( zernikeRCoeffs<calcRealT>( c, n, m ) < 0 )
313 return zernike<realT, calcRealT>( rho, phi, n, m, c );
316extern template float zernike<float, double>(
float rho,
float phi,
int n,
int m );
318extern template double zernike<double, double>(
double rho,
double phi,
int n,
int m );
320extern template long double zernike<long double, long double>(
long double rho,
long double phi,
int n,
int m );
323extern template __float128 zernike<__float128, __float128>( __float128 rho, __float128 phi,
int n,
int m );
334template <
typename realT,
typename calcRealT>
346 return zernike<realT, calcRealT>( rho, phi, n, m );
349extern template float zernike<float, double>(
float rho,
float phi,
int j );
351extern template double zernike<double, double>(
double rho,
double phi,
int j );
353extern template long double zernike<long double, long double>(
long double rho,
long double phi,
int j );
356extern template __float128 zernike<__float128, __float128>( __float128 rho, __float128 phi,
int j );
365template <
typename arrayT,
typename calcRealT,
int overscan = 2>
370 typename arrayT::Scalar xcen,
372 typename arrayT::Scalar ycen,
374 typename arrayT::Scalar rad = -1
378 typedef typename arrayT::Scalar realT;
384 std::vector<calcRealT> c;
389 size_t l0 = arr.rows();
390 size_t l1 = arr.cols();
393 rad = 0.5 * std::min( l0 - 1, l1 - 1 );
395 for(
size_t i = 0; i < l0; ++i )
397 for(
size_t j = 0; j < l1; ++j )
402 r = std::sqrt( x * x + y * y );
405 if( r > rad && r <= rad + ( 1.0 / overscan ) )
412 phi = std::atan2( y, x );
413 arr( i, j ) =
zernike( rho, phi, n, m, c );
431template <
typename arrayT,
typename calcRealT>
436 typename arrayT::Scalar xcen,
437 typename arrayT::Scalar ycen,
438 typename arrayT::Scalar rad = -1
442 typedef typename arrayT::Scalar realT;
449 return zernike<arrayT, calcRealT>( arr, n, m, xcen, ycen, rad );
459template <
typename arrayT,
typename calcRealT>
465 typename arrayT::Scalar rad = -1
469 typename arrayT::Scalar xcen = 0.5 * ( arr.rows() - 1.0 );
470 typename arrayT::Scalar ycen = 0.5 * ( arr.cols() - 1.0 );
472 return zernike<arrayT, calcRealT>( arr, n, m, xcen, ycen, rad );
482template <
typename arrayT,
typename calcRealT>
487 typename arrayT::Scalar rad = -1
491 typename arrayT::Scalar xcen = 0.5 * ( arr.rows() - 1.0 );
492 typename arrayT::Scalar ycen = 0.5 * ( arr.cols() - 1.0 );
494 return zernike<arrayT, calcRealT>( arr, j, xcen, ycen, rad );
506template <
typename cubeT,
typename calcRealT>
509 typename cubeT::Scalar rad = -1,
515 typedef typename cubeT::imageT arrayT;
517 typename cubeT::imageT im;
519 im.resize( cube.rows(), cube.cols() );
522 for(
int i = 0; i < cube.planes(); ++i )
524 rv = zernike<arrayT, calcRealT>( im, minj + i, rad );
530 cube.image( i ) = im;
547template <
typename realT>
556 std::complex<realT> Q;
571 Q = sqrt( n + 1 ) * Q;
575 Q = Q * pow( -1, 0.5 * ( n - m ) ) * pow( std::complex<realT>( { 0, 1 } ), m ) * sqrt( 2 ) * cos( m * phi );
579 Q = Q * pow( -1, 0.5 * ( n + m ) ) * pow( std::complex<realT>( { 0, 1 } ), -m ) * sqrt( 2 ) * sin( -m * phi );
583 Q = Q * pow( -1, 0.5 * n );
600template <
typename realT>
628 realT Q2 = ( n + 1 ) * ( B * B );
632 Q2 = 2 * Q2 * pow( cos( m * phi ), 2 );
636 Q2 = 2 * Q2 * pow( sin( -m * phi ), 2 );
642extern template float zernikeQNorm<float>(
float k,
float phi,
int n,
int m );
644extern template double zernikeQNorm<double>(
double k,
double phi,
int n,
int m );
646extern template long double zernikeQNorm<long double>(
long double k,
long double phi,
int n,
int m );
649extern template __float128 zernikeQNorm<__float128>( __float128 k, __float128 phi,
int n,
int m );
660template <
typename realT>
684template <
typename arrayT>
693 if( arr.rows() != k.rows() || arr.cols() != k.cols() )
699 if( arr.rows() != phi.rows() || arr.cols() != phi.cols() )
709 for(
size_t i = 0; i < arr.rows(); ++i )
711 for(
size_t j = 0; j < arr.cols(); ++j )
713 arr( i, j ) =
zernikeQNorm( k( i, j ), phi( i, j ), n, m );
720template <
typename realT>
727template <
typename realT>
734template <
typename realT>
741template <
typename realT>
748template <
typename realT>
755template <
typename realT>
@ invalidarg
An argument was invalid.
error_t mxlib_error_report(const error_t &code, const std::string &expl, const std::source_location &loc=std::source_location::current())
Print a report to stderr given an mxlib error_t code and explanation and return the code.
T2 bessel_j(T1 v, T2 x)
Bessel Functions of the First Kind.
T2 jincN(const T1 &v, const T2 &x)
The JincN function.
T jinc(const T &x)
The Jinc function.
constexpr floatT six_fifths()
Return 6/5 in the specified precision.
int noll_j(unsigned n, int m)
Get the Noll index j corresponding to Zernike coefficients n,m.
realT zernikeR(realT rho, int n, int m, std::vector< calcRealT > &c)
Calculate the value of a Zernike radial polynomial at a given separation.
realT zernikePPiston(const realT &kD)
Calculate the spatial power spectrum of Piston.
realT zernikePDefocus(const realT &kD)
Calculate the spatial power spectrum of Defocus.
realT zernikePTrefoil(const realT &kD)
Calculate the spatial power spectrum of Trefoil.
realT zernike(realT rho, realT phi, int n, int m, std::vector< calcRealT > &c)
Calculate the value of a Zernike radial polynomial at a given radius and angle.
int nZernRadOrd(unsigned n)
Get the number of Zernikes up to and including a radial order.
realT zernikePTipTilt(const realT &kD)
Calculate the spatial power spectrum of Tip & Tilt.
int noll_nm(int &n, int &m, int j)
Get the Zernike coefficients n,m corrresponding the Noll index j.
realT zernikeQNorm(realT k, realT phi, int n, int m)
Calculate the square-normed Fourier transform of a Zernike polynomial at position (k,...
std::complex< realT > zernikeQ(realT k, realT phi, int n, int m)
Calculate the square-normed Fourier transform of a Zernike polynomial at position (k,...
realT zernikePAstig(const realT &kD)
Calculate the spatial power spectrum of Astigmatism.
realT zernikePComa(const realT &kD)
Calculate the spatial power spectrum of Coma.
int zernikeRCoeffs(std::vector< realT > &c, int n, int m)
Calculate the coefficients of a Zernike radial polynomial.
int zernikeBasis(cubeT &cube, typename cubeT::Scalar rad=-1, int minj=2)
Fill in an Eigencube-like array with Zernike polynomials in Noll order.