#! /usr/bin/env python # This will generate the conductance versus surface potential curves # for undoped Germanium, 15 Ohm-cm n-Germanium, 4 k-cm FZ Si, # or 70 Ohm-cm n-Si # Requires python, numpy, and scipy, which can be obtained from # http://www.scipy.org from math import * from numpy import * import csv import sys #print sys.argv[1] # set up the array of sp values v = linspace( -60.,30.,900 ) while True: try: print "0 - Conductance Curve, 1 - Conversion to Potential" purp = int(raw_input('-->')) break except ValueError: print "Try again..." while True: try: print "0 - Undoped Ge, 1 - 15 Ohm-cm n-Ge, 2 - 4k-cm FZ Si, 3 - 70 Ohm-cm Si" dope = int(raw_input('-->')) break except ValueError: print "Try again..." if dope <= 1: # parameters for Ge kappa = 16 e0 = 8.85e-014 # F/cm q = 1.60e-19 #C ni = 2.40e+13 #cm-3 k = 8.61e-05 #eV/K L = 6.8e-05 #cm debye, intrinsic T = 300 # K mun = 3800 # mup = 1820 # else: # parameters for Si kappa = 11.9 e0 = 8.85e-014 # F/cm q = 1.60e-19 #C ni = 1.45e+10 #cm-3 k = 8.61e-05 #eV/K L = 2.4e-03 #cm debye, intrinsic T = 300 # K mun = 1500 # cm2/V-s mup = 450 # if dope == 0: # Ge-Intrinsic # gmind is for minority carriers under depletion/inversio # gmaja is for majority carriers under accumulation, etc. def gp(x): return exp(0.5*abs(x))-1 def gn(x): return exp(-0.5*abs(x))-1 gmind = 2*L*ni*gp(v) gmina = 2*L*ni*gn(v) # calling electrons majority, even for intrinsic gmaja = gmind gmajd = gmina # These values use: # nb = impurity concentration (Hall or fig.22 Ch1 Sze) elif dope == 1: # Ge-15 Ohm-cm nb = 1.0e+14 pb = (ni**2)/nb ub = log(nb/ni) Le = L*(((2*ni)/(nb+pb))**0.5) #effective Debye length elif dope == 2: # Si-4 k-cm nb = 4.5e+11 pb = (ni**2)/nb ub = log(nb/ni) Le = L*(((2*ni)/(nb+pb))**0.5) elif dope == 3: # Si-70 Ohm-cm nb = 6.6e+13 pb = (ni**2)/nb ub = log(nb/ni) Le = L*(((2*ni)/(nb+pb))**0.5) # now calculate for extrinsic if dope == 1 or dope == 2 or dope == 3: def fuv1(ub,v1): return cosh(ub+v1)/cosh(ub) def fuv2(ub,v1): return 2.*fuv1(ub,v1)-2.*v1*tanh(ub)-2 def fuv3(ub,v1): return fuv2(ub,v1)**0.5 # majority carriers, accumulation def integrand_maja(v1): return (exp(v1)-1.)/fuv3(abs(ub),v1) # majority carriers, depletion def integrand_majd(v1): return (exp(-v1)-1.)/fuv3(-abs(ub),v1) # minority carriers, accumulation def integrand_mina(v1): return exp(-2.*abs(ub))*(exp(-v1)-1.)/fuv3(abs(ub),v1) # minority carriers, depletion def integrand_mind(v1): return exp(-2.*abs(ub))*(exp(v1)-1.)/fuv3(-abs(ub),v1) # integration from scipy.integrate import quad def gna(ub,vs): return quad(integrand_maja,0.,abs(vs),args=())[0] def gnd(ub,vs): return quad(integrand_majd,0.,abs(vs),args=())[0] def gpa(ub,vs): return quad(integrand_mina,0.,abs(vs),args=())[0] def gpd(ub,vs): return quad(integrand_mind,0.,abs(vs),args=())[0] gmaja = zeros((900),dtype=float) gmina = zeros((900),dtype=float) gmind = zeros((900),dtype=float) gmajd = zeros((900),dtype=float) it=0 while it < 900: gmaja[it] += Le*nb*gna(ub,abs(v[it])) gmina[it] += Le*nb*gpa(ub,abs(v[it])) gmajd[it] += Le*nb*gnd(ub,abs(v[it])) gmind[it] += Le*nb*gpd(ub,abs(v[it])) it = it + 1 # this is more generalized # array 'sig' has two axes, 600 is for each surface potential # 2 is for (x-sp,y-sc) sig = zeros((900,2), dtype=float) # only add to depleted/inverted sig[0:599,1] += mun*gmajd[0:599] sig[0:599,1] += mup*gmind[0:599] # only add to accumulated sig[600:899,1] += mun*gmaja[600:899] sig[600:899,1] += mup*gmina[600:899] # multiply by q and we are done sig[:,1] *= q sig[:,0] += v if purp == 0: fest = csv.writer(open('/home/dk246/Thesis/SPmap_pub/curveout-dummy.csv','w'),delimiter=' ') print fest it=0 while it < 899: fest.writerow([sig[it,0],sig[it,1]]) it = it + 1 #################################################################### if purp == 1: # find the minimum it = 0 cmin = 1.0e-03 # an unlikely value while it < 899: if sig[it,1] < cmin: cmin = sig[it,1] pmin = sig[it,0] it = it + 1 # now the data actually gets read # The file to read filein = '/home/dk246/Thesis/SPmap/SPmap_in/%s.csv' % (sys.argv[1]) fileout = '/home/dk246/Thesis/SPmap/SPmap_out/%s.csv' % (sys.argv[1]) f = open(filein,'r') af=f.readlines() l=0 # line number data_out = zeros((len(af),2), dtype=float) apot_old = -50. # so that we choose the correct arm of curve # it needs to be changed for the oxide a_old = 1.0e-3 while l < len(af): # len(af) is from readlines ax = af[l] it=0 while it < 20: # 20 is just a nice size it += 1 if ax[it] == ',': break a = float(ax[0:it]) # a is the conductacnce # the data is conductance change relative to minimum, but calculations are relaive to flat-band a = a + cmin b = float(ax[it+1:-2]) # b is the SRV it = 0 ahold1 = 1.0e-03 # some unlikely residual ahold2 = 1.0e-03 # some unlikely residual apot_out = 0. while it < 899: adiff = a - sig[it,1] if abs(adiff) < abs(ahold1) and sig[it,0] < pmin: apot1 = sig[it,0] ahold1 = adiff elif abs(adiff) < abs(ahold2) and sig[it,0] > pmin: apot2 = sig[it,0] ahold2 = adiff it = it + 1 # two unambiguous cases # conductance is decreasing, and old potential is closer to negative choice if a < a_old and abs(apot_old - apot1) < abs(apot_old - apot2): apot_out = apot1 apot_old = apot1 a_old = a # conductance has increased, and old potential is closer to positive choice elif a >= a_old and abs(apot_old - apot1) >= abs(apot_old - apot2): apot_out = apot2 apot_old = apot2 a_old = a # ambiguous cases # the coductance has increased, but last potential is closer to negative choice # choose negative potential, but store positive potential and don't overwrite the old conductance. # If it is not a jitter, the next one will be increased too # and stored potential will be closer to positive choice next time # If it is jitter, the next conductance will not be increased and will be dealt with below elif a >= a_old and abs(apot_old - apot1) < abs(apot_old - apot2): if abs(abs(apot_old - apot1) - abs(apot_old - apot2)) < 3.0: # about 75 mV apot_out = apot2 # it is a toss-up, just proceed apot_old = apot2 else: apot_out = apot1 apot_old = apot2 # The conductance has decreased, but last potential is closer to poitive choice # choose positive potential but store negative and don't overwrite conductance # If it is not jitter, next conductance will decrease too, and stored potential # will be closer to negative next time # If it is jitter, next conductance will increase but stored potential will be # closer to negative, so it will go to case above for one value, then get back on track else: if abs(abs(apot_old - apot1) - abs(apot_old - apot2)) < 3.0: apot_out = apot1 apot_old = apot1 else: apot_out = apot2 apot_old = apot1 # so that output is in volts apot_out *= k*T data_out[l,0] = apot_out data_out[l,1] = b l = l + 1 it = 0 f2 = csv.writer(open(fileout,'w'),delimiter=' ') while it < len(af): f2.writerow([data_out[it,0],data_out[it,1]]) it = it + 1