Search This Blog

Sunday 31 July 2011

Best Line(Curve) Fitting - Least Square Method

          Curve fitting is very fun with our own coding that fits a best curve for a given set of points. Although it is fun, it is also an essential friend for students for plotting their readings. Most of the engineering stream students have to submit their observation with well plotted graph. But what they actually do is draw the graph and adjust the readings according to the their graph. I hope this program will help them to plot their graph more appropriately.


Theory
        The name least square denote the squares of the errors are the least possible values. What are the errors? The difference between our actual reading and the value of the chosen equation.
        Let us assume we are going to fit a straight line for the given set of readings. The equation of the line is : y = mx+c. This equation has two parameters x and y thus it has it own (x,y) values and we have our own set of (x,y) values observed from the experiment. The difference between these y (from equation) and y (from experiment) is called error.


Our Expt: Ohm's Law.

The circuit on the left is to prove the Ohm's Law V = IR.
Definition: Ohm's law states that the current through a conductor between two points is directly proportional to the potential difference across the two points, and inversely proportional to the resistance between them.


Assume that this is the set of readings we have:    


X ( Current ) Y (Voltage )
1 2.3
2 4.6
3 5.8
4 7.5
5 9.8
                                            
        This plot is not a perfect straight line. So we try to fit a straight line such that it is nearer to all of the points. What we are going to do is place a scale on the graph sheet and adjust it until it becomes nearer to all points and then we draw the line. Mathematically we fit a line y = mx+c, then we find the values of 'm' and 'c' so that it resemble the line we draw using the experimental values. For more theory google for it.
Coding:          
       We use the matrix library that was discussed in my previous post


File: lsm.h
   #include<matrix.h>
   typedef struct readings {
     float *x;
     float *y;
     int len;
   }Readings;
   typedef struct lsm_line {
     float *x;
     float *y;
     float *x2;
     float *xy;
     float X , Y , XY , X2;
     float *newy;
     float Dev;
     int len;
   }LsmLine;
   Readings* lsm_new_Readings(int n);
   LsmLine* lsm_new_LsmLine(Readings *Read);
   int lsm_del_Readings(Readings *anchor);
   int lsm_Read_farray(float *array,int len);
   int lsm_Print_farray(float *array,int len);
   int lsm_Calc_LsmLine(LsmLine* line);
   int lsm_Print_LsmLine(LsmLine* line); 
File : lsm.c
     #include "lsm.h"
     Readings* lsm_new_Readings(int len)
     {
        Readings *newRead = (Readings*)malloc(sizeof(Readings));
        newRead->x = (float*)malloc(sizeof(float)*len);
        newRead->y = (float*)malloc(sizeof(float)*len);
        newRead->len = len;
        return newRead;
     }

     LsmLine* lsm_new_LsmLine(Readings *read)
     {
        LsmLine *newLine = (LsmLine*)malloc(sizeof(LsmLine));
        int len = read->len;
        newLine->x = (float*)malloc(sizeof(float)*len);
        newLine->y = (float*)malloc(sizeof(float)*len);
        newLine->xy = (float*)malloc(sizeof(float)*len);
        newLine->x2= (float*)malloc(sizeof(float)*len);
        newLine->newy= (float*)malloc(sizeof(float)*len);
        newLine->len = len;
        newLine->X  = 0;
        newLine->Y  = 0;
        newLine->XY = 0;
        newLine->X2 = 0;
        newLine->Dev=0;
        int i;
        newLine->len = read->len;
        for(i = 0;i<newLine->len;i++){
            newLine->x[i]=read->x[i];
            newLine->y[i]=read->y[i];
            newLine->xy[i]=read->x[i]*read->y[i];
            newLine->x2[i]=read->x[i]*read->x[i];
            newLine->X +=  newLine->x[i];
            newLine->Y +=  newLine->y[i];
            newLine->XY +=  newLine->xy[i];
            newLine->X2 +=  newLine->x2[i];
        }
        return newLine;
  }
  
  int lsm_Calc_LsmLine(LsmLine *Line)
  {
     int i;
     Matrix *lhs = matrix_new_Matrix(2,2);
     Matrix *rhs = matrix_new_Matrix(2,1);
     Assuming Eqn is y=ax+b
     lhs->mat[0][0] = Line->X;
     lhs->mat[0][1] = Line->len;
     lhs->mat[1][0] = Line->X2;
     lhs->mat[1][2] = Line->X;
     rhs->mat[0][0]=Line->Y;
     rhs->mat[1][0]=Line->XY;
     MatrixEqn *Eqn = matrix_new_MatrixEqn(lhs,rhs);
     matrix_Solve_Det(Eqn);
     float a = Eqn->Soln->mat[0][0];
     float b = Eqn->Soln->mat[1][0] ;
     for(i=0;i<Line->len;i++){
       Line->newy[i] =  a*Line->x[i]+b;
       Line->Dev += (Line->y[i]-Line->newy[i])*(Line->y[i]-Line->newy[i]);
     }
 }


 int lsm_Print_LsmLine(LsmLine* line)
 {
    printf("\nS.No\tX\t\tY\t\tX2\t\tXY\t\tNewY\n");
    int i;
    for (i=0;i<line->len;i++){
       printf("\n%d",i+1);
       printf("\t%0.3f",line->x[i]);
       printf("\t\t%0.3f",line->y[i]);
       printf("\t\t%0.3f",line->x2[i]);
       printf("\t%0.3f",line->xy[i]);
       printf("\t\t%0.3f",line->newy[i]);
    }
    printf("\n\nTotal");
    printf("\t%0.3f",line->X);
    printf("\t\t%0.3f",line->Y);
    printf("\t\t%0.3f",line->X2);
    printf("\t%0.3f",line->XY);
    printf("\n\n%0.3f = %0.3fa + %db ",line->Y,line->X,line->len);
    printf("\n%0.3f = %0.3fa + %0.3fb ",line->XY,line->X2,line->X);
    printf("\n\nDeviation = %0.3f",line->Dev);
    return 0;
  }
  
  void lsm_Read_farray(float *array,int len)
  {
     int i=0;
     for(i=0;i<len;i++){
        scanf("%f",&array[i]);
     }
     return 0;
  }
  
   lsm_Print_farray(float *array,int len)
   {
      int i=0;
      for(i=0;i<len;i++){
         printf("%0.3f",array[i]);
      }
      return 0;
   }
Sample program to test.
       #include<stdio.h>
   #include"lsm.h"
   int main()
   {
       printf("\n\n\t\t\tLEAST SQUARE METHOD FOR BEST LINE");
       int n,choice;
       printf("\n\nEnter the number of readings\t:");
       scanf("%d",&n);
       Readings *read = lsm_new_Readings(n);
       printf("\nEnter the type of Variation of X:");
       printf("\n\t1.Constant Steps of X");
       printf("\n\t2.Variable Steps of X\n");
       printf("\nEnter the Choice\t:");
       scanf("%d",&choice);
       switch(choice){
         case 1:   printf("\nEnter First : Step : Last of X\t:") ;
                   float first , step , last;
                   scanf("%f %f %f",&first,&step,&last);
                   int i;
                   float value;
                   for( i=0,value=first;value<=last; value +=step,i++){
                       read->x[i] = value;
                   }
                   break;
         case 2:   printf("\nEnter X\t:\n");
                   lsm_Read_farray(read->x,n);
                   break;
         default: printf("\nWrong Option Restart the program!!!");
                   break;
      }
      printf("\nEnter Y\t:\n");
      lsm_Read_farray(read->y,n);
      LsmLine *line = lsm_new_LsmLine(read);
      lsm_Calc_LsmLine(line);
      lsm_Print_LsmLine(line);
      return 0;
}
         We can extend these project to various curves, and choose the curve which has least summation of error 'S', since all set of points will not be as above.

    No comments:

    Post a Comment