Category: Engineering
Author/Contact Info ~~David~~
Description: Utility to perform linear regressions to determine etch rates or temperatures using linear, exponential, or Arrhenius style equations.
#!g:\mtapps\perl\bin

#use GD::Graph;

#############################
#Author = David Daycock
#Date = May, 2004
#############################

&INTRO;
&CHOICE;



sub INTRO
{

print <<EOF


******************************************************
*                                                    *
*                                                    *
*          Bath Temperature Calculation Utility      *
*                      ver. 1.0.0                    *
*                                                    *
*                    by:                             *
*                      David Daycock                 *
*                                                    *
*                                                    *
*                                                    *
******************************************************


EOF
;

}

sub CHOICE
{
    print("\n1.  Predict Temperature for a given etch rate");
    print("\n2.  Predict Etch Rate for a given temperature");
    print("\n3.  Statistics on my data");
    print("\n4.  Information and assumptions");
    print("\n5.  Quit");   
    print("\n\nSelection:  ");
    $pick = <STDIN>;

    if ($pick == 1)
        { 
            &TtoER;
        }
    elsif ($pick == 2)
        {
            &ERtoT;
        }
    elsif ($pick == 3)
        {
            &STAT;
        }
    elsif ($pick == 4)
        {
            &INFO;
        }
    elsif ($pick == 5)
        {
            &QUIT;
        }
    else
        {
            print("I need a numerical answer!\n");
            &CHOICE;
        };
}

sub BASICS
{
    print("\nYou need to input our data in x,y pairs.  Press ENTER to 
+finish.\n");
    print("If using this for Temperature and Etch Rate calcs, X should
+ be Temp\n");
    print("and Y should be the etch rate.\n");


    for ($i = 0; 1; $i++)
    {
        $numdis = $i+1;
        print("\nX$numdis = ");
        $x[$i] = <STDIN>;
        chomp $x[$i];
        if ($x[$i] !~ m/\d/)
            {
            pop @x;
            last;
            };  #if a digit is not entered, leave the loop.
        print("\nY$numdis = ");
        $y[$i] = <STDIN>;
        chomp $y[$i];

    }
    
    @xstore = @x;
    @ystore = @y;
    
    $xref = \@x; #this is a reference for later putting into r squared
+ functions and slope functions, etc...
    $yref = \@y; #remember, "perldoc perlreftut" for information on re
+ferences....
    
}

    
sub STAT
{
    &BASICS;
    &LINorARH;
    
    
    my $avgX = average(@x);
    my $avgY = average(@y);
    my ($slope, $intercept, $rsquared) = linearfit($xref, $yref);
        
    if ($LINorARH == 1)
    {
        print("\n\nAVERAGE of Xs:\t\t\t$avgX\n");
        print("AVERAGE of Ys:\t\t\t$avgY\n");
        print("Slope of best fit line:\t\t$slope\n");
        print("Intercept of best fit line:\t$intercept\n");
        print("R-squared of fit:\t\t$rsquared\n");
    }
    elsif ($LINorARH == 2)
    {
        $expA = exp($intercept);
        $k = -1 * $slope;
        print("\n\nArrhenius Equation of type y \= A\*exp\(-k\/x\)\n")
+;
        print("A:\t\t\t$expA\n");
        print("k:\t\t\t$k\n");
        print("R-squared of fit:\t$rsquared\n");
    }
    
    elsif ($LINorARH == 3)
    {
        $expA = exp($intercept);
        $k = 1 * $slope;
        print("\n\nExponential Equation of type y \= A\*exp\(k \* x\)\
+n");
        print("A:\t\t\t$expA\n");
        print("k:\t\t\t$k\n");
        print("R-squared of fit:\t$rsquared\n");
    }

    &ASK;
        
}

sub LINorARH
{
    print("Is your data:\n");
    print("1.  Linear\n");
    print("2.  Fit to Arrhenius Equation\n");
    print("3.  Exponential\n");
    print("Choice:  ");
    $LINorARH = <STDIN>;
    chomp $LINorARH;
    
    if ($LINorARH == 2)
        {
            @x = map { 1 / $x[$_]} 0..$#x;
            @y = map {log $y[$_]} 0..$#y;
                        
            $xref = \@x;
            $yref = \@y;
            
        }
        
    elsif ($LINorARH == 1)
        {
            @x = @x;
            @y = @y;
        }
        
    elsif ($LINorARH == 3)
        {
            @x = @x;
            @y = map {log $y[$_]} 0..$#y;
                        
            $xref = \@x;
            $yref = \@y;
            
        }
        
    else
        {
            print("You did not enter a number!");
            &LINorARH;
        }
}


sub ERtoT
{
    &BASICS;
    &LINorARH;
    print("What is the desired etch rate:  ");
    $er = <STDIN>;
    chomp($er);

    my ($m, $b, $rsquared) = linearfit($xref, $yref);
        
    if ($LINorARH == 1)
    {
        
        $temp = ($er - $b) / $m;
        print("\nEtch Rate at $temp deg\.C = $er\n");
        
    }
    elsif ($LINorARH == 2)
    {
        $A = exp($b);
        $k = -1 * $m;
        $temp = $k / (log($A) - log($er));
        print("\n\nArrhenius Equation of type y \= A\*exp\(-k\/x\)\n")
+;
        print("Etch Rate at $temp deg\.C = $er\n");        

    }
    
    elsif ($LINorARH == 3)
    {
        $A = exp($b);
        $k = 1 * $m;
        $temp = (log($er) - log($A)) / $k;
        print("\n\nExponential Equation of type y \= A\*exp\(k \* x\)\
+n");
        print("Etch Rate at $temp deg\.C = $er\n");    
    }
    
    &ASK;
}

sub TtoER
{
    &BASICS;
    &LINorARH;
    print("At what temperature would you like to predict the etch rate
+:  ");
    $temp = <STDIN>;
    chomp($temp);

    my ($m, $b, $rsquared) = linearfit($xref, $yref);
        
    if ($LINorARH == 1)
    {
        
        $er = ($m * $temp) + $b;
        print("\nEtch Rate at $temp deg\.C = $er\n");
        
    }
    elsif ($LINorARH == 2)
    {
        $A = exp($b);
        $k = -1 * $m;
        $er = $A * exp(-$k/$temp);
        print("\n\nArrhenius Equation of type y \= A\*exp\(-k\/x\)\n")
+;
        print("Etch Rate at $temp deg\.C = $er\n");        

    }
    
    elsif ($LINorARH == 3)
    {
        $A = exp($b);
        $k = 1 * $m;
        $er = $A*exp($k * $temp);
        print("\n\nExponential Equation of type y \= A\*exp\(k \* x\)\
+n");
        print("Etch Rate at $temp deg\.C = $er\n");    
    }
    
    &ASK;
}

sub ASK
{
    print("\nWould you like to save your data table to a file (y): ");
    $savedata = <STDIN>;
    chomp($savedata);
    
    if ($savedata eq "y" || $savedata eq "Y")
    {
        print("\nFile name:  ");
        $fname = <STDIN>;
        chomp($fname);
        print("\nFile $fname\.xls saved to desktop.\n");
        
        $path = "$ENV{'HOMEDRIVE'}"."$ENV{'HOMEPATH'}"."\\"."Desktop".
+"\\";
        
        open(AFILE, ">$path"."$fname\.xls");
        
        print AFILE ("X \(Temp\)\tY\(Etch Rate\)\n");
        
        for ($i = 0; $i <= $#xstore; $i++)
        {
            print AFILE ("$xstore[$i] \t $ystore[$i] \n");
        }
        
        close AFILE;
    }
        
    print("\nAre you finished (y or n):  ");

    $quitornot = <STDIN>;
    chomp($quitornot);

    undef ($temp);
    undef ($A);
    undef ($b);
    undef ($m);
    undef ($k);
    undef ($LINroARH);
    undef ($rsquared);

    
    if ($quitornot eq "y" || $quitornot eq "Y")

          {
            &QUIT;

          } 
          
        elsif ($quitornot eq "n" || $quitornot eq "N")

          {
            &CHOICE;

          }
        
        else 
          {
              print ("\nThat is not an option...try again.\n");
              &ASK;

          };
}

sub INFO
{
    print("\nAssumptions include but are not limited to:\n");
    print("\nR-squared value is non-weighted.\n");
    print("I can't really think of any others right now.\n\n");
    &CHOICE;
}

sub QUIT
{print("\nHope this helped!  See you next time...\n");}


######################################################################
+#################
#Below here are function subroutines
######################################################################
+#################

sub average
{
    #this subroutine averages the results of an array passed to it.  R
+eturns a single value.
    my $sum = 0;
    foreach $_ (@_)
    {
        $sum += $_;
    }

    my $avg = $sum / ($#_ + 1);
    return $avg;
}

sub linearfit
{
    #this subroutine takes as arguments two array references containin
+g linear x and y 
    #it returns the linear best fit regression and r-squared correlati
+on.  
    #Usage is @foo = linearfit($xref, $yref) where $xref is a referenc
+e to an array holding all values of
    #x and $yref is a reference to an array holding all values of y.  
+The index of x and y must be equal
    #in order for this to work correctly.  The function returns an arr
+ay in the following order:
    # @results = (slope of line, intercept of line, rsquared correlati
+on)
    # in order fo this function to work, you need the sum, average and
+ sqr functions in the file.  
    
    my @xs = @{@_[0]};    #turns a reference into an array!
    my @ys = @{@_[1]};
    my @xsqrd = sqr(@xs);  
    my @xy = map {$xs[$_] * $ys[$_]} 0..$#xs;
    
    my $sumX = sum(@xs);
    my $sumY = sum(@ys);
    my $sumXY = sum(@xy);
    my $sumXsqr = sum(@xsqrd);
    
    my $n = $#xs;
    
    my $b = (($sumY * $sumXsqr) - ($sumX * $sumXY)) / ((($n+1) * $sumX
+sqr) - ($sumX * $sumX));
    my $m = ((($n+1) * $sumXY) - ($sumX * $sumY)) / ((($n+1) * $sumXsq
+r) - ($sumX * $sumX));

    my $w;
    my @predY;
    
    for ($w = 0; $w <= $#xs; $w++)
    {
        $predY[$w] = ($xs[$w] * $m ) + $b;
    }

    my $yAvg = average(@ys);

    my $k;
    my @predYErr;
    for ($k = 0; $k <= $#predY; $k++)
    {
        $predYErr[$k] = $predY[$k] - $yAvg;
    }
    
    my @ssPred = sqr(@predYErr);
    
    my $l;
    my @Err;
    for ($l = 0; $l <= $#xs; $l++)
    {
        $Err[$l] = $ys[$l] - $yAvg;
    }
    
    my @ssTotal = sqr(@Err);

    my $sumSSpred = sum(@ssPred);
    
    my $sumSStotal = sum(@ssTotal);

    my $rsqrd;
        
    if ($sumSStotal == 0)
    {
        $rsqrd = 0;
    }
    else
    {
        $rsqrd = $sumSSpred / $sumSStotal;
        
        $rsqrd = $rsqrd * 10000;
        $rsqrd = int ($rsqrd);
        $rsqrd = $rsqrd / 10000;  #this block of code gives a four sig
+ fig rsquared value.
        
    }
    
    my @ans = ($m, $b, $rsqrd);
    
#    @data = (@x, @predY);
#    my $graph = GD::Graph::points->new(400, 300);
#    
#    $graph->set
#    ( 
#     x_label           => 'Temperature',
#    y_label           => 'Etch Rate',
#   title             => 'Some simple graph',
#      y_max_value       => 100,
#      y_tick_number     => 100,
#      y_label_skip      => 2 
#      ) or die $my_graph->error;
#
#    my $gd = $my_graph->plot(\@data) or die $my_graph->error;
#    
    return @ans;
    
}


sub sum
{
    #this subroutine sums the numbers passed to it.  Returns a single 
+value.
    my $sum = 0;
    foreach my $line (@_)
    {
        $sum += $line;
    }
    return $sum;
}

sub sqr
{
    #Calculates the square of any array passed to it, returns an array
+ with the squares.
    my @xs = @_;
    my @result = map {$xs[$_] * $xs[$_]} 0..$#xs; #multiply each line 
+of an array together.
    return @result;
}