02-幂基曲线(1)
本文属于 “NURBS学习笔记” 专栏,更多文章可以点击↓↓↓
NURBS学习笔记专栏
1. 什么是幂基曲线
上一节中给出了一条在二维平面上首尾相接的参数曲线,我们把它从 u v uv uv 参数域放到一般的平面域。本节重点研究的就是这类曲线。
C ( u ) = { x ( u ) = 16 u 4 − 22 u 3 + u 2 + 5 u + 1 y ( u ) = 64 u 4 − 126 u 3 + 61 u 2 + u + 1 0 ≤ u ≤ 1 (1) \mathbf{C}\left(u\right)=\left\{\begin{matrix}\begin{aligned} x\left(u\right)&=16u^4-22u^3+u^2+5u+1 \\ y\left(u\right)&=64u^4-126u^3+61u^2+u+1 \end{aligned} \end{matrix} \right. \quad 0\le u \le 1 \tag{1} C(u)={x(u)y(u)=16u4−22u3+u2+5u+1=64u4−126u3+61u2+u+10≤u≤1(1)
用矢量形式将这条曲线可以改写得更优雅一些:
C ( u ) = ( 16 64 ) u 4 + ( − 22 − 126 ) u 3 + ( 1 61 ) u 2 + ( 5 1 ) u + ( 1 1 ) = a 4 u 4 + a 3 u 3 + a 2 u 2 + a 1 u + a 0 = ∑ i = 0 4 a i u i 0 ≤ u ≤ 1 (2) \begin{aligned} \mathbf{C}(u)&=\begin{pmatrix}16\\64\end{pmatrix}u^4+\begin{pmatrix}-22\\-126\end{pmatrix}u^3 +\begin{pmatrix}1\\61\end{pmatrix}u^2+\begin{pmatrix}5\\1\end{pmatrix}u+\begin{pmatrix}1\\1\end{pmatrix}\\ &=\mathbf{a}_4u^4+\mathbf{a}_3u^3+\mathbf{a}_2u^2+\mathbf{a}_1u+\mathbf{a}_0 \\ &=\sum_{i=0}^{4}\mathbf{a}_iu^i \end{aligned} \quad 0\le u \le 1 \tag{2} C(u)=(1664)u4+(−22−126)u3+(161)u2+(51)u+(11)=a4u4+a3u3+a2u2+a1u+a0=i=0∑4aiui0≤u≤1(2)
形如上式的曲线都可以称之为 幂基曲线 ,即曲线由一个和式表示:和式的每一项对应参数的幂乘上一个二维(或三维)的点。更一般的定义如下式。
C ( u ) = ∑ i = 0 n a i u i 0 ≤ u ≤ 1 (3) \mathbf{C}(u)=\sum_{i=0}^{n}\mathbf{a}_iu^i \quad 0\le u \le 1 \tag{3} C(u)=i=0∑naiui0≤u≤1(3)
一条幂基曲线有一个次数
n
n
n ,当
n
n
n 取定时,我们就得到了定义在参数域
u
∈
[
0
,
1
]
u\in[0,1]
u∈[0,1] 内的一组基函数
[
1
,
u
,
u
2
,
…
,
u
n
]
[{1,u,u^2,\dots,u^n}]
[1,u,u2,…,un] 。对于某个参数域内确定的
u
u
u (我们标记为
u
∗
u^*
u∗ ),基函数次数越小,其值越大。也就是说我们对
a
0
,
a
1
,
a
2
,
…
,
a
n
{\mathbf{a}_0,\mathbf{a}_1,\mathbf{a}_2,\dots,\mathbf{a}_n}
a0,a1,a2,…,an 做了线性组合,并且组合系数依次递减,从而得到了
C
(
u
∗
)
\mathbf{C}(u^*)
C(u∗) 。我们也能够对单个的
x
x
x 或者
y
y
y 坐标系进行分析,假如单独取
x
x
x 坐标,则对于任意时刻
u
∗
u^*
u∗,我们能够求出曲线的
x
x
x 坐标:
C
(
u
)
x
=
a
0
x
+
a
1
x
u
1
+
⋯
+
a
n
x
u
n
(4)
\mathbf{C}(u)^x=\mathbf{a}_0^x+\mathbf{a}_1^x{u}^1+\dots+\mathbf{a}_n^x{u}^n \tag{4}
C(u)x=a0x+a1xu1+⋯+anxun(4)
y
y
y 坐标亦然。当然了,
a
i
\mathbf{a}_i
ai 也可以是三维矢量,这样的话幂基曲线就定义在三维空间了。下图动态展示了公式
(
2
)
(2)
(2) 的幂基曲线的形成过程。
2. 幂基曲线的创建
当有了幂基曲线的表达形式后,我们首先考虑的就是:我该怎样得到一条幂基曲线:意即我怎么确定一条幂基曲线的 次数 和 系数 。在实际应用中,应该没有人在缺乏几何交互的情况下就能够确定出一根幂基曲线。大多数人想到的都是:我通过鼠标在屏幕上勾画几个点,然后通过这些点的一条幂基曲线就生成了。那就这么办。在正式开始之前,思考两个问题:
(1)假设确定出的点依次是: p 0 , p 1 , … , p m \mathbf{p}_0,\mathbf{p}_1,\dots,\mathbf{p}_m p0,p1,…,pm ,共计 m + 1 m+1 m+1 个,一个自然的想法是:当 u = 0 u=0 u=0 时,曲线上的点是 p 0 \mathbf{p}_0 p0 ,当 u = 1 u=1 u=1 时,曲线上的点是 p m \mathbf{p}_m pm 。那中间的那些点呢,它们对应的参数值是多少,或许你还会想到:等距分布就行了,那么 p i \mathbf{p}_i pi 对应的参数是 i / m {i}/{m} i/m ,这是唯一的选择吗,还有无更好的方法?
(2)当确定出了 m + 1 m+1 m+1 个点,幂基曲线的次数是多少,是要一直跟随点的个数增长吗?
2.1 数据点参数化问题
第一个问题实际上是 数据点参数化 问题。我们想象一部沿着曲线行驶的车, u = 0 u=0 u=0 的时刻,它确实在 p 0 \mathbf{p}_0 p0 , u = 1 u=1 u=1 的时刻,它也确实出现在 p m \mathbf{p}_m pm 。而中间还有许多里程碑节点( p 1 \mathbf{p}_1 p1 到 p m − 1 \mathbf{p}_{m-1} pm−1 )需要依次经过,但是具体在哪个时刻通过却是未知的,这是需要我们尽可能依据这些里程碑节点的空间分布情况去确定的。如果我们仅仅采用等距分布( 均匀参数化 ,或称 等距参数化 )的方法,无疑将里程碑节点的某些空间信息遗弃了,如果里程碑节点分布疏密不均,那么按照均匀参数化的方法,即要求每两个里程碑间的行车用时是相同的,那么这部车的速度一定是忽快忽慢的。
既然里程碑节点分布疏密不均,那么把两里程碑节点间的距离考虑在内将是一种更好的方法,距离远的节点间就多配置一些时间。这就是 积累弦长参数化 。
均匀参数化的公式为(暂未均一化到
[
0
,
1
]
[0,1]
[0,1] ):
u
i
=
i
,
i
=
0
,
1
,
…
,
m
(5)
u_i=i,\quad i=0,1,\dots,m \tag{5}
ui=i,i=0,1,…,m(5)
积累弦长参数化公式为(暂未均一化到 [ 0 , 1 ] [0,1] [0,1] ):
{ u 0 = 0 u i = u i − 1 + ∣ p i − p i − 1 ∣ i = 0 , 1 , … , m (6) \left\{\begin{matrix}\begin{aligned} u_0&=0 \\ u_i&=u_{i-1} + \left | \mathbf{p}_i-\mathbf{p}_{i-1}\right | \end{aligned}\end{matrix}\right. \quad i=0,1,\dots,m \tag{6} {u0ui=0=ui−1+∣pi−pi−1∣i=0,1,…,m(6)
上述公式所得参数化均不在
[
0
,
1
]
[0,1]
[0,1] 内,我们需要使用
u
i
n
e
w
=
u
i
max
u
i
i
=
0
,
1
,
…
,
m
(7)
u_i^{new}=\frac{u_i}{\max{u_i}} \quad i=0,1,\dots,m \tag{7}
uinew=maxuiuii=0,1,…,m(7)
将其归一化到
[
0
,
1
]
[0,1]
[0,1] 。
2.2 插值和逼近
现在我们已经拥有了点 [ p 0 , p 1 , … , p m ] [\mathbf{p}_0,\mathbf{p}_1,\dots,\mathbf{p}_m] [p0,p1,…,pm] ,以及一个确定好的参数化结果 [ u 0 , u 1 , … , u m ] [u_0,u_1,\dots,u_m] [u0,u1,…,um] ,我们可以根据公式 ( 3 ) (3) (3) 列方程了。
{ a 0 + a 1 u 0 + a 2 u 0 2 + ⋯ + a n u 0 n = p 0 a 0 + a 1 u 1 + a 2 u 1 2 + ⋯ + a n u 1 n = p 1 ⋮ a 0 + a 1 u m + a 2 u m 2 + ⋯ + a n u m n = p m (8) \left\{ \begin{array}{c}\begin{aligned} \mathbf{a}_0+\mathbf{a}_1u_0+\mathbf{a}_2{u_0}^2+\cdots +\mathbf{a}_n{u_0}^n&=\mathbf{p}_0\ \,\,\\ \mathbf{a}_0+\mathbf{a}_1u_1+\mathbf{a}_2{u_1}^2+\cdots +\mathbf{a}_n{u_1}^n&=\mathbf{p}_1\\ \vdots\\ \mathbf{a}_0+\mathbf{a}_1u_m+\mathbf{a}_2{u_m}^2+\cdots +\mathbf{a}_n{u_m}^n&=\mathbf{p}_m\\ \end{aligned}\end{array} \right. \tag{8} ⎩ ⎨ ⎧a0+a1u0+a2u02+⋯+anu0na0+a1u1+a2u12+⋯+anu1n⋮a0+a1um+a2um2+⋯+anumn=p0 =p1=pm(8)
方程 ( 8 ) (8) (8) 是一个未知数为 a 0 , a 1 , … , a n \mathbf{a}_0,\mathbf{a}_1,\dots,\mathbf{a}_n a0,a1,…,an 的线性方程,尽管 a i \mathbf{a}_i ai 是一个矢量,但其实我们可以在实际求解时仅考虑某一个坐标,比如单独将 x x x 坐标拎出来,上述方程就变为
{ a 0 x + a 1 x u 0 + a 2 x u 0 2 + ⋯ + a n x u 0 n = p 0 x a 0 x + a 1 x u 1 + a 2 x u 1 2 + ⋯ + a n x u 1 n = p 1 x ⋮ a 0 x + a 1 x u m + a 2 x u m 2 + ⋯ + a n x u m n = p m x (9) \left\{ \begin{array}{c}\begin{aligned} \mathbf{a}_0^x+\mathbf{a}_1^xu_0+\mathbf{a}_2^x{u_0}^2+\cdots +\mathbf{a}_n^x{u_0}^n&=\mathbf{p}_0^x\ \,\,\\ \mathbf{a}_0^x+\mathbf{a}_1^xu_1+\mathbf{a}_2^x{u_1}^2+\cdots +\mathbf{a}_n^x{u_1}^n&=\mathbf{p}_1^x\\ \vdots\\ \mathbf{a}_0^x+\mathbf{a}_1^xu_m+\mathbf{a}_2^x{u_m}^2+\cdots +\mathbf{a}_n^x{u_m}^n&=\mathbf{p}_m^x\\ \end{aligned}\end{array} \right. \tag{9} ⎩ ⎨ ⎧a0x+a1xu0+a2xu02+⋯+anxu0na0x+a1xu1+a2xu12+⋯+anxu1n⋮a0x+a1xum+a2xum2+⋯+anxumn=p0x =p1x=pmx(9)
这就是我们非常熟悉的线性方程了,后续分析过程中,我们就直接对公式 ( 8 ) (8) (8) 进行操作,隐含的一层含义就是:各个坐标系的求解过程都是一样的,我们统一用矢量来表示(矢量表示的公式看起来会更加复杂,但也只是形式上复杂了)。
到目前为止,我们还未指定需要求解的幂基曲线次数 n n n ,所以方程 ( 8 ) (8) (8) 的未知数的个数 n + 1 n+1 n+1 (幂基曲线次数加1)也未确定,而方程的个数为 m + 1 m+1 m+1 (点的个数)。那么当我们指定了次数后,就存在下面三种情况:
- 当 m < n m<n m<n 时,点的个数小于曲线的次数加1,方程组将求不出唯一解。也就是说你给的曲线次数很高,当前的点难以还原曲线的全部信息;
- 当 m = n m=n m=n 时,点的个数等于曲线的次数加1,方程组将有唯一解。也就是说你给的曲线次数和当前的点恰好匹配,刚好可以还原曲线的全部信息;
- 当 m > n m>n m>n 时,点的个数大于曲线的次数加1,方程组将无解。也就是说你给的曲线次数难以同时通过所有点。
2.2.1 插值
对于
m
<
n
m<n
m<n 的情况,曲线是确定不了的。这种情况下,我们需要再补充一些额外的条件:
比如当
n
=
2
,
m
=
1
n=2,m=1
n=2,m=1,即要求取
2
2
2 次幂基曲线的
3
3
3 个系数系数
a
0
\mathbf{a}_0
a0、
a
1
\mathbf{a}_1
a1、
a
2
\mathbf{a}_2
a2,我们仅知道其通过了
2
2
2 个点
[
p
0
,
p
1
]
[\mathbf{p}_0,\mathbf{p}_1]
[p0,p1] ),我们可以再补充一个点(假如当
u
=
u
2
u=u_2
u=u2 时通过了
p
3
\mathbf{p}_3
p3),这样其实就转换成了
m
=
n
m=n
m=n 的情况。
{
a
0
+
a
1
u
0
+
a
2
u
0
2
=
p
0
a
0
+
a
1
u
1
+
a
2
u
1
2
=
p
1
a
0
+
a
1
u
2
+
a
2
u
2
2
=
p
3
(10)
\left\{\begin{matrix}\begin{aligned} \mathbf{a}_0+\mathbf{a}_1u_0+\mathbf{a}_2{u_0}^2 = \mathbf{p}_0 \\ \mathbf{a}_0+\mathbf{a}_1u_1+\mathbf{a}_2{u_1}^2 = \mathbf{p}_1 \\ \color{red}\mathbf{a}_0+\mathbf{a}_1u_2+\mathbf{a}_2{u_2}^2 = \mathbf{p}_3 \end{aligned}\end{matrix} \right. \tag{10}
⎩
⎨
⎧a0+a1u0+a2u02=p0a0+a1u1+a2u12=p1a0+a1u2+a2u22=p3(10)
或者可以补充在某个参数( u 2 u_2 u2)下的一阶导矢( D 2 \mathbf{D}_2 D2)
{ a 0 + a 1 u 0 + a 2 u 0 2 = p 0 a 0 + a 1 u 1 + a 2 u 1 2 = p 1 a 1 + 2 a 2 u 2 = D 2 (11) \left\{\begin{matrix}\begin{aligned} \mathbf{a}_0+\mathbf{a}_1u_0+\mathbf{a}_2{u_0}^2 &= \mathbf{p}_0 \\ \mathbf{a}_0+\mathbf{a}_1u_1+\mathbf{a}_2{u_1}^2 &= \mathbf{p}_1 \\ \color{red}\mathbf{a}_1+2\mathbf{a}_2{u_2} &\color{red}= \mathbf{D}_2 \end{aligned}\end{matrix} \right. \tag{11} ⎩ ⎨ ⎧a0+a1u0+a2u02a0+a1u1+a2u12a1+2a2u2=p0=p1=D2(11)
或者可以补充在某个参数( u 2 u_2 u2)下的二阶导矢( D 2 \mathbf{D}_2 D2)
{ a 0 + a 1 u 0 + a 2 u 0 2 = p 0 a 0 + a 1 u 1 + a 2 u 1 2 = p 1 2 a 2 = D 2 (12) \left\{\begin{matrix}\begin{aligned} \mathbf{a}_0+\mathbf{a}_1u_0+\mathbf{a}_2{u_0}^2 &=\mathbf{p}_0 \\ \mathbf{a}_0+\mathbf{a}_1u_1+\mathbf{a}_2{u_1}^2 &=\mathbf{p}_1 \\ \color{red}2\mathbf{a}_2 &\color{red}= \mathbf{D}_2 \end{aligned}\end{matrix} \right. \tag{12} ⎩ ⎨ ⎧a0+a1u0+a2u02a0+a1u1+a2u122a2=p0=p1=D2(12)
对于二次曲线而言,更高阶的导矢都是 0 \mathbf{0} 0 了,是不能作为条件给出的。
再比如当 n = 3 , m = 1 n=3,m=1 n=3,m=1,即要求取 3 3 3 次幂基曲线的 4 4 4 个系数 [ a 0 , a 1 , a 2 , a 3 ] [\mathbf{a}_0,\mathbf{a}_1,\mathbf{a}_2,\mathbf{a}_3] [a0,a1,a2,a3] ,我们仅知道其通过了 2 2 2 个点( p 0 \mathbf{p}_0 p0、 p 1 \mathbf{p}_1 p1),我们可以再补充两个点位,这样其实就转换成了 m = n m=n m=n 的情况。
{ a 0 + a 1 u 0 + a 2 u 0 2 + a 3 u 0 3 = p 0 a 0 + a 1 u 1 + a 2 u 1 2 + a 3 u 1 3 = p 1 a 0 + a 1 u 2 + a 2 u 2 2 + a 3 u 2 3 = p 2 a 0 + a 1 u 3 + a 2 u 3 2 + a 3 u 3 3 = p 3 (13) \left\{\begin{matrix}\begin{aligned} \mathbf{a}_0+\mathbf{a}_1u_0+\mathbf{a}_2{u_0}^2+\mathbf{a}_3{u_0}^3 &= \mathbf{p}_0 \\ \mathbf{a}_0+\mathbf{a}_1u_1+\mathbf{a}_2{u_1}^2+\mathbf{a}_3{u_1}^3 &= \mathbf{p}_1 \\ \color{red}\mathbf{a}_0+\mathbf{a}_1u_2+\mathbf{a}_2{u_2}^2+\mathbf{a}_3{u_2}^3 &\color{red}= \mathbf{p}_2 \\ \color{red}\mathbf{a}_0+\mathbf{a}_1u_3+\mathbf{a}_2{u_3}^2+\mathbf{a}_3{u_3}^3 &\color{red}= \mathbf{p}_3 \\ \end{aligned}\end{matrix} \right. \tag{13} ⎩ ⎨ ⎧a0+a1u0+a2u02+a3u03a0+a1u1+a2u12+a3u13a0+a1u2+a2u22+a3u23a0+a1u3+a2u32+a3u33=p0=p1=p2=p3(13)
或者可以补充在某两个参数下的一阶导矢,这种情况下,我们一般选择的点是曲线首尾两个端点的一阶导矢( D 0 \mathbf{D}_0 D0、 D 1 \mathbf{D}_1 D1)。
{ a 0 + a 1 u 0 + a 2 u 0 2 + a 3 u 0 3 = p 0 a 0 + a 1 u 1 + a 2 u 1 2 + a 3 u 1 3 = p 1 a 1 + 2 a 2 u 0 + 3 a 3 u 0 2 = D 0 a 1 + 2 a 2 u 0 + 3 a 3 u 1 2 = D 1 (14) \left\{\begin{matrix}\begin{aligned} \mathbf{a}_0+\mathbf{a}_1u_0+\mathbf{a}_2{u_0}^2+\mathbf{a}_3{u_0}^3 &= \mathbf{p}_0 \\ \mathbf{a}_0+\mathbf{a}_1u_1+\mathbf{a}_2{u_1}^2+\mathbf{a}_3{u_1}^3 &= \mathbf{p}_1 \\ \color{red}\mathbf{a}_1+2\mathbf{a}_2{u_0}+3\mathbf{a}_3{u_0}^2 &\color{red}= \mathbf{D}_0 \\ \color{red}\mathbf{a}_1+2\mathbf{a}_2{u_0}+3\mathbf{a}_3{u_1}^2 &\color{red}= \mathbf{D}_1 \\ \end{aligned}\end{matrix} \right. \tag{14} ⎩ ⎨ ⎧a0+a1u0+a2u02+a3u03a0+a1u1+a2u12+a3u13a1+2a2u0+3a3u02a1+2a2u0+3a3u12=p0=p1=D0=D1(14)
二、三阶导矢也可以作为条件给出。对于三次曲线而言,三阶导矢是固定的 6 a 3 6\mathbf{a}_3 6a3,更高阶的导矢都是 0 \mathbf{0} 0 了。这些情况我们就不再罗列具体的公式。
公式
(
14
)
(14)
(14) 的使用度较高。这种情况给定的
4
4
4 个条件都有明显的几何意义。也就是说,我们可以直观地修改这些条件,从而调整曲线的样子。这种调整具有很好的几何直观。如下图所示,分别对
4
4
4 个条件做了调整,可以看到曲线跟随调整的意图也发生了改变。我们也应看到:当我们对幂基函数的某个细节进行调整时,总是“牵一发而动全身”,只不过受影响的程度有轻重之分。想象下曲线的设计过程:一个设计者在对某些局部修改满意后,再去调整其他部分,却发现已修改的部分也发生移动了。我们先初步感受下幂基曲线的此种劣势。
当我们对
m
<
n
m<n
m<n 的情况补充上条件后,就可以进行求解,获得唯一的参数曲线。这个过程称之为插值,当补充的条件含有导矢条件时,就是埃尔米特插值。
对于 m = n m=n m=n 的情况,我们直接求解方程 ( 4 ) (4) (4) 即可。下图中给出了一个例子,即在第一象限的 1 / 4 1/4 1/4 单位圆弧上按照逆时针随机采点,然后采用幂基曲线进行插值。同时对比了均匀和积累弦长两种参数化对插值结果的影响。从图中可以看出:积累弦长参数化比均匀参数化的效果要更好,尤其是在采样点分布不均时;另一方面,随着所采用的插值曲线次数的增加,不管采用哪种参数化方式,插值结果都开始发生明显的扭曲了。我们在图中还基于均匀参数化进行了三次样条插值,它的结果非常好。即使次数很高,也没有让插值结果发生大的扭曲。
三次样条插值 和本节我们所用的插值有什么区别呢?我们想一下:当使用较高的次数进行插值时,我们得到的插值结果具有无穷阶连续,意即曲线的任意阶导矢都是连续的。但我们需要这么高的连续性吗?从几何直观的角度来看,两条曲线在端点处拼接在一起,我们是能够感知到在这个连接点处是否“光滑”:如果在拼接点处的两条曲线在拼接点处的一阶导同向,我们就感觉到曲线是光滑的;从应用的角度来看,更高阶的连续对后续应用的计算无益,是一种浪费。出于这种考虑,我们想能否将曲线打成一段一段的,仅保证段与段之间一定程度的连续就够了。这样的话,每一段都将用次数不高的曲线来插值。这就是样条插值的基本思想,即在损失连续性的前提下,对整体曲线采用多个局部片段表示的方法。关于样条插值我们不再赘述了。大家可以参考其他的资料。
2.2.2 逼近
对于 m > n m>n m>n 的情况,提高曲线的次数是一个解决办法,这就又回到了 m = n m=n m=n 的情况,那在不改变次数 n n n 的前提下,有无其他的办法呢?既然当前的次数难以完美地同时通过所有的点,那退而求其次,将这个条件折中行不行?怎样才算是“折中”——寻找到一条次数为 n n n 的曲线,所有的点不会同时落在曲线上了,那他们和曲线间都存在一个距离,让所有的距离加和取得最小值或者让其中最大的距离最小,这看起来是可行的办法。这其实就是我们常说的 最小二乘 的基本思想——对苛刻条件的一种让步。后文我们将对此进行详细讨论。在实际的操作过程中,我们并不是选择距离加和最小,也没有选择最大的距离最小,而是用距离的平方加和最小(这才是最小二乘名称的由来,“二乘“源自日语,即”平方“)来处理。
当采用最小二乘法处理 m > n m>n m>n 的情况时,我们一般称之为 逼近。
我们仍以上述 1 / 4 1/4 1/4 圆弧采点进行插值的数据为例,对最小二乘法逼近就行说明。假设圆弧上采样了 10 10 10 个点 [ p 0 , p 1 , … , p 9 ] [\mathbf{p}_0,\mathbf{p}_1,\dots,\mathbf{p}_9] [p0,p1,…,p9] ,如果以 9 9 9 次幂基曲线进行插值,就是上述 m = n m=n m=n 的情况。为了避免发生高次曲线的扭曲,我们逼近的曲线次数小于 9 9 9 。
{ a 0 + a 1 u 0 + a 2 u 0 2 + ⋯ + a n u 0 n = p 0 a 0 + a 1 u 1 + a 2 u 1 2 + ⋯ + a n u 1 n = p 1 ⋮ a 0 + a 1 u 9 + a 2 u 9 2 + ⋯ + a n u 9 n = p 9 ⇒ ( 1 u 0 u 0 2 … u 0 n 1 u 1 u 1 2 … u 1 n ⋮ ⋮ ⋮ ⋱ ⋮ 1 u 9 u 9 2 … u 9 n ) ( a 0 a 1 ⋮ a n ) = ( p 0 p 1 ⋮ p n ) ⇒ U A = P (15) \left\{\begin{matrix}\begin{aligned} \mathbf{a}_0+\mathbf{a}_1u_0+\mathbf{a}_2{u_0}^2+\cdots +\mathbf{a}_n{u_0}^n&=\mathbf{p}_0\ \,\,\\ \mathbf{a}_0+\mathbf{a}_1u_1+\mathbf{a}_2{u_1}^2+\cdots +\mathbf{a}_n{u_1}^n&=\mathbf{p}_1\\ \vdots\\ \mathbf{a}_0+\mathbf{a}_1u_9+\mathbf{a}_2{u_9}^2+\cdots +\mathbf{a}_n{u_9}^n&=\mathbf{p}_9\\ \end{aligned}\end{matrix} \right. \\ \Rightarrow \begin{pmatrix} 1 & u_0 & {u_0}^2 & \dots & {u_0}^n \\ 1 & u_1 & {u_1}^2 & \dots & {u_1}^n \\ \vdots&\vdots&\vdots&\ddots&\vdots \\ 1 & u_9 & {u_9}^2 & \dots & {u_9}^n \\ \end{pmatrix} \begin{pmatrix} \mathbf{a}_0 \\ \mathbf{a}_1 \\ \vdots \\ \mathbf{a}_n \\ \end{pmatrix}= \begin{pmatrix} \mathbf{p}_0 \\ \mathbf{p}_1 \\ \vdots \\ \mathbf{p}_n \\ \end{pmatrix} \\ \Rightarrow \mathbf{U}\mathbf{A}=\mathbf{P} \tag{15} ⎩ ⎨ ⎧a0+a1u0+a2u02+⋯+anu0na0+a1u1+a2u12+⋯+anu1n⋮a0+a1u9+a2u92+⋯+anu9n=p0 =p1=p9⇒ 11⋮1u0u1⋮u9u02u12⋮u92……⋱…u0nu1n⋮u9n a0a1⋮an = p0p1⋮pn ⇒UA=P(15)
对于方程 ( 15 ) (15) (15) ,我们已经确知其无解。我们可以从线性组合的几何意义的角度来思考方程 ( 15 ) (15) (15),对其进行适当变形,有
( 1 u 0 u 0 2 … u 0 n 1 u 1 u 1 2 … u 1 n ⋮ ⋮ ⋮ ⋱ ⋮ 1 u 9 u 9 2 … u 9 n ) ( a 0 a 1 ⋮ a n ) = ( p 0 p 1 ⋮ p n ) ⇒ ( 1 1 ⋮ 1 ) a 0 + ( u 0 u 1 ⋮ u 9 ) a 1 + ⋯ + ( u 0 n u 1 n ⋮ u 9 n ) a n ⇒ u 0 a 0 + u 1 a 1 + ⋯ + u n a n = P (16) \begin{pmatrix} 1 & u_0 & {u_0}^2 & \dots & {u_0}^n \\ 1 & u_1 & {u_1}^2 & \dots & {u_1}^n \\ \vdots&\vdots&\vdots&\ddots&\vdots \\ 1 & u_9 & {u_9}^2 & \dots & {u_9}^n \\ \end{pmatrix} \begin{pmatrix} \mathbf{a}_0 \\ \mathbf{a}_1 \\ \vdots \\ \mathbf{a}_n \\ \end{pmatrix}= \begin{pmatrix} \mathbf{p}_0 \\ \mathbf{p}_1 \\ \vdots \\ \mathbf{p}_n \\ \end{pmatrix} \\ \Rightarrow \begin{pmatrix} 1 \\ 1 \\ \vdots \\ 1 \\ \end{pmatrix}\mathbf{a}_0 + \begin{pmatrix} {u_0} \\ {u_1} \\ \vdots \\ {u_9} \\ \end{pmatrix}\mathbf{a}_1 + \dots + \begin{pmatrix} {u_0}^n \\ {u_1}^n \\ \vdots \\ {u_9}^n \\ \end{pmatrix}\mathbf{a}_n \\ \Rightarrow \mathbf{u}_0\mathbf{a}_0+\mathbf{u}_1\mathbf{a}_1+\dots+\mathbf{u}_n\mathbf{a}_n=\mathbf{P} \tag{16} 11⋮1u0u1⋮u9u02u12⋮u92……⋱…u0nu1n⋮u9n a0a1⋮an = p0p1⋮pn ⇒ 11⋮1 a0+ u0u1⋮u9 a1+⋯+ u0nu1n⋮u9n an⇒u0a0+u1a1+⋯+unan=P(16)
即我们要在 u 0 , u 1 , … , u n {\mathbf{u}_0,\mathbf{u}_1,\dots,\mathbf{u}_n} u0,u1,…,un 张成的空间中找到一组系数 a 0 , a 1 , … , a n {\mathbf{a}_0,\mathbf{a}_1,\dots,\mathbf{a}_n} a0,a1,…,an,使得 u 0 , u 1 , … , u n {\mathbf{u}_0,\mathbf{u}_1,\dots,\mathbf{u}_n} u0,u1,…,un 在这组系数下的线性组合是 P \mathbf{P} P 。
我们是不可能找到这样的系数组合的。可以类比下面的例子。有向量 u 0 = [ 1 , 0 ] T \mathbf{u}_0=[1,0]^{T} u0=[1,0]T , u 1 = [ 0 , 1 ] T \mathbf{u}_1=[0,1]^{T} u1=[0,1]T , U = [ u 0 , u 1 ] \mathbf{U}=[\mathbf{u}_0,\mathbf{u}_1] U=[u0,u1],我们要找到一组系数 [ a 0 , a 1 ] [a_0,a_1] [a0,a1] 使得 u 0 a 0 + u 1 a 1 = P = ( 1 , 1 , 1 ) T \mathbf{u}_0a_0+\mathbf{u}_1a_1=\mathbf{P}=(1,1,1)^{T} u0a0+u1a1=P=(1,1,1)T 。我们能做的是在 u 0 , u 1 \mathbf{u}_0,\mathbf{u}_1 u0,u1 张成的空间中找到一组 A = [ a 0 , a 1 ] T \mathbf{A} = [a_0,a_1]^{T} A=[a0,a1]T 使得 P ∗ = u 0 a 0 + u 1 a 1 = U A \mathbf{P}^{*}=\mathbf{u}_0a_0+\mathbf{u}_1a_1=\mathbf{U}\mathbf{A} P∗=u0a0+u1a1=UA 距离 P \mathbf{P} P 最近。从几何上看,即 P − P ∗ \mathbf{P}-\mathbf{P}^{*} P−P∗ 与 u 0 \mathbf{u}_0 u0 和 u 1 \mathbf{u}_1 u1 垂直,即 u 0 T ⋅ ( P − P ∗ ) = 0 \mathbf{u}_0^{T}\cdot(\mathbf{P}-\mathbf{P}^{*})=0 u0T⋅(P−P∗)=0 和 u 1 T ⋅ ( P − P ∗ ) = 0 \mathbf{u}_1^{T}\cdot(\mathbf{P}-\mathbf{P}^{*})=0 u1T⋅(P−P∗)=0 ,可以写作 U T ⋅ ( P − P ∗ ) = U T ⋅ ( P − U A ) = 0 \mathbf{U}^{T}\cdot(\mathbf{P}-\mathbf{P}^{*})=\mathbf{U}^{T}\cdot(\mathbf{P}-\mathbf{U}\mathbf{A})=0 UT⋅(P−P∗)=UT⋅(P−UA)=0 ,从而有 A = ( U T U ) − 1 U T P \mathbf{A}=(\mathbf{U}^{T}\mathbf{U})^{-1}\mathbf{U}^{T}\mathbf{P} A=(UTU)−1UTP 。
A
=
(
U
T
U
)
−
1
U
T
P
\mathbf{A}=(\mathbf{U}^{T}\mathbf{U})^{-1}\mathbf{U}^{T}\mathbf{P}
A=(UTU)−1UTP 同样适用于公式
(
15
)
(15)
(15) 。给定了采样点,我们就能得到
P
\mathbf{P}
P ,给定了逼近的曲线次数
n
n
n 和合适的参数化,我们就能得到
U
\mathbf{U}
U 。从而得到逼近的幂基曲线的系数
A
\mathbf{A}
A 。
上图展示了用 1 − 9 1-9 1−9 次的幂基曲线依次逼近 10 10 10 个圆弧上采样点的结果。可以看到,随着所用逼近曲线次数的增加,距离平方和在逐渐减小,这也意味着曲线将逐渐向所有的点靠拢,直至采用了 9 9 9 次曲线,逼近曲线与逼近点的平方距离和为 0.0 0.0 0.0 ,这意味着曲线通过了所有的点。也可以将 9 9 9 次幂基曲线逼近 10 10 10 个点的情况理解为一种特殊的最小二乘,其实这是一种 m = n m=n m=n 的插值的情况。
到此为止,我们终于能够通过输入点和次数来构建幂基曲线。采用插值的方式能够确保结果通过所有的点,但是随着点数的增加,所需的次数也在增加,高次曲线会让曲线发生不可控的扭曲,此外高次曲线的计算成本也很高,此时可以采用低次样条插值;采用逼近的方式能够用较低次数的曲线(可以理解为结构比较简单)兼容更多的输入点信息。试想这样的应用场景:有一个翼型数据,是用离散点表示的,点数也很多,此时我们可以选择 低次样条曲线插值 或者 低次曲线逼近 。
我们选择 NACA 2414 翼型 ,其由61个数据点表示。我们用
3
3
3 次样条插值和
10
10
10 次最小二乘逼近来创建该翼型曲线,其结果分别是
60
60
60 个连续的
3
3
3 次幂基曲线和
1
1
1 个
10
10
10 次幂基曲线。可以看到,样条插值的效果要比最小二乘逼近好多了。如果用一个
60
60
60 次的幂基曲线直接插值呢?从数值稳定性的角度来看,在CAD中是很排斥高次曲线的,可以想象,让计算机计算一个数的
60
60
60 次方,再小的误差都会被放大。