Home Page. Click Here.

Example C code: Parabolic Curve Fitting


Date of Coding: April 1988
Language: C (Borland Turbo C ver 2)

A parabolic curve fit is used to locate a point of data on a curve. Where these routines were used by us was in a situation where a circular object (a semiconductor wafer) was placed on a rotating assembly via a robotic arm. Since the center of the wafer was never truly aligned with the center of the rotating assembly, the idea was to to rotate the object a degree at a time, collecting data on the location of the wafer edge. Since the edge detector was at a fixed location (See Fig 1), the data collected would vary with distance. If you were to plot detector data along a graph (Fig.2) the data collected would look a lot like a sine wave as the edge varies with the wafer center seeming to rotate about the assembly center. The job of the curve fit is to determine the data point of highest magnitude; the data point number gives us the angle of offset. The sine amplitude shows us how far off (eccentric) the centers are.

Fig 1. Wafer center is offset to fixed assembly and detector

Wafer offset diagram

Fig 2. Detector data: Offset (mm) vs. Rotation Degree

X/Y data plot

By now I know a few of you are looking at this and wondering why go through a curve fit when apparently all you have to do is simply go through the array and find the largest and smallest offset numbers.

But... not so fast. In the real world detectors have limits in their resolution. In some instances there may in fact be deviation but the detector is unable to see it. Electronics are also subject to random noise and therefore there can be odd data points. Also, we will want to know what the offset angle is to a precise number; one degree in this application is too much. We want to know the angle to a fraction of a degree. As a result, the only realistic way to calculate the angle is a curve fit.

This curve fit code is generic. Code very much like this is used all the time in industrial applications and uses such as graphics (e.g. calculating histogram modal points,etc.), ballistics, and so on.

/*****************************************************************/
/*                     PARABOLIC CURVE FIT                       */
/*****************************************************************/

#define MAX       5
#define TERMCOUNT 3

// global variables
double xaxis[360];            // parabolic fit arrays
double yaxis[360];            //         ""
double outputdata[10];        //         ""
double RawDataArray[360];

int main(void)
{
   int     i, j, datapointcount;
   double  ecc_angle;  // angle of eccentricity

   // our mythical routine to get raw data should return
   // one datum per degree
   datapointcount = DoSomethingToGetRawData();

   // get the x/y arrays ready for curve routine
   for(i = 0, j = 1; i < datapointcount; i++, j++){
       xaxis[j] = (double)i;
       yaxis[j] = RawDataArray[i];
   }
   // fit the curve and assign data to outputdata array
   curvefit(--j);              
   ecc_angle = (-outputdata[2]) / (2 * outputdata[3]));
   return(1);
}

void curvefit(int pointcount)
{
   int    i, j, k, l, n;
   double xinput, yinput, delta, xterm, yterm;
   double xsum[6];
   double ysum[4];

   union{
      double darray[4][4]; 
      double arrayout[16];
   } arrayunion;

   // zero the summing arrays
   for(i = 1; i <= MAX; i++)       xsum[i] = 0;
   for(i = 1; i <= TERMCOUNT; i++) ysum[i] = 0;

   // now calculate the sums
   for(i = 1; i <= pointcount; i++){  
       xinput = xaxis[i];
       yinput = yaxis[i];
       xterm = 1.0;
       for(j = 1; j <= MAX; j++){  
           xsum[j] += xterm;
           xterm *= xinput;
       }
       yterm = yinput;
       for(j = 1; j <= TERMCOUNT;j++){
           ysum[j] += yterm;
           yterm *= xinput;
       }
   }
   
   // then assign the sums   
   for(j = 1; j <= TERMCOUNT; j++){
       for(k = 1; k <= TERMCOUNT; k++){
           n = j + (k - 1);
           arrayunion.darray[j][k] = xsum[n];
       }
   }

   delta = determ(arrayunion.arrayout, TERMCOUNT);

   for(l = 1; l <= TERMCOUNT; l++){
       for(j = 1; j <= TERMCOUNT; j++){
           for(k = 1; k <= TERMCOUNT; k++){
               n = j + (k - 1);
               arrayunion.darray[j][k] = xsum[n];
           }
           arrayunion.darray[j][l] = ysum[j];
       }
       outputdata[l] = determ(arrayunion.arrayout, TERMCOUNT) / delta;
   }
}

double determ(double inputarray[16], int size)
{
   int    i, j, k, k1;
   double save, det = 1;
   BOOL   flag;
   union{
     double arrayin[16]; 
     double ar4x4[4][4];
   } arrayunion;
      
   for(k = 0; k <= 15; k++) p.arrayin[k] = inputarray[k];

   for(k = 1; k <= size; k++){
       if(arrayunion.ar4x4[k][k] == 0){
          flag = FALSE;
          for(j = k; j <= size; j++){
              if(arrayunion.ar4x4[k][j] != 0){
                 flag = TRUE;
                 break;
              }
          }
          // only 1 array element can be 0 
          if(flag == FALSE) return(0);

          // swap
          for(i = k; i <= size; i++){              
              save = arrayunion.ar4x4[i][j];
              arrayunion.ar4x4[i][j] = arrayunion.ar4x4[i][k];
              arrayunion.ar4x4[i][k] = save; 
          }
          det = -det; 
       } // if array == 0

       det *= arrayunion.ar4x4[k][k];

       if((k - size) < 0){
          k1 = k + 1;
          for(i = k1; i <= size; i++){
              for(j = k1; j <= size; j++)
                  arrayunion.ar4x4[i][j] -= (arrayunion.ar4x4[i][k] * 
                                             arrayunion.ar4x4[k][j] / 
                                             arrayunion.ar4x4[k][k]);
          }
       } // if (k - size)
   } // for k

   return(det);
}



Home

Copyright ©1988 - 2002 by AlstonLabs.com - ALL RIGHTS RESERVED