Estabilidade numérica de polinômios Zernike de ordem superior

9

Estou tentando calcular momentos Zernike de ordem superior (por exemplo m=0, n=46) para alguma imagem. No entanto, estou com um problema em relação ao polinômio radial (consulte a Wikipedia ). Este é um polinômio definido no intervalo [0 1]. Veja o código MATLAB abaixo

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

No entanto, isso obviamente tem problemas numéricos próximos RHO > 0.9. Um polinômio com muito barulho

Eu tentei refatorá-lo para polyval pensar que poderia ter alguns algoritmos melhores nos bastidores, mas isso não resolveu nada. Convertê-lo em um cálculo simbólico criou o gráfico desejado, mas foi incrivelmente lento mesmo para um gráfico simples como o mostrado.

Existe uma maneira numericamente estável de avaliar esses polinômios de alta ordem?

Sanchises
fonte
3
Muitas vezes, é melhor usar polinômios ortogonais, aqui polinômios de Jacobi . Você já experimentou mathworks.com/help/symbolic/jacobip.html e a relação
Rnm(r)=(1)(nm)/2rmP(nm)/2(m,0)(12r2)?
gammatester
@gammatester Isso funciona! Você poderia elaborar uma resposta sobre por que esse seria o caso?
Sanchises
Bom ouvir que funciona. Infelizmente, não posso dar uma resposta decicada por dois motivos. Primeiro: embora seja comumente conhecido que os polinômios ortogonais têm melhores propriedades de estabilidade do que a forma padrão, não conheço uma prova formal (especialmente neste caso). Segundo, não uso o Matlab e não posso fornecer dados para os polinômios Jacobi implementados.
gammatester
11
@ Sanchises Não há almoço grátis aqui: apenas porque algo é um polinômio, não significa que a fórmula direta em termos de poderes seja a maneira certa de computá-lo, e computar com precisão os polinômios de Jacobi não é uma questão trivial - você não faz através dos coeficientes, por isso não é tão barato.
22418 Kirill #
2
O motivo pelo qual ele trabalha para usar os polinômios Jacobi é que você se livra do cancelamento catastrófico em sua fórmula (observe todos os fatores oscilantes com coeficientes muito grandes!) E o procedimento padrão de avaliação polinomial Jacobi é implementado com cuidado em uma biblioteca, garantindo assim Para ser exato. A maior parte do trabalho aqui é feita para garantir que os polinômios de Jacobi sejam avaliados com precisão.
Kirill

Respostas:

7

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

Isso é implementado no seguinte script do 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

insira a descrição da imagem aqui

m=0 0n=46.1.4e-10

wim
fonte
Seu enredo parece um bug no Matlab jacobiPD, não como qualquer cancelamento catastrófico genérico.
21918 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
11
@ wim Eu não percebi que não é do Matlab. Se a implementação polinomial de Jacobi de alguém é boa o suficiente para sua finalidade, isso não é problema. Eu apenas disse que é um bug porque não entendi e pensei que fosse uma função interna (espero que as funções da biblioteca sejam muito sólidas). Por "genérico", quis dizer que, se você não sabe como a função é implementada, não pode chamar saídas incorretas de "cancelamento catastrófico" como um termo genérico para todos os tipos de erros, mas esse foi apenas o meu mal-entendido sobre o que o código estava fazendo.
21918 Kirill
11
Para ser claro: meu código não é recursivo. É a relação de recorrência iterativa padrão de três termos (semelhante aos polinômios de Chebyshev) que deve ser normalmente mais estável do que, por exemplo, a forma Horner para polinômios.
gammatester
8

Uma solução possível (sugerida por @gammatester) é usar polinômios de Jacobi. Isso contorna o problema do cancelamento catastrófico ao adicionar grandes coeficientes polinomiais por avaliação polinomial "ingênua".

O polinômio radial de Zernike pode ser expresso pelos polinômios de Jacobi da seguinte forma (consulte a equação (6) )

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

No entanto, no MATLAB, o uso de jacobiP(n,a,b,x)é inaceitavelmente lento para vetores / matrizes grandes de x=rho. A jacobiPfunção é realmente parte da Symbolic Toolbox e a avaliação do polinômio é adiada para o mecanismo simbólico, que troca a velocidade por precisão arbitrária. Uma implementação manual dos polinômios de Jacobi é, portanto, necessária.

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

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

No MATLAB, isto traduz-se (Jacobi p polícia prosseguiu d EPARTAMENTO P olynomial, ' D ouble' implementação)

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

O polinômio radial de Zernike real é assim (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: essa resposta automática é apenas uma solução prática; fique à vontade para marcar outra resposta que explique por que isso funciona.

Sanchises
fonte