Stabilità numerica di polinomi di Zernike di ordine superiore


9

Sto cercando di calcolare i momenti Zernike di ordine superiore (ad esempio m=0, n=46) per qualche immagine. Tuttavia, sto riscontrando un problema relativo al polinomio radiale (vedi Wikipedia ). Questo è un polinomio definito sull'intervallo [0 1]. Vedi sotto il codice MATLAB

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

Tuttavia, questo ovviamente incontra problemi numerici vicino RHO > 0.9. Un polinomio con molto rumore

Ho provato a rifattorarlo polyvalpensando che potesse avere alcuni algoritmi dietro le quinte migliori ma che non ha risolto nulla. La conversione in un calcolo simbolico ha creato il grafico desiderato ma è stato incredibilmente lento anche per un grafico semplice come mostrato.

Esiste un modo numericamente stabile di valutare tali polinomi di alto ordine?


3
Spesso è meglio usare i polinomi ortogonali, qui i polinomi di Jacobi . Hai provato mathworks.com/help/symbolic/jacobip.html e la relazione
Rnm(r)=(1)(nm)/2rmP(nm)/2(m,0)(12r2)?
Gammatester,

@gammatester Funziona! Potresti forse elaborare una risposta sul perché questo sarebbe il caso?
Sanchises,

Bello sentire che funziona. Purtroppo non posso dare una risposta decisa per due motivi. Primo: sebbene sia risaputo che i polinomi ortogonali hanno proprietà di stabilità migliori rispetto alla forma standard, non conosco una prova formale (specialmente in questo caso). Secondo, non uso Matlab e non posso fornire dati per i polinomi Jacobi implementati.
Gammatester,

1
@Sanchises Non c'è pranzo gratis qui: solo perché qualcosa è un polinomio non significa che la formula diretta in termini di poteri sia il modo giusto per calcolarlo, e il calcolo accurato dei polinomi di Jacobi non è di per sé una cosa da poco: non lo fai attraverso i coefficienti, quindi non è così economico.
Kirill,

2
Il motivo per cui funziona l'uso dei polinomi Jacobi è che ti sbarazzi della cancellazione catastrofica nella tua formula (guarda tutti quei fattori oscillanti con coefficienti molto grandi!), E la procedura di valutazione polinomiale Jacobi predefinita è implementata attentamente in una libreria, quindi è garantita per essere precisi. La maggior parte del lavoro qui viene svolto per assicurarsi che i polinomi di Jacobi siano valutati accuratamente.
Kirill,

Risposte:


7

Rnm(ρ)=ρ(Rn1|m1|(ρ)+Rn1m+1(ρ))Rn2m(ρ)

Questo è implementato nel seguente script 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)

m=22n=112ρ=0.7

inserisci qui la descrizione dell'immagine

m=0n=461.4e-10


La tua trama sembra un bug in Matlab jacobiPD, non come una cancellazione catastrofica generica.
Kirill,

JacobiPDn=30mρ6.9e-13JacobiPDfactorial(n+a) * factorial(n+b)

m=22n=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 Non ho notato che non è di Matlab. Se l'implementazione polinomiale di Jacobi di qualcuno è abbastanza buona per il suo scopo, non c'è problema. Ho solo detto che è un bug perché ho frainteso e pensato che fosse una funzione integrata (mi aspetto che le funzioni della libreria siano molto solide). Con "generico" intendevo dire che se non sai come implementare la funzione, non puoi chiamare output errati "cancellazione catastrofica" come un termine generico per tutti i tipi di errori, ma quello era solo il mio fraintendimento di ciò che il codice stava funzionando.
Kirill,

1
Per essere chiari: il mio codice non è ricorsivo. È la relazione di ricorrenza standard a tre termini iterativa (simile ai polinomi di Chebyshev) che dovrebbe essere normalmente più stabile rispetto ad esempio alla forma di Horner per i polinomi.
Gammatester,

8

Una possibile soluzione (suggerita da @gammatester) è l'uso dei polinomi di Jacobi. Ciò aggira il problema della cancellazione catastrofica aggiungendo i grandi coefficienti polinomiali mediante una valutazione polinomiale "ingenua".

Il polinomio radiale di Zernike può essere espresso dai polinomi di Jacobi come segue (vedi equazione (6) )

Rnm(ρ)=(1)(nm)/2ρmP(nm)/2(m,0)(12ρ2)

In MATLAB, tuttavia, l'uso di jacobiP(n,a,b,x)è inaccettabilmente lento per grandi vettori / matrici di x=rho. La jacobiPfunzione fa effettivamente parte del Toolbox simbolico e la valutazione del polinomio viene rinviata al motore simbolico, che scambia la velocità con precisione arbitraria. È quindi necessaria un'implementazione manuale dei polinomi di Jacobi.

α=mβ=0n=(nm/2)s

Pn(α,β)(ρ)=(n+α)!(n+β)!s=0n[1s!(n+αs)!(β+s)!(ns)!(x12)ns(x+12)s]

In MATLAB, questo si traduce in (Jacobi p olice d IPARTIMENTO P olynomial, ' D ouble' attuazione)

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

L'attuale polinomio radiale di Zernike è quindi (per m=abs(m))

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

Nota: questa risposta è solo una soluzione pratica; sentiti libero di taggare un'altra risposta che spiega perché questo funziona.

Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.