拟合算法

来源:互联网 发布:韩国学术造假事件 知乎 编辑:程序博客网 时间:2024/04/30 14:52

3.1 直线拟合

原理:已知一组数据Xi,YiXiYi具有线性关系;利用最小二乘法,有如下关系

Φ(a,b)= (aXi+b-Yi)2    1

要使得Φ(a,b)取得最小值,那么

Φ(a,b)/ a=0, Φ(a,b)/ b=0

是极小值点的必要条件,于是(1)可化为

2Xi(aXi+b-Yi)=0

2i(aXi+b-Yi)=0

对上式求解可得:

a=[(n+1) XiYi- Xi Yi]/[(n+1) Xi2-( Xi)2]

b=[ Xi2 Yi- Xi XiYi]/[(n+1) Xi2-( Xi)2]

typedef struct tagLpoint

{

       double x;

       double y;

}Lpoint;

 

int LineMin2(HDC hDC,Lpoint *lp,int n)

{

       int           i;

       double     a,b,sumX,sumX2,sumY,sumXY;

 

       sumX=0.0;

       sumX2=0.0;

       sumY=0.0;

       sumXY=0.0;

 

       for(i=0;i<n;i++)

       {

              sumX+=lp[i].x;

              sumX2+=lp[i].x*lp[i].x;

              sumY+=lp[i].y;

              sumXY+=lp[i].x*lp[i].y;

       }

 

       a=(n*sumXY-sumX*sumY)/(n*sumX2-sumX*sumX);

       b=(sumX2*sumY-sumX*sumXY)/(n*sumX2-sumX*sumX);

 

       MoveToEx(hDC,0,-b/a,NULL);

       LineTo(hDC,600,(600-b)/a);  //600表示从高度600开始画

       SelectObject(hDC,CreatePen(0,1,RGB(255,0,0)));

       MoveToEx(hDC,0,b,NULL);

       LineTo(hDC,700,700*a+b);//0-700x

       return 1;

}

3.2 二次以上拟合

typedef struct tagLpoint

{

       double     x;

       double     y;

}Lpoint;

//检查方程组是否有解

int Check(double s[10][10],int R,int k)

{

       int           i;

 

       i=k;

       do i=i+1;

       while((i<=R)&&(abs(s[i][k])<=ER));

       if(i>=R)

       {

              MessageBox(NULL,"方程组无解或无惟一解,程序终止",NULL,NULL);

              return 0;

       }

       return 1;

}

///把最大元素作为对角线元数

int Pivot(double s[10][10],double c[10],int R,int k)

{

       int           l,j;

       double     swap;

 

       l=k;

       for(j=k;j<R;j++)

              if(abs(s[j][k])>abs(s[l][k]))

                     l=j;//即找出最大绝对值的下标

       if(l==k)

              return 0;

       swap=c[k];

       c[k]=c[l];

       c[l]=swap;

       for(j=k;j<R;j++)

       {

              swap=s[k][j];

              s[k][j]=s[l][j];

              s[l][j]=swap;

       }

       return 1;

}

 

//高斯消元法解线性方程组

int GussianSalve(double s[10][10],double c[10],int R,double a[10])

{

       int           i,j,k,ret;

       double     f;

 

       for(k=0;k<R-1;k++)

       {

              ret=Check(s,R,k);

              if(ret==0)

                     return 0;

              Pivot(s,c,R,k);

              for(i=k+1;i<R;i++)

              {

                     f=s[i][k]/s[k][k];

                     c[i]=c[i]-c[k]*f;

                     for(j=k+1;j<R;j++)

                            s[i][j]=s[i][j]-s[k][j]*f;

              }

       }

       a[R-1]=c[R-1]/s[R-1][R-1];

       for(i=R-2;i>=0;i--)

       {

              f=0.0;

              for(j=i+1;j<R;j++)

                     f=f+s[i][j]*a[j];

              a[i]=(c[i]-f)/s[i][i];

       }

       return 1;

}

 

//多项式最小二乘法算法

/*名称:PolyMin

 功能:对一组数据进行多项式拟合

 参数:hDC绘画句柄,tempasc时个包含x,y值的数组,R表示几次如2表示一次,意思是要求ab两个参数,n表示数组个数

*/

void PolyMin(HDC hDC,Lpoint *tempasc,int R,int n)

{

       int           i,j,k;

       double     s[10][10],c[10],a[10];

       double     **px,temp,te;

 

       px=new double*[n];

       for(i=0;i<n;i++)

              px[i]=new double[10];

 

       for(i=0;i<R;i++)

       {

              c[i]=0.0;

              for(j=0;j<R;j++)

                     s[i][j]=0.0;

       }

       for(i=0;i<n;i++)

       {

              px[i][0]=1.0;

              for(j=1;j<R;j++)

                     px[i][j]=px[i][j-1]*tempasc[i].x;

       }

       for(i=0;i<R;i++)

       {

              for(j=0;j<n;j++)

                     c[i]=c[i]+tempasc[j].y*px[j][i];

              for(j=0;j<R;j++)

                     for(k=0;k<n;k++)

                            s[i][j]=s[i][j]+px[k][i]*px[k][j];

       }

       GussianSalve(s,c,R,a);

       SelectObject(hDC,CreatePen(0,1,RGB(255,0,0)));

       MoveToEx(hDC,40,400-50*a[0],NULL);

       for(te=0;te<31;te+=0.25)

       {

              temp=a[R-1];

              for(j=R-1;j>0;j--)

                     temp=temp*te+a[j-1];

              LineTo(hDC,40+te*50,400-temp*50);//从坐标点40,500处开始画

       }

       for(i=0;i<n;i++)

              delete []px[i];

       delete []px;

}

3.3 拉格朗日插值曲线

double     LagBasChg(Lpoint *p,int n,double ly,int k)

{

       int           i;

       double     lf;

 

       lf=1.0;

       for(i=0;i<n;i++)

              if(i!=k)

                     lf=lf*(ly-p[i].x)/(p[k].x-p[i].x);

       return lf;

}

void LagrangeInterpChg(HDC hDC,int color,Lpoint *p,int n)

{

       int           i;

       double     ly,te;

       HPEN     hPen;

 

       ly=0.0;

       for(i=0;i<n;i++)

              ly=ly+p[i].pasc*LagBasChg(p,n,0.0,i);

       hPen=CreatePen(0,1,color);

       SelectObject(hDC,hPen);

       MoveToEx(hDC,40,500-ly,NULL);

       for(te=0;te<=30;te+=0.25)

       {

              ly=0.0;

              for(i=0;i<N;i++)

                     ly=ly+p[i].y*LagBasChg(p,n,te,i);

              LineTo(hDC,40+te*20,500-ly);

       }

       DeleteObject(hPen);

}

 
原创粉丝点击