Friday, June 21, 2024

I used Perl today

Let me dump the script first, then I'll talk about it:

#!perl
# Combine_KeysightResistance_Data_Into_Excel_20240620.pl
# Jovan Trujillo
# AEP Core - MTW
# Arizona State University
# 8/7/2023
#
#
# Usage: perl Combine_KeysightResistance_Data_Into_Excel_20240620.pl "path-to-data-folder"
# ChangeLog:
# Version 0.1 - Need to standardize on data input file format. Not sure it this script works yet.
# Version 0.2 - Porting what does work from Combine_Capacitance_Data_Into_Excel.pl
#

use Modern::Perl;
use File::Find;
use Switch;
use Excel::Writer::XLSX;

our $Excelbook = Excel::Writer::XLSX->new('Combined_KeysightResistance_Data.xlsx');
        die "Problems creating new Excel file: $!" unless defined $Excelbook;
our $Excelsheet = $Excelbook->add_worksheet('Summary');
our $row = 0;
our $col = 0;

sub main {
    if ($#ARGV != 0) {
        print "Usage: perl Combine_KeysightResistance_Data_Into_Excel_20240620.pl path-to-data-folder\n";
    } else {
       
        # ControlPanel will provide interface for Excel Macros embedded into the data collected into this spreadsheet. Will be useful for generating the plots I want, unless PDL can do it more efficiently for me.
        # Need to write some chart making macros in Excel and export the VBA as a binary. The Excel::Writer::XLSX module has a program to help me do that.
        # From the command line.
       
        #Create header in Summary worksheet.
        $Excelsheet->write($row,$col,"Lot");
        $col = $col + 1;
        $Excelsheet->write($row,$col,"Wafer");
        $col = $col + 1;
        $Excelsheet->write($row,$col,"X");
        $col = $col + 1;
        $Excelsheet->write($row,$col,"Y");
        $col = $col + 1;
        $Excelsheet->write($row,$col,"Die #");
        $col = $col + 1;
        $Excelsheet->write($row,$col,"Avg. Resistance");
        $col = $col + 1;
        $Excelsheet->write($row,$col,"StdDev. Resistance");
        $col = $col + 1;
        $Excelsheet->write($row,$col,"Date");
        $col = $col + 1;
        $Excelsheet->write($row,$col,"Time");
       
        my $folder = shift @ARGV;
        print "Search for resistance data in: " . $folder . "\n";
        my (@dir) = $folder;
        find(\&process_file, @dir);
        $Excelbook->close();
    }
}

sub process_file {
    # print $File::Find::name."\n";
    my $filepath = $File::Find::name;
    my $date;
    my $time;
    my $X;
    my $Y;
    my $DieNum;
    my $Wafer;
    my $Lot;
    my $Excelbook = shift @_;
    
    my $filename = $_;
    #print "filename: $filename\n";
    if ( -f $filepath) {
        # print " This is a file: $filename \n";
        if ( $filename =~ /Residual\sR\s\[(\w\w\w\w\w\-\d\d\d)-([\d]*)\s_\s(\d+)\s(\d+)\s\s\(([\d]*)\)\s;\s([\d\_]*)\s([\w\s\_]*)\]\.csv/ ) {
            #print " This is a file : $filename \n";
            $Lot = $1;
            $Wafer = $2;
            $X = $3;
            $Y = $4;
            $DieNum = $5;
            $date = $6;
            $time = $7;
            #print "\nProcessing: $filename\n\n";
            &analysis($filepath, $filename, $Lot, $Wafer, $X, $Y, $DieNum, $date, $time);
        } else {
            print "Not valid filename regex: " . $filename . "\n";
        }
    } else {
        # Keep looking for valid data files.
        say "Not a valid file path\n";
    }
}

sub analysis() {
    # Calculate average residual resistance for each file and save to Excel spreadsheet.
    my $filepath = shift @_;
    my $filename = shift @_;
    my $Lot = shift @_;
    my $Wafer = shift @_;
    my $X = shift @_;
    my $Y = shift @_;
    my $DieNum = shift @_;
    my $date = shift @_;
    my $time = shift @_;
    my $resTot = 0.0;
    my $count = 0;
    my $resAvg = 0.0;
    my $Label;
    my $Vm;
    my $If;
    my $Ta;
    my $ResidualR;
    my $resDev = 0.0;
    my @resData;
    open DATA, "<$filepath" or die "Error opening file $filename: $!\n";
    # There is a lot of cruft I need to sift through before I get to the meat of the data file
    while (<DATA>) {
        # Look for DataName     Vm     If     Ta     ResidualR Field and Parse for ResidualR data
        # Look for DataValue in line to know when to split for ResidualR data values.
        if ($_ =~ /DataValue/) {
            ($Label, $Vm, $If, $Ta, $ResidualR) = split(/,/,$_,5);
            push(@resData, $ResidualR);
            $resTot = $resTot + $ResidualR;
            $count = $count + 1;
        }
    }
    # Done reading data file, time to caculate average resistance from the dataset.
    $resAvg = $resTot/$count;
    for (my $i=0; $i < $count; $i++) {
        $resDev = $resDev + ($resData[$i]-$resAvg)**2;
    }
    $resDev = sqrt($resDev / $count);
    undef @resData;
    print "$Lot, $Wafer, $X, $Y, $DieNum, $resAvg, $resDev, $date, $time\n";
    
    # Save data to Excel Workbook
    #Columns are:
    # 0 - Lot
    # 1 - Wafer
    # 2 - Die X Index
    # 3 - Die Y Index
    # 4 - Die #
    # 5 - Average Resistance
    # 6 - Standard Deviation Resistance
    # 7 - Date
    # 8 - Time
    $row = $row + 1;
    $Excelsheet->write($row,0,$Lot);
    $Excelsheet->write($row,1,$Wafer);
    $Excelsheet->write($row,2,$X);
    $Excelsheet->write($row,3,$Y);
    $Excelsheet->write($row,4,$DieNum);
    $Excelsheet->write($row,5,$resAvg);
    $Excelsheet->write($row,6,$resDev);
    $Excelsheet->write($row,7,$date);
    $Excelsheet->write($row,8,$time);
    
    close(DATA);
    
}


&main();

1;

 

This was needed to compile the hundreds of CSV text files my Keysight B1505A instrument was spewing out while it collected contact resistance data from 100 die in each of 8 wafers tested. A lot of data, and each file contained 10 resistance values that I needed to average out and calculate the standard deviation of. Overall I was actually able to reuse a previous script that did similar work for Kelvin sheet resistance data that I was collecting using the Keithley 4200. In that case each file contained coordinate data and anywhere from 1 to 40 resistivity points for me to compile and average out into a Spreadsheet to make a pretty map of the sheet resistance variation on a wafer's surface. I'm doing the same thing here, but the file name for the text files is a lot messier. Here is an example of what I'm talking about:

Residual R [E2424-002-02 _ 3 7  (77) ; 6_20_2024 10_46_59 AM].csv 

That was a fun regular expression exercise parsing everything I needed out of that file name. But I did it, and it worked, and it created this nice table of values in an Excel spreadsheet for the team to analyze. 


 Now I can use Minitab to slurp up this Excel spreadsheet and compare differences between wafers and within wafers. Some fine data munging done today with some proper code reuse to boot.