Estabilidad numérica de polinomios de Zernike de orden superior

9

Estoy tratando de calcular los momentos de Zernike de orden superior (p. Ej. m=0, n=46) Para alguna imagen. Sin embargo, me encuentro con un problema con respecto al polinomio radial (ver wikipedia ). Este es un polinomio definido en el intervalo [0 1]. Ver el código MATLAB a continuación

function R = radial_polynomial(m,n,RHO)
    R = 0;
    for k = 0:((n-m)/2)        
        R = R + (-1).^k.*factorial(n-k) ...
            ./ ( factorial(k).*factorial((n+m)./2-k) .* factorial((n-m)./2-k) ) ...
            .*RHO.^(n-2.*k);
    end
end

Sin embargo, esto obviamente tiene problemas numéricos cercanos RHO > 0.9. Un polinomio con mucho ruido.

Traté de refactorizarlo para polyvalpensar que podría tener algunos mejores algoritmos detrás de escena, pero eso no resolvió nada. La conversión a un cálculo simbólico creó el gráfico deseado, pero fue increíblemente lento incluso para un gráfico simple como se muestra.

¿Existe una forma numéricamente estable de evaluar tales polinomios de alto orden?

Sanchises
fuente
3
A menudo es mejor usar polinomios ortogonales, aquí los polinomios de Jacobi . ¿Has probado mathworks.com/help/symbolic/jacobip.html y la relación
Rnortemetro(r)=(-1)(norte-metro)/ /2rmetroPAGS(norte-metro)/ /2(metro,0 0)(1-2r2)?
gammatester
@gammatester ¡Eso funciona! ¿Podrías dar una respuesta sobre por qué este sería el caso?
Sanchises
Es bueno escuchar que funciona. Lamentablemente, no puedo dar una respuesta determinada por dos razones. Primero: aunque se sabe comúnmente que los polinomios ortogonales tienen mejores propiedades de estabilidad que la forma estándar, no conozco una prueba formal (especialmente en este caso). Segundo, no uso Matlab y no puedo dar datos para los polinomios de Jacobi implementados.
gammatester
1
@Sanchises No hay almuerzo gratis aquí: solo porque algo es un polinomio no significa que la fórmula directa en términos de poderes sea la forma correcta de calcularlo, y calcular polinomios de Jacobi con precisión no es en sí mismo un asunto trivial, no lo hace a través de los coeficientes, por lo que no es tan barato.
Kirill
2
La razón por la que funciona para usar los polinomios de Jacobi es que te deshaces de la cancelación catastrófica en tu fórmula (¡mira todos esos factores oscilantes con coeficientes muy grandes!), Y el procedimiento de evaluación polinomial de Jacobi predeterminado se implementa cuidadosamente en una biblioteca, por lo que está garantizado ser preciso. La mayor parte del trabajo aquí se realiza para garantizar que los polinomios de Jacobi se evalúen con precisión.
Kirill

Respuestas:

7

Rnortemetro(ρ)=ρ(Rnorte-1El |metro-1El |(ρ)+Rnorte-1metro+1(ρ))-Rnorte-2metro(ρ)

Esto se implementa en el siguiente script de Octave:

clear                                     % Tested with Octave instead of Matlab
N = 120;
n_r = 1000;
R = cell(N+1,N+1);
rho = [0:n_r]/n_r;
rho_x_2 = 2*[0:n_r]/n_r;

R{0+1,0+1} = ones(1,n_r+1);               % R^0_0  Unfortunately zero based cell indexing is not possible
R{1+1,1+1} = R{0+1,0+1}.*rho;             % R^1_1  ==>  R{...+1,...+1} etc.
for n = 2:N,
    if bitget(n,1) == 0,                  % n is even
        R{0+1,n+1} = -R{0+1,n-2+1}+rho_x_2.*R{1+1,n-1+1};                % R^0_n
        m_lo = 2;
        m_hi = n-2;
    else
        m_lo = 1;
        m_hi = n-1;
    end
    for m = m_lo:2:m_hi,
        R{m+1,n+1} = rho.*(R{m-1+1,n-1+1}+R{m+1+1,n-1+1})-R{m+1,n-2+1};  % R^m_n
    end
    R{n+1,n+1} = rho.*R{n-1+1,n-1+1};                                    % R^n_n
end;


Z = @(m,n,rho) (-1)^((n-m)/2) * rho.^m .* jacobiPD((n-m)/2,m,0,1-2*rho.^2);
m = 22;
n = 112;
figure
plot(rho,Z(m,n,rho))
hold on
plot(rho,R{m+1,n+1},'r');
xlabel("rho")
ylabel("R^{22}_{112}(rho)")
legend("via Jacobi","recursive");
%print -djpg plt.jpg

m = 0;
n = 46;
max_diff_m_0_n_46 = norm(Z(m,n,rho)-R{m+1,n+1},inf)

metro=22norte=112ρ=0.7

ingrese la descripción de la imagen aquí

metro=0 0norte=461.4e-10

wim
fuente
Su trama se ve como un error en Matlab jacobiPD, no como una cancelación catastrófica genérica.
Kirill
JacobiPDnorte=30metroρ6.9e-13JacobiPDfactorial(n+a) * factorial(n+b)
metro=22norte=1121/(factorial(s)*factorial(n+a-s)*factorial(b+s)*factorial(n-s)) * ((x-1)/2).^(n-s).*((x+1)/2).^s * factorial(n+a) * factorial(n+b)1.4e18-2.1
1
@wim No me di cuenta de que no es de Matlab. Si la implementación del polinomio Jacobi de alguien es lo suficientemente buena para su propósito, no hay problema. Solo dije que es un error porque no entendí bien y pensé que es una función incorporada (espero que las funciones de la biblioteca sean muy sólidas). Por "genérico" quise decir que si no sabes cómo se implementa la función, no puedes llamar a salidas incorrectas "cancelación catastrófica" como un término general para todo tipo de errores, pero eso fue solo mi malentendido de qué El código estaba haciendo.
Kirill
1
Para ser claros: mi código no es recursivo. Es la relación de recurrencia de tres términos estándar iterativa (similar a los polinomios de Chebyshev) que se supone que es normalmente más estable que, por ejemplo, la forma de Horner para polinomios.
gammatester
8

Una posible solución (sugerida por @gammatester) es usar polinomios de Jacobi. Esto evita el problema de la cancelación catastrófica al agregar los grandes coeficientes polinómicos mediante una evaluación polinómica "ingenua".

El polinomio radial de Zernike se puede expresar mediante los polinomios de Jacobi de la siguiente manera (ver ecuación (6) )

Rnortemetro(ρ)=(-1)(norte-metro)/ /2ρmetroPAGS(norte-metro)/ /2(metro,0 0)(1-2ρ2)

Sin embargo, en MATLAB, el uso de jacobiP(n,a,b,x)es inaceptablemente lento para grandes vectores / matrices de x=rho. La jacobiPfunción es en realidad parte de la Caja de herramientas simbólica, y la evaluación del polinomio se difiere al motor simbólico, que intercambia velocidad por precisión arbitraria. Por lo tanto, es necesaria una implementación manual de los polinomios de Jacobi.

α=metroβ=0 0norte=(norte-metro/ /2)s

PAGSnorte(α,β)(ρ)=(norte+α)!(norte+β)!s=0 0norte[1s!(norte+α-s)!(β+s)!(norte-s)!(X-12)norte-s(X+12)s]

En MATLAB, esto se traduce en (Jacobi p olice d epartment P olynomial, implementación ' D ' doble ')

function P = jacobiPD(n,a,b,x)
    P = 0;
    for  s  0:n
        P = P + ...
            1/(factorial(s)*factorial(n+a-s)*factorial(b+s)*factorial(n-s)) * ...
            ((x-1)/2).^(n-s).*((x+1)/2).^s;
    end
    P = P*factorial(n+a) * factorial(n+b);
end

El polinomio radial real de Zernike es así (para m=abs(m))

Z = @(m,n,rho) (-1)^((n-m)/2) * rho.^m .* jacobiPD((n-m)/2,m,0,1-2*rho.^2);

Nota: esta auto respuesta es solo una solución práctica; siéntase libre de etiquetar otra respuesta que explique por qué esto funciona.

Sanchises
fuente