2023-01-02 17:27来源:m.sf1369.com作者:宇宇
已知速度曲线v(t) 上的四个数据点下表所示
基本原理:
利用插值(即求过已知有限个数据点的近似函数)的基本原理,用多项式作为研究插值的工具,进行代数插值.其基本问题是:已知函数f (x)在区间[a,b]上n +1个不同点x0,…,xn处的函数值 (i = 0,1,…,n),求一个至多n 次多项式 ψn(x)
使其在给定点处与 f (x)同值,即满足插值条件: ψn(x)= = .
许多工程技术中提出的计算问题对插值函数的光滑性有较高要求,如飞机的机翼外
形,内燃机的进、排气门的凸轮曲线,都要求曲线具有较高的光滑程度,不仅要连续,
而且要有连续的曲率,这就导致了样条插值的产生.
数学上将具有一定光滑性的分段多项式称为样条函数.具体地说,给定区间[a,b]
的一个分划
Δ:
如果函数s(x) 满足:
(i)在每个小区间[ ](i=0,1,…,n)上s(x)是k 次多项式;
(ii)s(x)在[a,b]上具有k −1阶连续导数.
则称s(x)为关于分划Δ 的k 次样条函数,其图形称为k 次样条曲线.
基本思路:
根据插值的基本原理,先对v进行三次样条插值,可以得到许多v(t)的值;然后根据积分的基本原理,分割、近似、求和、取极限,可以求得积分.根据求导原理,因变量的微小变化量与自变量变化量的商,可以求得所求点的导数值.
程序代码:
t0=[0.15 0.16 0.17 0.18];v0=[3.5 1.5 2.5 2.8];
t=0.15:0.0001:0.18;
%三次样条插值;
v=interp1(t0,v0,t,'spline');
v=spline(t0,v0,t);
pp=csape(t0,v0,'second');v=ppval(pp,t)% 使用csape函数;
S=sum(v)*0.0001;%求积分值
T=(v(301)-v(300))/0.0001;%求导数值
Plot(t0,v0,’*’,t,v);
样条插值的次数只有三次,应该不会发生龙格现象吧
分段插值: 通常可能指的是直接分段低次线插, 通俗来说 这样出来的线条不是很平滑. 因为在节点上不一定可导.直接hermite插值就和一楼说的差不多三次样条与分段 Hermite 插值的根本区别在于S(x)自身光滑(考虑了二阶倒数),不需要知道 f 的导数值(除了在2个端点可能需要);而Hermite插值依赖于f 在所有插值点的导数值。(S(x)为插值基函数,f为你要插值的函数)
#include<iostream>
#include<iomanip>
using namespace std;
const int MAX = 50;
float x[MAX], y[MAX], h[MAX];
float c[MAX], a[MAX], fxym[MAX];
float f(int x1, int x2, int x3){
float a = (y[x3] - y[x2]) / (x[x3] - x[x2]);
float b = (y[x2] - y[x1]) / (x[x2] - x[x1]);
return (a - b)/(x[x3] - x[x1]);
} //求差分
void cal_m(int n){ //用追赶法求解出弯矩向量M……
float B[MAX];
B[0] = c[0] / 2;
for(int i = 1; i < n; i++)
B[i] = c[i] / (2 - a[i]*B[i-1]);
fxym[0] = fxym[0] / 2;
for(i = 1; i <= n; i++)
fxym[i] = (fxym[i] - a[i]*fxym[i-1]) / (2 - a[i]*B[i-1]);
for(i = n-1; i >= 0; i--)
fxym[i] = fxym[i] - B[i]*fxym[i+1];
}
void printout(int n);
int main(){
int n,i; char ch;
do{
cout<<Please put in the number of the dots:;
cin>>n;
for(i = 0; i <= n; i++){
cout<<Please put in X<<i<<':';
cin>>x[i]; //cout<<endl;
cout<<Please put in Y<<i<<':';
cin>>y[i]; //cout<<endl;
}
for(i = 0; i < n; i++) //求 步长
h[i] = x[i+1] - x[i];
cout<<Please 输入边界条件\n 1: 已知两端的一阶导数\n 2:两端的二阶导数已知\n 默认:自然边界条件\n;
int t;
float f0, f1;
cin>>t;
switch(t){
case 1:cout<<Please put in Y0\' Y<<n<<\'\n;
cin>>f0>>f1;
c[0] = 1; a[n] = 1;
fxym[0] = 6*((y[1] - y[0]) / (x[1] - x[0]) - f0) / h[0];
fxym[n] = 6*(f1 - (y[n] - y[n-1]) / (x[n] - x[n-1])) / h[n-1];
break;
case 2:cout<<Please put in Y0\ Y<<n<<\\n;
cin>>f0>>f1;
c[0] = a[n] = 0;
fxym[0] = 2*f0; fxym[n] = 2*f1;
break;
default:cout<<不可用\n;//待定
};//switch
for(i = 1; i < n; i++)
fxym[i] = 6 * f(i-1, i, i+1);
for(i = 1; i < n; i++){
a[i] = h[i-1] / (h[i] + h[i-1]);
c[i] = 1 - a[i];
}
a[n] = h[n-1] / (h[n-1] + h[n]);
cal_m(n);
cout<<\n输出三次样条插值函数:\n;
printout(n);
cout<<Do you to have anther try ? y/n :;
cin>>ch;
}while(ch == 'y' || ch == 'Y');
return 0;
}
void printout(int n){
cout<<setprecision(6);
for(int i = 0; i < n; i++){
cout<<i+1<<: [<<x[i]<< , <<x[i+1]<<]\n<<\t;
/*
cout<<fxym[i]/(6*h[i])<< * (<<x[i+1]<< - x)^3 + <<<< * (x - <<x[i]<<)^3 +
<<(y[i] - fxym[i]*h[i]*h[i]/6)/h[i]<< * (<<x[i+1]<< - x) +
<<(y[i+1] - fxym[i+1]*h[i]*h[i]/6)/h[i]<<(x - <<x[i]<<)\n;
cout<<endl;*/
float t = fxym[i]/(6*h[i]);
if(t > 0)cout<<t<<*(<<x[i+1]<< - x)^3;
else cout<<-t<<*(x - <<x[i+1]<<)^3;
t = fxym[i+1]/(6*h[i]);
if(t > 0)cout<< + <<t<<*(x - <<x[i]<<)^3;
else cout<< - <<-t<<*(x - <<x[i]<<)^3;
cout<<\n\t;
t = (y[i] - fxym[i]*h[i]*h[i]/6)/h[i];
if(t > 0)cout<<+ <<t<<*(<<x[i+1]<< - x);
else cout<<- <<-t<<*(<<x[i+1]<< - x);
t = (y[i+1] - fxym[i+1]*h[i]*h[i]/6)/h[i];
if(t > 0)cout<< + <<t<<*(x - <<x[i]<<);
else cout<< - <<-t<<*(x - <<x[i]<<);
cout<<endl<<endl;
}
cout<<endl;
}