Skip to main content Link Search Menu Expand Document (external link)
目录

用样条插值重构外旋轮线

问题描述

假如一个大圆的半径为$R$, 一个半径为$r$的小圆围绕着大圆滚动(如下图). 考虑离小圆圆心距离为$d$的一个附着在小圆上的点$P$, 于是$P$也会随着小圆的转动而转动.

我们把$P$的运动轨迹称为外旋轮线(epitrochoid), 它的参数方程为

\[\begin{aligned} x(\theta)&=(R+r)\cos\theta+d\cos\left(\dfrac{R+r}{r}\theta\right), \\ y(\theta)&=(R+r)\sin\theta-d\sin\left(\dfrac{R+r}{r}\theta\right), \end{aligned}\]

在外旋轮线中取$R=5$, $r=2$, $d=3$, $\theta\in[0,4\pi]$. 它的图像如下.

用$n$个等距点(即$\theta_k=\tfrac{4\pi}{n}k$, $k=0,1,\cdots,n-1$, 如图为$n=40$的情形), 求函数$x(\theta)$和$y(\theta)$的三次样条插值函数$\tilde{x}(\theta)$和$\tilde{y}(\theta)$, 并画出参数曲线$\theta\mapsto(\tilde{x}(\theta),\tilde{y}(\theta))$的图像.

回顾:三次样条插值函数满足

\[S(x)=\left\{\begin{aligned} &S_1(x), &&x\in[x_1,x_2], \\ &\vdots \\ &S_i(x), &&x\in[x_i,x_{i+1}], \\ &\vdots \\ &S_n(x), &&x\in[x_n,x_{n+1}]. \end{aligned}\right.\] \[S_i(x)=\sum\limits_{k=1}^4A_{k,i}(x-x_i)^{k-1}, \qquad x\in[x_i,x_{i+1}],\]

其中系数为

\[\begin{aligned} A_{1,i}&=f_i, \\ A_{2,i}&=f[x_i,x_{i+1}]-\dfrac{h_i}{6}(m_{i+1}+2m_i), \\ A_{3,i}&=\dfrac{m_i}{2}, \\ A_{4,i}&=\dfrac{m_{i+1}-m_i}{6h_i}. \end{aligned}\]

所以需要求出$m_2,\cdots,m_{n+1}$即可得到三次样条插值函数.

由于这是等距结点, 所以$h_i=h=\dfrac{4\pi}{n}$. 再由于原来的问题可以看作周期三次样条插值问题, 根据$S(x)$函数值相等、导数相等和二次导数相等的条件, 可以写出线性方程组

\[\mathbf{Hm}=\dfrac{6}{h}\mathbf{d},\]

其中,

\[\begin{aligned} &\mathbf{H}=\begin{pmatrix} 4 & 1 & & & & 1 \\ 1 & 4 & 1 \\ & 1 & 4 & 1 \\ & & \ddots &\ddots & \ddots \\ & & & 1 & 4 & 1 \\ 1 & & & & 1 & 4 \end{pmatrix}, \\ &\mathbf{m}=(m_2,m_3,\cdots,m_{n+1})^T, \\ &\mathbf{d}=(d_2,d_3,\cdots,d_{n+1})^T, \end{aligned}\] \[\begin{aligned} &d_i=f[x_i,x_{i+1}]-f[x_{i-1},x_i], && i=2,\cdots,n, \\ &d_{n+1}=f[x_1,x_2]-f[x_n,x_{n+1}]. \end{aligned}\]

运行结果

最终运行结果如下, 可以发现当$n=160$时得到的样条插值函数图像与原来的函数图像非常接近.


图1:原图像与$n=20$的样条插值图像

图2:原图像与$n=40$和$n=160$的样条插值图像

附录:Matlab代码

主程序

clf; %清空
f = @(x) (7*cos(x)+3*cos(3.5*x));
g = @(x) (7*sin(x)-3*sin(3.5*x));
xx = linspace(0,4*pi, 200);

ff_real = f(xx);
gg_real = g(xx);
plot(ff_real,gg_real, 'b--', 'DisplayName', '原图像');
hold on;

for n = [40,160] %可改变n的值
    h = 4*pi/n;
    
    xdata = linspace(0,4*pi,n+1);
    
    A1 = splineA(f, xdata);
    A2 = splineA(g, xdata);
    
    ff = spline(A1, xdata, xx);
    gg = spline(A2, xdata, xx);
    
    hold on;
    plot(ff,gg, 'Color', [n/160 0 0], 'DisplayName', '样条插值(n='+string(n)+')');
end
legend

样条函数的编写

function y = spline(A, xdata, x)
    %根据系数A和xdata复原的三次样条函数求x处的值
    m = length(xdata); %获取长度
    num = length(x);
    y = zeros(1,num);
    for k = 1:num
        for i = 1:m-1
            if (xdata(i)<= x(k) && x(k)<=xdata(i+1))
                %计算S_i(x)
                y(k) = A(4,i);
                for j = 1:3
                    y(k) = A(4-j, i) + (x(k)-xdata(i))*y(k);
                end
            end
        end
    end
end

function A = splineA(f, xdata)
    % 获取三次样条函数的系数A_{k,i}.
    n = length(xdata) - 1;
    h = xdata(2)-xdata(1);
    % 创建矩阵 H
    H = diag(4*ones(n,1),0)+diag(ones(n-1,1),1)+diag(ones(n-1,1),-1);
    H(1,n) = 1;
    H(n,1) = 1;
    
    % 创建向量 d
    d = zeros(n,1);
    for i = 1:n-1
        d(i) = (f(xdata(i+2))-f(xdata(i)))/h;
    end
    d(n) = ( f(xdata(2))-f(xdata(1)) - (f(xdata(n+1))-f(xdata(n))) )/h;
    H = sparse(H); %稀疏化
    m = H\d; %解方程组
    
    mtmp = m(n);
    m = [mtmp; m]; %变成n+1维向量
    
    %装配A_{1,i}
    A = zeros(4,n);
    for i = 1:n
        A(1,i) = f(xdata(i));
        A(2,i) = (f(xdata(i+1))-f(xdata(i)))/h-h/6*(m(i)+2*m(i+1));
        A(3,i) = m(i)/2;
        A(4,i) = (m(i+1)-m(i))/6/h;
    end
end