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
Fig 2. Detector data: Offset (mm) vs. Rotation Degree
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);
}