Stabilitas numerik polinomial tingkat tinggi Zernike

9

Saya mencoba menghitung urutan lebih tinggi (misalnya m=0,, n=46) momen Zernike untuk beberapa gambar. Namun, saya mengalami masalah mengenai polinomial radial (lihat wikipedia ). Ini adalah polinomial yang didefinisikan pada interval [0 1]. Lihat kode MATLAB di bawah ini

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

Namun, ini jelas mengalami masalah numerik dekat RHO > 0.9. Polinomial dengan banyak suara

Saya mencoba refactoring untuk polyvalberpikir mungkin ada beberapa algoritma di belakang layar yang lebih baik tapi itu tidak menyelesaikan apa pun. Mengubahnya ke perhitungan simbolis memang membuat grafik yang diinginkan tetapi sangat lambat bahkan untuk grafik sederhana seperti yang ditunjukkan.

Apakah ada cara yang stabil secara numerik untuk mengevaluasi polinomial tingkat tinggi seperti itu?

Sanchises
sumber
3
Seringkali lebih baik menggunakan polinomial ortogonal, di sini polinomial Jacobi . Sudahkah Anda mencoba mathworks.com/help/symbolic/jacobip.html dan hubungannya dengan
Rnm(r)=(1)(nm)/2rmP(nm)/2(m,0)(12r2)?
gammatester
@ gramatester Itu berhasil! Bisakah Anda menguraikan jawaban mengapa ini bisa terjadi?
Sanchises
Senang mendengar bahwa itu bekerja. Sayangnya saya tidak bisa memberikan jawaban yang didekasikan karena dua alasan. Pertama: walaupun secara umum diketahui bahwa polinomial ortogonal memiliki sifat stabilitas yang lebih baik daripada bentuk standar, saya tidak tahu bukti formal (terutama dalam kasus ini). Kedua saya tidak menggunakan Matlab dan tidak bisa memberikan data untuk polinomial Jacobi yang diimplementasikan.
gammatester
1
@Sanchises Tidak ada makan siang gratis di sini: hanya karena sesuatu polinomial bukan berarti rumus langsung dalam hal kekuatan adalah cara yang tepat untuk menghitungnya, dan menghitung polinomial Jacobi secara akurat bukanlah masalah sepele — Anda tidak melakukannya melalui koefisien, jadi tidak semurah itu.
Kirill
2
Alasan mengapa ia berhasil menggunakan polinomial Jacobi adalah karena Anda menyingkirkan pembatalan bencana dalam rumus Anda (lihat semua faktor berosilasi dengan koefisien yang sangat besar!), Dan prosedur evaluasi polinomial Jacobi standar diimplementasikan dengan hati-hati di perpustakaan sehingga dijamin untuk lebih akurat. Sebagian besar pekerjaan di sini dilakukan untuk memastikan polinomial Jacobi dievaluasi secara akurat.
Kirill

Jawaban:

7

Dalam tulisan ini , Honarvar dan Paramesran memperoleh metode yang menarik untuk menghitung polinomial radial Zernike dengan cara rekursif yang sangat bagus. Formula rekursi secara langsung sangat mudah, tanpa pembagian atau perkalian dengan bilangan bulat besar: Saya akan merekomendasikan untuk melihat gambar 1 di Honarvar dan Paramesran kertas, yang dengan jelas menggambarkan ketergantungan antara berbagai polinomial Zernike.

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

Ini diimplementasikan dalam skrip Oktaf berikut:

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)

Misalnya, gambar yang dihasilkan oleh kode ini menunjukkan bahwa dengan , dan , pembatalan bencana terjadi di dekat , jika polinom radial Zernike dikomputasi melalui polinomial Jacobi. Oleh karena itu, kita juga harus khawatir tentang keakuratan polinomial Zernike tingkat rendah.m=22n=112ρ=0.7

masukkan deskripsi gambar di sini

Metode rekursif tampaknya jauh lebih cocok untuk menghitung polinomial Zernike tingkat tinggi ini dengan cara yang stabil. Namun demikian, untuk dan , perbedaan maksimum antara Jacobi dan metode rekursif adalah (hanya?) , Yang mungkin cukup akurat untuk aplikasi Anda.m=0n=461.4e-10

wim
sumber
Plot Anda terlihat seperti bug di Matlab jacobiPD, tidak seperti pembatalan bencana umum.
Kirill
@ Kiril: Saya menggunakan Sanchises JacobiPDdari jawabannya . Ini berfungsi dengan baik untuk polinomial tingkat rendah. Misalnya, dengan , arbitrary , dan arbitrary , perbedaan antara kedua metode lebih kecil dari . Meskipun istilah individual dalam penjumlahan adalah kecil, mereka mungkin menjadi besar setelah dikalikan dengan . Selain itu mereka memiliki tanda bolak-balik, yang merupakan resep sempurna untuk pembatalan bencana. n=30mρ6.9e-13JacobiPDfactorial(n+a) * factorial(n+b)
wim
(lanjutan) Misalnya dengan dan ekspresi , dapat menjadi sebesar , sedangkan jumlahnya hanya pada akhirnya. Anda dapat menyebutnya bug, tetapi dengan ketepatan tak terbatas, jawabannya pasti benar. Bisakah Anda menjelaskan apa yang Anda maksudkan dengan "tidak ada pembatalan bencana umum"? 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
wim
1
@wim saya tidak melihat itu bukan Matlab. Jika implementasi polinomial seseorang Jacobi cukup baik untuk tujuan mereka, itu tidak masalah. Saya hanya mengatakan itu bug karena saya salah paham dan menganggapnya sebagai fungsi bawaan (saya berharap fungsi perpustakaan menjadi sangat padat). Dengan "generik" yang saya maksudkan adalah jika Anda tidak tahu bagaimana fungsi diimplementasikan, Anda tidak dapat menyebut output yang salah "pembatalan bencana" seperti istilah umum untuk semua jenis kesalahan, tapi itu hanya kesalahpahaman saya tentang apa kode itu lakukan.
Kirill
1
Agar jelas: kode saya tidak rekursif. Ini adalah hubungan berulang tiga istilah standar berulang (serupa dengan polinomial Chebyshev) yang seharusnya lebih stabil daripada misalnya bentuk Horner untuk polinomial.
gammatester
8

Solusi yang mungkin (disarankan oleh @ gramatester) adalah dengan menggunakan polinomial Jacobi. Ini menghindari masalah pembatalan katastropik dalam menambahkan koefisien polinom besar dengan evaluasi polinomial 'naif'.

Polinomial Zernike radial dapat diekspresikan oleh polinomial Jacobi sebagai berikut (lihat persamaan (6) )

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

Namun dalam MATLAB, penggunaan jacobiP(n,a,b,x)tidak dapat diterima lambat untuk vektor / matriks besar x=rho. The jacobiPFungsi sebenarnya adalah bagian dari Toolbox simbolik, dan evaluasi dari polinomial ditangguhkan untuk mesin simbolik, yang perdagangan kecepatan untuk presisi sewenang-wenang. Implementasi manual polinomial Jacobi dengan demikian diperlukan.

Karena parameter ke fungsi Jacobi semuanya nonnegatif ( , , ), kita dapat menggunakan ekspresi berikut (lihat Wikipedia , perhatikan bahwa saya mengisi nilai untuk ) α=mβ=0n=(nm/2)s

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

Dalam MATLAB, ini diterjemahkan menjadi (Jacobi p olice d epartment P olynomial, ' D ouble' implementasi)

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

Polinomial Zernike radial yang sebenarnya dengan demikian (untuk m=abs(m))

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

Catatan: jawaban-diri ini hanya solusi praktis; jangan ragu memberi tag pada jawaban lain yang menjelaskan mengapa ini berhasil.

Sanchises
sumber