def main(): """Main function""" print "\nBatch importing .csv files..." print data_path, '\n' for f in files: print f # Loops through all transfer files if "Bias Stress" not in f: continue datatransfer, datastress = mf.csvBiasStressImport(f, data_path) no_scans = len(datatransfer) no_stress = len(datastress) stress_time = datastress[0]['Time'][-1] for s in xrange(no_scans): print " Scan number:", s+1 outname = "{:s}_{:03d}".format(re.sub("[^\[]*\[|_;|]", "", f[:-4].replace(' ', '_')), s+1) vd = np.array(datatransfer[s]['Vdrain'][0]) vg = np.array(datatransfer[s]['Vgate']) ids = np.array(datatransfer[s]['absIdrain']) igs = np.array(datatransfer[s]['absIgate']) if doublesweep: ids_forward = ids[:len(ids)/2] vg_forward = vg[:len(vg)/2] else: ids_forward = ids vg_forward = vg ids_smoothed = mf.adjAvSmooth(abs(ids_forward), N=1) diff_ids_smoothed = np.array(mf.numDiff(ids_smoothed, vg_forward)) tlmaxarg = np.argmax(diff_ids_smoothed[skipinit:-1]) + skipinit # Linear mobility (max transconductance) linmob_tmax = (chl/(chw*ci*vd))*(diff_ids_smoothed[tlmaxarg]) # Linear threshold voltage (max transconductance) vthlin_tmax = vg[tlmaxarg] - ids_smoothed[tlmaxarg]/diff_ids_smoothed[tlmaxarg] # Linear mobility at vth + 1 V linmob_constn = (chl/(chw*ci*vd))*np.interp(vthlin_tmax + 1.0, vg_forward, diff_ids_smoothed) # Subthreshold slope lin_sts = min(abs(1/np.array(mf.numDiff([np.log10(abs(x)) for x in ids_smoothed[skipinit:-1]], vg_forward[skipinit:-1])))) data_summary.append([outname, linmob_tmax, vthlin_tmax, linmob_constn, lin_sts]) mf.dataOutput(outname + "_transfer.txt", data_path, [vg, ids, igs], format="%.2f\t %.5e\t %.5e\n") # Plot transfer if plot: mf.quickPlot(outname + "_TRANSFERplot", data_path, [vg, ids, igs], xlabel="Vg [V]", ylabel="Id,g [A]", yscale="log", yrange=[1e-12, 1e-3]) mf.quickPlot(outname + "_TCplot", data_path, [vg_forward, ids_smoothed], xlabel="Vg [V]", ylabel="Id [A]") if s < no_stress: time = np.array(datastress[s]['Time']) idsst = np.array(datastress[s]['absIdStress']) igsst = np.array(datastress[s]['absIgStress']) mf.dataOutput(outname + "_stress.txt", data_path, [time, idsst, igsst], format="%.2f\t %.5e\t %.5e\n") mf.dataOutput("BIAS_STRESS_SUMMARY.txt", data_path, map(list, zip(*data_summary)), format="%s\t %.5e\t %.5f\t %.5e\t %.5e\n") return
def main(): """Main function""" print "\nBatch importing .xlsx files..." print data_path, '\n' for f in files: print f # Loops through all transfer files if "IDVG.xlsx" in f: workbook = xlrd.open_workbook(f, logfile=open(os.devnull, 'w')) for dev in workbook.sheet_names(): if "Sheet" in dev: continue print " - device {:s}".format(dev) datasheet = workbook.sheet_by_name(dev) run_numbers = [str(int(x)) for x in datasheet.row_values(2) if x] for i, run in enumerate(run_numbers): print " - run {:s}".format(run) data = {} # File name for outputs outname = f[:-5] + '_' + dev + '_' + run # Constant parameters taken from header of .xlsx file vd1 = float(datasheet.cell_value(3, 6*i + 3)) vd2 = float(datasheet.cell_value(4, 6*i + 3)) chl = float(datasheet.cell_value(1, 1)) chw = float(datasheet.cell_value(0, 1)) tox = float(datasheet.cell_value(1, 3)) kox = float(datasheet.cell_value(0, 3)) ldr = float(datasheet.cell_value(1, 5)) lso = float(datasheet.cell_value(0, 5)) # Calculation of geometric capacitance ci = 8.85418782e-7*kox/tox # Extract data for h in colheads: data[h] = [] for row in range(datasheet.nrows - 9): for col, h in enumerate(colheads): if datasheet.cell_type(9 + row, 6*i + col) is 0: continue data[h].append(float(datasheet.cell_value(9 + row, 6*i + col))) p = len(data['VG'])/2 # Forward scan if sweepfwddirection: vg = np.array(data['VG'][:p]) id1 = np.array(data['ID1'][:p]) id2 = np.array(data['ID2'][:p]) ig1 = np.array(data['IG1'][:p]) ig2 = np.array(data['IG2'][:p]) else: vg = np.array(data['VG'][:p][::-1]) id1 = np.array(data['ID1'][:p][::-1]) id2 = np.array(data['ID2'][:p][::-1]) ig1 = np.array(data['IG1'][:p][::-1]) ig2 = np.array(data['IG2'][:p][::-1]) # Reverse scan if sweepfwddirection: vg_r = np.array(data['VG'][p:][::-1]) id1_r = np.array(data['ID1'][p:][::-1]) id2_r = np.array(data['ID2'][p:][::-1]) ig1_r = np.array(data['IG1'][p:][::-1]) ig2_r = np.array(data['IG2'][p:][::-1]) else: vg_r = np.array(data['VG'][p:]) id1_r = np.array(data['ID1'][p:]) id2_r = np.array(data['ID2'][p:]) ig1_r = np.array(data['IG1'][p:]) ig2_r = np.array(data['IG2'][p:]) # Smoothing Id for fitting id1_smoothed = mf.adjAvSmooth(abs(id1), N=1) id2_smoothed = mf.adjAvSmooth(abs(id2), N=1) id1_r_smoothed = mf.adjAvSmooth(abs(id1_r), N=1) id2_r_smoothed = mf.adjAvSmooth(abs(id2_r), N=1) # On-off ratio onoffratio1 = np.log10(max(id1[skipinit:-1])/min(abs(id1[skipinit:-1]))) onoffratio2 = np.log10(max(id2[skipinit:-1])/min(abs(id2[skipinit:-1]))) # Leakage ratio leakage_ratio1 = np.log10(abs(id1/ig1)) leakage_ratio2 = np.log10(abs(id2/ig2)) # Finding max saturation transconductance sqrtid2 = np.sqrt(id2_smoothed) sqrtid2_r = np.sqrt(id2_r_smoothed) diff_sqrt_id2_smoothed = np.array(mf.numDiff(sqrtid2, vg)) diff_sqrt_id2_r_smoothed = np.array(mf.numDiff(sqrtid2_r, vg_r)) tsmaxarg = np.argmax(diff_sqrt_id2_smoothed[skipinit:-1]) + skipinit tsmaxarg_r = np.argmax(diff_sqrt_id2_r_smoothed[skipinit:-1]) + skipinit # Saturation mobility (max transconductance) satmob_t = mobilitycorrection * (2*chl/(chw*ci))*(diff_sqrt_id2_smoothed)**2 satmob_r_t = mobilitycorrection * (2*chl/(chw*ci))*(diff_sqrt_id2_r_smoothed)**2 satmob_tmax = satmob_t[tsmaxarg] satmob_r_tmax = satmob_r_t[tsmaxarg_r] # Saturation threshold voltage (max transconductance) vthsat_tmax = vg[tsmaxarg] - sqrtid2[tsmaxarg]/diff_sqrt_id2_smoothed[tsmaxarg] vthsat_r_tmax = vg_r[tsmaxarg_r] - sqrtid2_r[tsmaxarg_r]/diff_sqrt_id2_r_smoothed[tsmaxarg_r] # Hysteresis hysteresissat = vthsat_tmax - vthsat_r_tmax # Calculate subthreshold slopes sts_sat = min(abs(1/np.array(mf.numDiff([np.log10(abs(x)) for x in id2_smoothed[skipinit:-1]], vg[skipinit:-1])))) sts_r_sat = min(abs(1/np.array(mf.numDiff([np.log10(abs(x)) for x in id2_r_smoothed[skipinit:-1]], vg_r[skipinit:-1])))) # Finding max linear transconductance diff_id1_smoothed = np.array(mf.numDiff(id1_smoothed, vg)) diff_id1_r_smoothed = np.array(mf.numDiff(id1_r_smoothed, vg_r)) tlmaxarg = np.argmax(diff_id1_smoothed[skipinit:-1]) + skipinit tlmaxarg_r = np.argmax(diff_id1_r_smoothed[skipinit:-1]) + skipinit # Linear mobility (max transconductance) linmob_t = mobilitycorrection * (chl/(chw*ci*vd1))*(diff_id1_smoothed) linmob_r_t = mobilitycorrection * (chl/(chw*ci*vd1))*(diff_id1_r_smoothed) linmob_tmax = linmob_t[tlmaxarg] linmob_r_tmax = linmob_r_t[tlmaxarg_r] # Linear threshold voltage (max transconductance) vthlin_tmax = vg[tlmaxarg] - id1_smoothed[tlmaxarg]/diff_id1_smoothed[tlmaxarg] vthlin_r_tmax = vg_r[tlmaxarg_r] - id1_r_smoothed[tlmaxarg_r]/diff_id1_r_smoothed[tlmaxarg_r] # Hysteresis hysteresislin = vthlin_tmax - vthlin_r_tmax # Calculate subthreshold slopes sts_lin = min(abs(1/np.array(mf.numDiff([np.log10(abs(x)) for x in id1_smoothed[skipinit:-1]], vg[skipinit:-1])))) sts_r_lin = min(abs(1/np.array(mf.numDiff([np.log10(abs(x)) for x in id1_r_smoothed[skipinit:-1]], vg_r[skipinit:-1])))) # Finds range of data that lies within the minimum+x% and the maximum-x% and also has a positive transconductance fitrange_id_lo = (1-rangefitbot/100.0)*min(sqrtid2[skipinit:-1]) + (rangefitbot/100.0)*max(sqrtid2[skipinit:-1]) fitrange_id_hi = (1-rangefittop/100.0)*max(sqrtid2[skipinit:-1]) + (rangefittop/100.0)*min(sqrtid2[skipinit:-1]) fitrange_bool = np.bitwise_and(np.bitwise_and(sqrtid2 > fitrange_id_lo, sqrtid2 < fitrange_id_hi), diff_sqrt_id2_smoothed > 0) # Checks that there are at least 3 data points to fit if sum(fitrange_bool) < 3: print " NOT ENOUGH DATA TO FIT" satmob_FITTED = np.nan vthsat_FITTED = np.nan r_value = np.nan else: # Linear Fitting to sqrt(Idrain) slope, intercept, r_value, p_value, std_err = stats.linregress(vg[fitrange_bool][skipinit:-1], sqrtid2[fitrange_bool][skipinit:-1]) fitline = slope*vg + intercept # Saturation mobility (from slope of sqrt(Idrain) fit) satmob_FITTED = mobilitycorrection * (2*chl/(chw*ci))*slope**2 # Threshold Voltage (from slope of sqrt(Idrain) fit) vthsat_FITTED = -intercept/slope # Plot sqrt(Isd) mf.quickPlot(outname+"_SQRTplot", data_path, [vg, sqrtid2, fitline], xlabel="VG [V]", ylabel="sqrt(Id) [A^0.5]", yrange=[0, 'auto']) # Output data data_summary.append([outname, satmob_tmax, vthsat_tmax, satmob_r_tmax, vthsat_r_tmax, linmob_tmax, vthlin_tmax, linmob_r_tmax, vthlin_r_tmax, hysteresislin, hysteresissat, onoffratio1, onoffratio2, leakage_ratio1[-skipinit], leakage_ratio2[-skipinit], sts_lin, sts_r_lin, sts_sat, sts_r_sat, satmob_FITTED, vthsat_FITTED, r_value**2]) # Ouput files mf.dataOutputHead(outname+"_transfer.txt", data_path, [np.array(data['VG']), abs(np.array(data['ID1'])), abs(np.array(data['ID2'])), abs(np.array(data['IG1'])), abs(np.array(data['IG2'])), np.concatenate((linmob_t, linmob_r_t[::-1])), np.concatenate((satmob_t, satmob_r_t[::-1]))], [["vg", "idlin", "idsat", "iglin", "igsat", "LINMOB", "SATMOB"]], format_d="%.3f\t %.5e\t %.5e\t %.5e\t %.5e\t %.5e\t %.5e\n", format_h="%s\t") # Plot transfer mf.quickPlot(outname+"_TRANSFERplot", data_path, [vg, id1_smoothed, id1_r_smoothed, abs(ig1), id2_smoothed, id2_r_smoothed, abs(ig2)], xlabel="VG [V]", ylabel="Id,g [A]", yscale="log", yrange=[1e-12, 1e-2], col=["r", "r", "r", "b", "b", "b"]) mf.dataOutputHead("SUMMARY.txt", data_path, map(list, zip(*data_summary)), summary_list_header, format_d="%s\t %.5e\t %.5f\t %.5e\t %.5f\t %.5e\t %.5f\t %.5e\t %.5f\t %.5f\t %.5f\t %.5f\t %.5f\t %.5f\t %.5f\t %.5f\t %.5f\t %.5f\t %.5f\t %.5e\t %.5f\t %.6f\n", format_h="%s\t") return