高阶泽尼克多项式的数值稳定性

计算科学 matlab 多项式 数值限制
2021-12-18 07:18:22

我正在尝试计算某些图像的高阶(例如,m=0n=46Zernike 矩。但是,我遇到了关于径向多项式的问题(请参阅维基百科)。这是在区间 [0 1] 上定义的多项式。请参阅下面的 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

但是,这显然会遇到 附近的数值问题RHO > 0.9具有大量噪声的多项式

我尝试重构它,polyval认为它可能有一些更好的幕后算法,但这并没有解决任何问题。将其转换为符号计算确实创建了所需的图形,但即使对于如图所示的简单图形,速度也慢得令人难以置信。

是否有一种数值稳定的方法来评估这种高阶多项式?

2个回答

一个可能的解决方案(@gammatester 建议)是使用 Jacobi 多项式。这避免了通过“朴素”多项式评估添加大多项式系数时的灾难性抵消问题。

径向 Zernike 多项式可以用 Jacobi 多项式表示如下(见方程(6)

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

然而,在 MATLAB 中,jacobiP(n,a,b,x)对于x=rho. jacobiP函数实际上是符号工具箱的一部分,多项式的计算被推迟到符号引擎,它以速度换取任意精度。因此需要手动执行 Jacobi 多项式。

由于 Jacobi 函数的参数都是非负的 (α=m,β=0,n=(nm/2)),我们可以使用以下表达式(参见Wikipedia,注意我填写的值s)

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

在 MATLAB 中,这转换为 (Jacobi p olice d epartment P olynomial, ' D ouble' implementation)

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

因此,实际的径向 Zernike 多项式是 (对于m=abs(m))

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

注意:这个自我回答只是一个实际的解决方案;随意标记另一个解释为什么它有效的答案。

本文中,Honarvar 和 Paramesran 推导出了一种有趣的方法,以非常好的递归方式计算径向 Zernike 多项式。递归公式非常简单,无需除以或乘以大整数:

Rnm(ρ)=ρ(Rn1|m1|(ρ)+Rn1m+1(ρ))Rn2m(ρ)
我建议看一下 Honarvar 和 Paramesran 论文中的图 1,它清楚地说明了不同 Zernike 多项式之间的依赖关系。

这是在以下 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=22, 和n=112,灾难性的取消发生在附近ρ=0.7,如果 Zernike 径向多项式是通过 Jacobi 多项式计算的。因此,人们还必须担心低次泽尼克多项式的准确性。

在此处输入图像描述

递归方法似乎更适合以稳定的方式计算这些高阶 Zernike 多项式。尽管如此,对于m=0n=46,雅可比和递归方法之间的最大差异是(仅?)1.4e-10,这对于您的应用程序可能足够准确。