第五章 常用插值算法
合集下载
相关主题
- 1、下载文档前请自行甄别文档内容的完整性,平台不提供额外的编辑、内容补充、找答案等附加服务。
- 2、"仅部分预览"的文档,不可在线预览部分如存在完整性等问题,可反馈申请退款(可完整预览的文档不适用该条件!)。
- 3、如文档侵犯您的权益,请联系客服反馈,我们会尽快为您处理(人工客服工作时间:9:00-18:30)。
第五章 常用插值算法
§5.1 线性插值算法
线性插值是代数插值的最简 单形式。假设变量 y 和自变量 x ,X G2Ï V Ò 5- 1 中 曲 线 y1 y y0 A f(x) B g(x)
Y
y = f ( x ) 所示。已知 y 在点 x0
和 x1 的对应值 y 0 和 y1 ;现在要 求 用 一 线 性 插 值 函 数
x0 和 x1 之间,称为内插,否则称为外插或外推。在这里,
我们只考虑内插。在进行插值运算前,还要考虑下面两个具体问题: 插值节点的选取:在单片机的应用中,往往把常用的函数以表格的形式固化在程序 存储器中。 例如某物理量的温度补偿值是非线性的, 表格中的值是在若干个温度点 实测得到的补偿值; 又比如等间距角度的正弦函数值组成的表格等等。 对于任一给 定的插值点 x ÈùEî›1T),X¤k.BnÔE¥,Xøþ¦&•
g ( x ) = y0 +
y1 − y 0 ( x − x0 ) x1 − x0
(点斜式)
或:
g ( x ) = y0 (
x −x x1 − x ) + y1 ( 0 ) x1 − x0 x0 − x1
(两点式)
由图 5- 1 也可以看出, 插值节点 x0 和 x1 之间的间距越小, 那么在这一区间 g ( x ) 与 f ( x ) 之间的误差就越小。若插值点 x ü
bp=sp+4; M_GetValue 6; push r3,r4 to [sp]; M_GetValue 3; push r3,r4 to [sp]; M_GetValue 2; push r3,r4 to [sp]; M_GetValue 1; push r3,r4 to [sp]; M_GetValue 0; push r3,r4 to [sp]; call F_LinearInsert; sp+=10; M_StoreValue 3; M_GetValue 6; push r3,r4 to [sp]; M_GetValue 5; push r3,r4 to [sp]; M_GetValue 4; push r3,r4 to [sp]; M_GetValue 1; push r3,r4 to [sp]; M_GetValue 0; push r3,r4 to [sp]; call F_LinearInsert; sp+=10; M_StoreValue 5; M_GetValue 6; push r3,r4 to [sp]; M_GetValue 5; push r3,r4 to [sp]; M_GetValue 4; push r3,r4 to [sp]; M_GetValue 3; push r3,r4 to [sp]; M_GetValue 2; push r3,r4 to [sp]; call F_LinearInsert; sp+=10; pop bp from [sp]; retf; .endp
(8.1)
第二步:过点 ( x0 , y 0 ) , ( x 2 , y 2 ) 作直线 L02 ,即
L02 = y 0 +
y 2 − y0 ( x − x0 ) x 2 − x0
(8.2)
第三步:将 ( x1 , L01 ) , ( x 2 , L02 ) 也理解为“点” ,过这两点作“直线” ,记之为 L012 , 即
M_StoreValue 4; M_GetValue 1; push r3,r4 to [sp]; M_GetValue 3; push r3,r4 to [sp]; call __subf2; sp+=4; M_StoreValue 3; M_GetValue 0; push r3,r4 to [sp]; M_GetValue 2; push r3,r4 to [sp]; call __subf2; sp+=4; M_StoreValue 2; M_GetValue 4; push r3,r4 to [sp]; M_GetValue 3; push r3,r4 to [sp]; call __mulf2; sp+=4; M_StoreValue 4; M_GetValue 2; push r3,r4 to [sp]; M_GetValue 4; push r3,r4 to [sp]; call __divf2; sp+=4; push r1,r2 to [sp]; M_GetValue 1; push r3,r4 to [sp]; call __addf2; sp+=4; pop bp from [sp]; retf; .endp
g ( xi ) = f ( x i )
其中: i = 0,1,2 ;
ax12 + bx1 + c = y1
2 + bx + c = y ax2 2 2
解此方程组可得 g ( x ) 的系数 a 、 b 和 c ,但是这样运算很麻烦。实际计算中,我们可 以把 g ( x ) 写成各种形式的二次多项式, 然后运用待定系数法把 g ( x ) 确定下来。 这些方法包 括抛物线插值的拉各朗日(Lagrange)形式,抛物线插值的牛顿(Newton)形式,逐次线性 插值法等。在这里,我们只讨论逐次线性插值法,因为它能充分利用前面线性插值程序,也 容易在计算机上实现。
(8.4)
不难看出, L012 是关于 x ,X`õÑDÈJè$µC‡sÆ-¹&•G2ÏÖ
L012 ( xi ) = y i
所以, L012 就是所要求的二次插值多项式 g ( x ) 。
(i = 0,1,2)
仔细观察式(8.4)后可以看出, ( y1 − y 0 ) ÷ ( x1 − x 0 ) 是一阶差商,而方括号内的分式 是二阶差商。式(8.3)是通过两个线性插值的结果获得 g ( x ) ,所以称为逐次线性插值。显 然,式(8.1) 、 (8.2)和(8.3)都是线性插值中的点斜式表达式,因此,可以直接调用前面 的线性插值程序。 因为只考虑内插,所以插值点 x h!b
5.2.2 逐次线性插值算法
已知三点 ( x0 , y 0 ) , ( x1 , y1 ) , ( x 2 , y 2 ) 及插值点的 x È"Íh,X 用直线点斜式公式: 第一步:过点 ( x0 , y 0 ) , ( x1 , y1 ) 作直线 L01 ,即
y 值。
L01 = y 0 +
y1 − y 0 ( x − x0 ) x1 − x0
L012 = L01 +
L02 − L01 ( x − x1 ) x 2 − x1
(8.3)
第四步:把式(8.1)和(8.2)代入式(8.3) ,得
L012
y 2 − y 0 y1 − y 0 x −x − x −x y1 − y 0 0 1 0 ( x − x0 )( x − x1 ) ( x − x0 ) + 2 = y0 + x1 − x0 x 2 − x1
//x-x0 存入参数 x //取 y0 //取 y1 //计算 y1-y0 //y1-y0 存入参数 y1 //取 x0 //取 x1 //计算 x1-x0 //x1-x0 存入参数 x1 //取 x,即 x-x0 //取 y1,即 y1-y0 //计算(x-x0)x(y1-y0) //(x-x0)x(y1-y0)存入参数 x //取 x1,即 x1-x0 //取 x,即(x-x0)x(y1-y0) //计算(x-x0)x(y1-y0)/(x1-x0)
g ( x ) = ax + b , 近似代替 f ( x ) 。
根据插值条件,应满足:
0
X x0 x x1
ax0 + b = y 0
ax1 + b = y1
图 5- 1 用直线拟合求准确峰位示意图
解该方程组,便可确定线性插值函数 g ( x ) 的参数 a 和 b 。由图可知,线性插值的几何意义 是用通过点 A( x0 , y 0 ) 和点 B ( x1 , y1 ) 的直线近似地代替曲线 y = f ( x ) 。我们很容易求得该 直线表达式:
[x0 , x2 ]的区间内。当我们将三个节点的坐标和
插值点的横坐标代入下面的程序后,就可以得到插值点的函数近似值。 //====================================================== // 程序名称: F_QuadraticInsert // 功能描述: 实现逐次线性插值算法: // 1、计算 L01=y0+(y1-y0)(x-x0)/(x1-x0) // 2、计算 L02=y0+(y2-y0)(x-x0)/(x2-x0) // 3、计算 L012=L01+(L02-L01)(x-x1)/(x2-x1) // 输入: 浮点数 x0,y0,x1,y1,x2,y2,x // 输出: 浮点数 y->r1,r2 // 破坏: r1,r2,r3,பைடு நூலகம்4; // 使用: r1,r2,r3,r4,bp,sp; // 占用堆栈: 28; //====================================================== .public F_QuadraticInsert; .public _F_QuadraticInsert; F_QuadraticInsert: _F_QuadraticInsert: .proc push bp to [sp];
g( x)
Y A B
f ( x)
C
X
0
x0
x1
图 5- 2 抛物线插值示意图
x2
C ( x2 , y 2 ) ; 过此三点可以作一
抛物线,即一条二次曲线
g ( x ) ,且是唯一的。
设: 已知: 由此可得下列方程组:
2 + bx + c = y ax0 0 0
g ( x ) = ax 2 + bx + c
//取 y0 //计算(x-x0)x(y1-y0)/(x1-x0)+y0
§5.2 抛物线插值算法
5.2.1 算法概述
抛物线插值又称为二次插 值,它是以一元二次多项式去 拟合某一段曲线。精度自然要 比线性插值高。 如图 5- 2 所示, 已 知 一 条 曲线 y = f ( x ) 上 的 三点 A( x0 , y 0 ) , B ( x1 , y1 ) ,
x0 和 x1 以及在表中对 y 值。
应的函数值 y 0 和 y1 ,然后就可以进行插值运算,求得插值点 x Íh,X
为了提高插值精度,大多数情况下都是采用浮点运算,因此参与插值运算的数据和 表格应事先转换成规格化浮点。 以点斜式线性插值算法为例, 当给定两个插值点的坐标后, 就可以通过如下插值算法得 到插值点的函数近似值: 首先定义宏如下: M_GetValue: .MACRO Index //参数 Index=0,1,2,3,4,5,6; //Index 表示参数在程序调用时的位置,最左边编号为 0 r1=Index; r1=r1 lsl 1; r1+=bp; //得到参数在堆栈中的位置 r3=[r1++]; //读取参数的值 r4=[r1]; .ENDM M_StoreValue: .MACRO Index //参数 Index=0,1,2,3,4,5,6; //Index 表示参数在程序调用时的位置,最左边编号为 0 r3=Index; r3=r3 lsl 1; r3+=bp; //得到参数在堆栈中的位置 [r3++]=r1; //将 r1,r2 的值存入该参数 [r3]=r2; .ENDM //====================================================== // 程序名称: F_LinearInsert // 功能描述: 计算(x-x0)x(y1-y0)/(x1-x0)+y0,实现线性插值算法. // 输入: 浮点数 x0,y0,x1,y1,x // 输出: 浮点数 y->r1,r2 // 破坏: r1,r2,r3,r4; // 使用: r1,r2,r3,r4,bp,sp; // 占用堆栈: 14; //====================================================== .public F_LinearInsert; .public _F_LinearInsert; .code F_LinearInsert: _F_LinearInsert: .proc push bp to [sp]; bp=sp; bp+=4; //bp 指向参数 x0 M_GetValue 0; //取 x0 push r3,r4 to [sp]; M_GetValue 4; //取 x push r3,r4 to [sp]; call __subf2; //计算 x-x0 sp+=4;
§5.1 线性插值算法
线性插值是代数插值的最简 单形式。假设变量 y 和自变量 x ,X G2Ï V Ò 5- 1 中 曲 线 y1 y y0 A f(x) B g(x)
Y
y = f ( x ) 所示。已知 y 在点 x0
和 x1 的对应值 y 0 和 y1 ;现在要 求 用 一 线 性 插 值 函 数
x0 和 x1 之间,称为内插,否则称为外插或外推。在这里,
我们只考虑内插。在进行插值运算前,还要考虑下面两个具体问题: 插值节点的选取:在单片机的应用中,往往把常用的函数以表格的形式固化在程序 存储器中。 例如某物理量的温度补偿值是非线性的, 表格中的值是在若干个温度点 实测得到的补偿值; 又比如等间距角度的正弦函数值组成的表格等等。 对于任一给 定的插值点 x ÈùEî›1T),X¤k.BnÔE¥,Xøþ¦&•
g ( x ) = y0 +
y1 − y 0 ( x − x0 ) x1 − x0
(点斜式)
或:
g ( x ) = y0 (
x −x x1 − x ) + y1 ( 0 ) x1 − x0 x0 − x1
(两点式)
由图 5- 1 也可以看出, 插值节点 x0 和 x1 之间的间距越小, 那么在这一区间 g ( x ) 与 f ( x ) 之间的误差就越小。若插值点 x ü
bp=sp+4; M_GetValue 6; push r3,r4 to [sp]; M_GetValue 3; push r3,r4 to [sp]; M_GetValue 2; push r3,r4 to [sp]; M_GetValue 1; push r3,r4 to [sp]; M_GetValue 0; push r3,r4 to [sp]; call F_LinearInsert; sp+=10; M_StoreValue 3; M_GetValue 6; push r3,r4 to [sp]; M_GetValue 5; push r3,r4 to [sp]; M_GetValue 4; push r3,r4 to [sp]; M_GetValue 1; push r3,r4 to [sp]; M_GetValue 0; push r3,r4 to [sp]; call F_LinearInsert; sp+=10; M_StoreValue 5; M_GetValue 6; push r3,r4 to [sp]; M_GetValue 5; push r3,r4 to [sp]; M_GetValue 4; push r3,r4 to [sp]; M_GetValue 3; push r3,r4 to [sp]; M_GetValue 2; push r3,r4 to [sp]; call F_LinearInsert; sp+=10; pop bp from [sp]; retf; .endp
(8.1)
第二步:过点 ( x0 , y 0 ) , ( x 2 , y 2 ) 作直线 L02 ,即
L02 = y 0 +
y 2 − y0 ( x − x0 ) x 2 − x0
(8.2)
第三步:将 ( x1 , L01 ) , ( x 2 , L02 ) 也理解为“点” ,过这两点作“直线” ,记之为 L012 , 即
M_StoreValue 4; M_GetValue 1; push r3,r4 to [sp]; M_GetValue 3; push r3,r4 to [sp]; call __subf2; sp+=4; M_StoreValue 3; M_GetValue 0; push r3,r4 to [sp]; M_GetValue 2; push r3,r4 to [sp]; call __subf2; sp+=4; M_StoreValue 2; M_GetValue 4; push r3,r4 to [sp]; M_GetValue 3; push r3,r4 to [sp]; call __mulf2; sp+=4; M_StoreValue 4; M_GetValue 2; push r3,r4 to [sp]; M_GetValue 4; push r3,r4 to [sp]; call __divf2; sp+=4; push r1,r2 to [sp]; M_GetValue 1; push r3,r4 to [sp]; call __addf2; sp+=4; pop bp from [sp]; retf; .endp
g ( xi ) = f ( x i )
其中: i = 0,1,2 ;
ax12 + bx1 + c = y1
2 + bx + c = y ax2 2 2
解此方程组可得 g ( x ) 的系数 a 、 b 和 c ,但是这样运算很麻烦。实际计算中,我们可 以把 g ( x ) 写成各种形式的二次多项式, 然后运用待定系数法把 g ( x ) 确定下来。 这些方法包 括抛物线插值的拉各朗日(Lagrange)形式,抛物线插值的牛顿(Newton)形式,逐次线性 插值法等。在这里,我们只讨论逐次线性插值法,因为它能充分利用前面线性插值程序,也 容易在计算机上实现。
(8.4)
不难看出, L012 是关于 x ,X`õÑDÈJè$µC‡sÆ-¹&•G2ÏÖ
L012 ( xi ) = y i
所以, L012 就是所要求的二次插值多项式 g ( x ) 。
(i = 0,1,2)
仔细观察式(8.4)后可以看出, ( y1 − y 0 ) ÷ ( x1 − x 0 ) 是一阶差商,而方括号内的分式 是二阶差商。式(8.3)是通过两个线性插值的结果获得 g ( x ) ,所以称为逐次线性插值。显 然,式(8.1) 、 (8.2)和(8.3)都是线性插值中的点斜式表达式,因此,可以直接调用前面 的线性插值程序。 因为只考虑内插,所以插值点 x h!b
5.2.2 逐次线性插值算法
已知三点 ( x0 , y 0 ) , ( x1 , y1 ) , ( x 2 , y 2 ) 及插值点的 x È"Íh,X 用直线点斜式公式: 第一步:过点 ( x0 , y 0 ) , ( x1 , y1 ) 作直线 L01 ,即
y 值。
L01 = y 0 +
y1 − y 0 ( x − x0 ) x1 − x0
L012 = L01 +
L02 − L01 ( x − x1 ) x 2 − x1
(8.3)
第四步:把式(8.1)和(8.2)代入式(8.3) ,得
L012
y 2 − y 0 y1 − y 0 x −x − x −x y1 − y 0 0 1 0 ( x − x0 )( x − x1 ) ( x − x0 ) + 2 = y0 + x1 − x0 x 2 − x1
//x-x0 存入参数 x //取 y0 //取 y1 //计算 y1-y0 //y1-y0 存入参数 y1 //取 x0 //取 x1 //计算 x1-x0 //x1-x0 存入参数 x1 //取 x,即 x-x0 //取 y1,即 y1-y0 //计算(x-x0)x(y1-y0) //(x-x0)x(y1-y0)存入参数 x //取 x1,即 x1-x0 //取 x,即(x-x0)x(y1-y0) //计算(x-x0)x(y1-y0)/(x1-x0)
g ( x ) = ax + b , 近似代替 f ( x ) 。
根据插值条件,应满足:
0
X x0 x x1
ax0 + b = y 0
ax1 + b = y1
图 5- 1 用直线拟合求准确峰位示意图
解该方程组,便可确定线性插值函数 g ( x ) 的参数 a 和 b 。由图可知,线性插值的几何意义 是用通过点 A( x0 , y 0 ) 和点 B ( x1 , y1 ) 的直线近似地代替曲线 y = f ( x ) 。我们很容易求得该 直线表达式:
[x0 , x2 ]的区间内。当我们将三个节点的坐标和
插值点的横坐标代入下面的程序后,就可以得到插值点的函数近似值。 //====================================================== // 程序名称: F_QuadraticInsert // 功能描述: 实现逐次线性插值算法: // 1、计算 L01=y0+(y1-y0)(x-x0)/(x1-x0) // 2、计算 L02=y0+(y2-y0)(x-x0)/(x2-x0) // 3、计算 L012=L01+(L02-L01)(x-x1)/(x2-x1) // 输入: 浮点数 x0,y0,x1,y1,x2,y2,x // 输出: 浮点数 y->r1,r2 // 破坏: r1,r2,r3,பைடு நூலகம்4; // 使用: r1,r2,r3,r4,bp,sp; // 占用堆栈: 28; //====================================================== .public F_QuadraticInsert; .public _F_QuadraticInsert; F_QuadraticInsert: _F_QuadraticInsert: .proc push bp to [sp];
g( x)
Y A B
f ( x)
C
X
0
x0
x1
图 5- 2 抛物线插值示意图
x2
C ( x2 , y 2 ) ; 过此三点可以作一
抛物线,即一条二次曲线
g ( x ) ,且是唯一的。
设: 已知: 由此可得下列方程组:
2 + bx + c = y ax0 0 0
g ( x ) = ax 2 + bx + c
//取 y0 //计算(x-x0)x(y1-y0)/(x1-x0)+y0
§5.2 抛物线插值算法
5.2.1 算法概述
抛物线插值又称为二次插 值,它是以一元二次多项式去 拟合某一段曲线。精度自然要 比线性插值高。 如图 5- 2 所示, 已 知 一 条 曲线 y = f ( x ) 上 的 三点 A( x0 , y 0 ) , B ( x1 , y1 ) ,
x0 和 x1 以及在表中对 y 值。
应的函数值 y 0 和 y1 ,然后就可以进行插值运算,求得插值点 x Íh,X
为了提高插值精度,大多数情况下都是采用浮点运算,因此参与插值运算的数据和 表格应事先转换成规格化浮点。 以点斜式线性插值算法为例, 当给定两个插值点的坐标后, 就可以通过如下插值算法得 到插值点的函数近似值: 首先定义宏如下: M_GetValue: .MACRO Index //参数 Index=0,1,2,3,4,5,6; //Index 表示参数在程序调用时的位置,最左边编号为 0 r1=Index; r1=r1 lsl 1; r1+=bp; //得到参数在堆栈中的位置 r3=[r1++]; //读取参数的值 r4=[r1]; .ENDM M_StoreValue: .MACRO Index //参数 Index=0,1,2,3,4,5,6; //Index 表示参数在程序调用时的位置,最左边编号为 0 r3=Index; r3=r3 lsl 1; r3+=bp; //得到参数在堆栈中的位置 [r3++]=r1; //将 r1,r2 的值存入该参数 [r3]=r2; .ENDM //====================================================== // 程序名称: F_LinearInsert // 功能描述: 计算(x-x0)x(y1-y0)/(x1-x0)+y0,实现线性插值算法. // 输入: 浮点数 x0,y0,x1,y1,x // 输出: 浮点数 y->r1,r2 // 破坏: r1,r2,r3,r4; // 使用: r1,r2,r3,r4,bp,sp; // 占用堆栈: 14; //====================================================== .public F_LinearInsert; .public _F_LinearInsert; .code F_LinearInsert: _F_LinearInsert: .proc push bp to [sp]; bp=sp; bp+=4; //bp 指向参数 x0 M_GetValue 0; //取 x0 push r3,r4 to [sp]; M_GetValue 4; //取 x push r3,r4 to [sp]; call __subf2; //计算 x-x0 sp+=4;