5
5
6
6
import tkinter as tk
7
7
from tkinter import filedialog
8
+ from tkinter import messagebox
9
+ import os
10
+ import sys
8
11
9
12
import numpy as np
10
13
import itertools
11
14
import csv
15
+ import re
12
16
13
17
class GFET_IO :
14
18
@@ -18,18 +22,41 @@ def __init__(self, *args, **kwargs):
18
22
self .extTransSweep = False
19
23
self .extIVSweep = False
20
24
25
+ # def resource_path(self, relative):
26
+ # return os.path.join(
27
+ # os.environ.get(
28
+ # sys._MEIPASS,
29
+ # os.path.abspath(".")
30
+ # ),
31
+ # relative
32
+ # )
33
+ def resource_path (self , relative_path ):
34
+ try :
35
+ base_path = sys ._MEIPASS
36
+ except Exception :
37
+ base_path = os .path .abspath ("." )
38
+ return os .path .join (base_path , relative_path )
39
+
21
40
# Load Values (dielectric materials etc. from txt file
22
- def loadDielectrics (self ):
23
- dielectrics = np .loadtxt ('Dielectrics.txt' , dtype = np .dtype ('O' ), delimiter = ',' , skiprows = 1 )
24
- return dielectrics
41
+ def loadDielectrics (self , root ):
42
+
43
+ filename = self .resource_path (os .path .dirname (os .path .abspath (__file__ ))) + "/Dielectrics.txt"
44
+ try :
45
+ dielectrics = np .loadtxt (filename , dtype = np .dtype ('O' ), delimiter = ',' , skiprows = 1 )
46
+ return dielectrics
47
+ except :
48
+ messagebox .showerror ("File Error" , "Error: Dielectrics.txt not found. Quitting..." )
49
+ root .destroy ()
50
+ sys .exit (1 )
51
+
25
52
26
53
def exportTransferChars (self , data ):
27
54
filename = filedialog .asksaveasfilename ()#mode='w', defaultextension=".csv")
28
55
if filename is None :
29
56
return
30
-
57
+
31
58
self .transData .update (data ["TransChars" ])
32
-
59
+
33
60
dataPairs = []
34
61
35
62
for index , Id in enumerate (self .transData ["Ids" ]): # for each entry in Ids
@@ -50,7 +77,7 @@ def exportTransferChars(self, data):
50
77
for dp in self .transData ["Vds" ]:
51
78
row = "Vtg (V):" + "," + "Ids (A):"
52
79
titlerow .append (row )
53
-
80
+
54
81
with open (filename + '.csv' , 'w' ) as f :
55
82
writer = csv .writer (f , quoting = csv .QUOTE_NONE , escapechar = " " )
56
83
writer .writerow (headerRow )
@@ -65,9 +92,9 @@ def exportIVChars(self, data):
65
92
66
93
if filename is None :
67
94
return
68
-
95
+
69
96
self .ivData .update (data ["IVChars" ])
70
-
97
+
71
98
dataPairs = []
72
99
73
100
for index , Id in enumerate (self .ivData ["Ids" ]): # for each entry in Ids
@@ -78,7 +105,7 @@ def exportIVChars(self, data):
78
105
dataPairs .append (column )
79
106
80
107
rows = list (zip (* itertools .chain (dataPairs )))
81
-
108
+
82
109
headerRow = []
83
110
for dp in self .ivData ["Vtg" ]:
84
111
row = "Vtg:" + ',' + str (dp )
@@ -88,7 +115,7 @@ def exportIVChars(self, data):
88
115
for dp in self .ivData ["Vtg" ]:
89
116
row = "Vds (V):" + "," + "Ids (A):"
90
117
titlerow .append (row )
91
-
118
+
92
119
with open (filename + '.csv' , 'w' ) as f :
93
120
writer = csv .writer (f , quoting = csv .QUOTE_NONE , escapechar = " " )
94
121
writer .writerow (headerRow )
@@ -102,11 +129,11 @@ def exportFreq(self, data):
102
129
filename = filedialog .asksaveasfilename ()#mode='w', defaultextension=".csv")
103
130
if filename is None :
104
131
return
105
-
132
+
106
133
self .transData .update (data ["TransChars" ])
107
-
134
+
108
135
dataPairs = []
109
-
136
+
110
137
111
138
for index , Id in enumerate (self .transData ["Ids" ]): # for each entry in Ids
112
139
column = []
@@ -127,7 +154,7 @@ def exportFreq(self, data):
127
154
for dp in self .transData ["Vds" ]:
128
155
row = "Vtg (V):" + "," + "Ids (A):" + "," + "fT (Hz)"
129
156
titlerow .append (row )
130
-
157
+
131
158
with open (filename + '.csv' , 'w' ) as f :
132
159
writer = csv .writer (f , quoting = csv .QUOTE_NONE , escapechar = " " )
133
160
writer .writerow (headerRow )
@@ -145,7 +172,7 @@ def loadSweep(self, sweepType):
145
172
146
173
if f == '' :
147
174
return
148
-
175
+
149
176
# Get the bias voltage(s) first
150
177
with open (f , newline = '' ) as csvfile :
151
178
reader1 , reader2 = itertools .tee (csv .reader (csvfile , delimiter = ',' ))
@@ -164,18 +191,18 @@ def loadSweep(self, sweepType):
164
191
if sweepType == "Gate" :
165
192
for column in range (columns ):
166
193
Vds .append (float (row1 [column ]))
167
- elif sweepType == "Drain" :
194
+ elif sweepType == "Drain" :
168
195
for column in range (columns ):
169
196
Vtg .append (float (row1 [column ]))
170
197
171
198
sweep = False
172
-
199
+
173
200
while sweep == False :
174
201
row1 = next (reader2 ) # iterate row in csv
175
-
202
+
176
203
# if the first number can be converted to a float,
177
204
# i.e. is a number, not a heading, break loop
178
- try :
205
+ try :
179
206
float (row1 [0 ])
180
207
sweep = True
181
208
except (ValueError , IndexError ) as e :
@@ -192,15 +219,15 @@ def loadSweep(self, sweepType):
192
219
Vtg .append (float (row1 [0 ]))
193
220
elif sweepType == "Drain" :
194
221
Vds .append (float (row1 [0 ]))
195
-
222
+
196
223
# Now get the sweeps. Should be third row onwards
197
224
if sweepType == "Gate" :
198
225
for row in reader2 :
199
226
Vtg .append (float (row [0 ]))
200
- elif sweepType == "Drain" :
227
+ elif sweepType == "Drain" :
201
228
for row in reader2 :
202
229
Vds .append (float (row [0 ]))
203
-
230
+
204
231
# Finally, update sweep data
205
232
if sweepType == "Gate" :
206
233
self .extTransSweep = True
@@ -217,8 +244,8 @@ def expTemp(self, biasVoltage, sweepVoltage):
217
244
filename = filedialog .asksaveasfilename () #Maybe Give a default name, but choose location
218
245
if filename is None :
219
246
return
220
-
221
- # First few rows as an example:
247
+
248
+ # First few rows as an example:
222
249
with open (filename + '.csv' , 'w' ) as f :
223
250
writer = csv .writer (f , quoting = csv .QUOTE_NONE , escapechar = " " )
224
251
writer .writerow ([biasVoltage ])
@@ -230,7 +257,7 @@ def expTemp(self, biasVoltage, sweepVoltage):
230
257
writer .writerow ("x" )
231
258
writer .writerow (["..." ])
232
259
f .close ()
233
-
260
+
234
261
def exportSPICEModel (self , model , params , eps1 , eps2 ):
235
262
if model == "Rodriguez" :
236
263
filename = filedialog .asksaveasfilename ()
@@ -239,7 +266,7 @@ def exportSPICEModel(self, model, params, eps1, eps2):
239
266
240
267
# Parse model parameters from variables
241
268
parameters = []
242
-
269
+
243
270
parameters .append ("+L= " + str (float (params [3 ])* 10 ** (- 6 )))
244
271
parameters .append ("+W=" + str (float (params [2 ])* 10 ** (- 6 )))
245
272
parameters .append ("+Tox=" + str (float (params [0 ])* 10 ** (- 9 )))
@@ -250,13 +277,13 @@ def exportSPICEModel(self, model, params, eps1, eps2):
250
277
251
278
# Probably will want to make the models a bit more dynamic
252
279
# in terms of loads, rather than hard-coding
253
-
280
+
254
281
headerLine = "* G D S"
255
282
subcktLine = ".subckt GFET_Rodriguez n1 n2 n3"
256
283
paramsLine = ".params"
257
284
modelDef = "BI n1 n2 I = abs((mu*W*Ctg*((V(n1)+Vth-V(n2)/2)))/((L/V(n2))+(mu/omega)*sqrt((pi*Ctg)/echarge)*sqrt(abs(V(n1)+Vth-V(n2)/2))))"
258
285
endsLine = ".ends GFET_Rodriguez"
259
-
286
+
260
287
with open (filename + '.lib' , 'w' ) as f :
261
288
f .write (headerLine + "\n " )
262
289
f .write (subcktLine + "\n " )
@@ -269,13 +296,13 @@ def exportSPICEModel(self, model, params, eps1, eps2):
269
296
# Write constants
270
297
f .write ("+e0 = 8.854e-12\n " )
271
298
f .write ("+pi = 3.141\n " )
272
-
299
+
273
300
# Write calculations
274
301
f .write ("+eox = {er*e0}\n " )
275
302
f .write ("+Ctg = {eox/Tox}\n " )
276
303
f .write ("+Vth = {(echarge*Nf)/Ctg}\n " )
277
304
f .write ("+omega={hw/(2*pi*planck)}\n " )
278
-
305
+
279
306
# Write model definition
280
307
f .write (modelDef + "\n " )
281
308
f .write (endsLine + "\n " )
@@ -288,26 +315,27 @@ def exportSPICEModel(self, model, params, eps1, eps2):
288
315
289
316
# Parse model parameters from variables
290
317
parameters = []
291
-
292
- parameters .append ("+L= " + str (float (params [3 ])* 10 ** (- 6 )))
293
- parameters .append ("+W=" + str (float (params [2 ])* 10 ** (- 6 )))
318
+
294
319
parameters .append ("+Tox1=" + str (float (params [0 ])* 10 ** (- 9 )))
295
320
parameters .append ("+Tox2=" + str (float (params [1 ])* 10 ** (- 9 )))
296
- parameters .append ("+er1= " + str (eps1 .get ().split ("(" )[1 ].replace (")" ,"" )))
297
- parameters .append ("+er2= " + str (eps1 .get ().split ("(" )[1 ].replace (")" ,"" )))
298
- parameters .append ("+mu= " + str (float (params [4 ]))) # cm2/Vs to m2/Vs
299
- parameters .append ("+hw= {" + str ((float (params [5 ]))) + "*echarge}" )
300
- parameters .append ("+Nf= " + str (float (params [6 ])))
321
+ parameters .append ("+W= " + str (float (params [2 ])* 10 ** (- 6 )))
322
+ parameters .append ("+L=" + str (float (params [3 ])* 10 ** (- 6 )))
323
+ parameters .append ("+hw=" + str (float (re .search ('(Ɛr=(.*), ħω=(.*))' , eps1 .get ()).group (3 )[:- 5 ])* 10 ** (- 3 )* consts .e ))
324
+ parameters .append ("+er1= " + str (re .search ('(Ɛr=(.*), ħω=(.*))' , eps1 .get ()).group (2 )))
325
+ parameters .append ("+er2= " + str (re .search ('(Ɛr=(.*), ħω=(.*))' , eps2 .get ()).group (2 )))
326
+ parameters .append ("+mun= " + str (float (params [4 ])* 10 ** (- 4 ))) # cm2/Vs to m2/Vs
327
+ parameters .append ("+mup= " + str (float (params [5 ])* 10 ** (- 4 )))
328
+ parameters .append ("+vF= " + str (float (params [6 ])))
329
+ parameters .append ("+Nf= " + str (float (params [7 ])))
301
330
302
331
# Probably will want to make the models a bit more dynamic
303
332
# in terms of loads, rather than hard-coding
304
-
305
- headerLine = "* G D S"
306
- subcktLine = ".subckt GFET_Jimenez n1 n2 n3"
333
+ headerLine = "* TG D S BG"
334
+ subcktLine = ".subckt GFET_Jimenez n1 n2 n3 n4"
307
335
paramsLine = ".params"
308
- modelDef = "BI n1 n2 I = ((mu *k)/2)*(W/Leff (V(n2)))*(g1( V(n1),V(n2))-g2( V(n1)))"
336
+ modelDef = "BI n1 n2 I = ((muAv *k)/2)*(W/leff (V(n1),V( n2),V(n4)))*(g(Vcd( V(n1),V(n2),V(n4)))-g(Vcs( V(n1),V(n4) )))"
309
337
endsLine = ".ends GFET_Jimenez"
310
-
338
+
311
339
with open (filename + '.lib' , 'w' ) as f :
312
340
f .write (headerLine + "\n " )
313
341
f .write (subcktLine + "\n " )
@@ -317,28 +345,32 @@ def exportSPICEModel(self, model, params, eps1, eps2):
317
345
for parameter in parameters :
318
346
f .write (parameter + "\n " )
319
347
320
- f .write ("+vF=1e6\n " )
321
348
f .write ("+e0=8.854e-12\n " )
322
- f .write ("+Vbg=0.0\n " )
323
- f .write ("+Vg0=0.85\n " )
324
- f .write ("+Vb0=0\n " )
325
-
349
+
326
350
# Write calculations
327
351
f .write ("+hbar={planck/(2*pi)}\n " )
328
352
f .write ("+omega={hw/hbar}\n " )
329
353
f .write ("+eox1={er1*e0}\n " )
330
354
f .write ("+eox2={er2*e0}\n " )
331
355
f .write ("+Ct={eox1/Tox1}\n " )
332
356
f .write ("+Cb={eox2/Tox2}\n " )
357
+ f .write ("+Vg0={(echarge*Nf)/Ct}\n " )
358
+ f .write ("+Vb0={(echarge*Nf)/Cb}\n " )
333
359
f .write ("+k={((2*(echarge**2))/pi)*(echarge/((hbar*vF)**2))}\n " )
360
+ f .write ("+beta={(echarge**3)/(pi*((hbar*vF)**2))}\n " )
361
+ f .write ("+delta={54*10**(-3)*echarge}\n " )
362
+ f .write ("+npud={(delta**2)/(pi*((hbar*vF)**2))}\n " )
363
+ f .write ("+alpha={mun/mup}\n " )
364
+ f .write ("+muAv={(mun+mup)/2}\n \n " )
334
365
335
366
# Write functions
336
- f .write (".func Leff(vds) {L+mu*(abs(vds)/vF)}\n " )
337
- f .write (".func Vcd(v,vds) {if((((v-Vg0-vds)*Ct+(Vbg-Vb0-vds)*Cb) > 0), ((-(Ct+Cb)+sqrt(((Ct+Cb)**2)+2*k*((v-Vg0-vds)*Ct+(Vbg-Vb0-vds)*Cb)))/(k)), ((-(Ct+Cb)+sqrt(((Ct+Cb)**2)-2*k*((v-Vg0-vds)*Ct+(Vbg-Vb0-vds)*Cb)))/(-k)))}\n " )
338
- f .write (".func Vcs(v) {if((((v-Vg0)*Ct+(Vbg-Vb0)*Cb) > 0), ((-(Ct+Cb)+sqrt(((Ct+Cb)**2)+2*k*((v-Vg0)*Ct+(Vbg-Vb0)*Cb)))/(k)), ((-(Ct+Cb)+sqrt(((Ct+Cb)**2)-2*k*((v-Vg0)*Ct+(Vbg-Vb0)*Cb)))/(-k)))}\n " )
339
- f .write (".func g1(v,vds) {(-(Vcd(v,vds)**3)/3)-sgn(Vcd(v,vds))*((k*(Vcd(v,vds)**4))/(4*(Ct+Cb)))}\n " )
340
- f .write (".func g2(v) {(-(Vcs(v)**3)/3)-sgn(Vcs(v))*((k*(Vcs(v)**4))/(4*(Ct+Cb)))}\n " )
341
-
367
+ f .write (".func Qnet(v,vds,vbg) {beta*(Vcd(v,vds,vbg)-Vcs(v,vbg))*abs((Vcd(v,vds,vbg)-Vcs(v,vbg)))}\n " )
368
+ f .write (".func vsat(v,vds,vbg) {omega/sqrt(((pi*abs(Qnet(v,vds,vbg)))/echarge)+npud/2)}\n " )
369
+ f .write (".func leff(v,vds,vbg) {L+muAv*(abs(vds)/vsat(v,vds,vbg))}\n " )
370
+ f .write (".func Vcd(v,vds,vbg) {if(((v-Vg0-vds)*Ct+(vbg-Vb0-vds)*Cb) > 0, alpha*(-(Ct+Cb)+sqrt(((Ct+Cb)**2)+2*k*((v-Vg0-vds)*Ct+(vbg-Vb0-vds)*Cb)))/(k), (-(Ct+Cb)+sqrt(((Ct+Cb)**2)-2*k*((v-Vg0-vds)*Ct+(vbg-Vb0-vds)*Cb)))/(-k))}\n " )
371
+ f .write (".func Vcs(v,vbg) {if((((v-Vg0)*Ct+(vbg-Vb0)*Cb) > 0), alpha*((-(Ct+Cb)+sqrt(((Ct+Cb)**2)+2*k*((v-Vg0)*Ct+(vbg-Vb0)*Cb)))/(k)), ((-(Ct+Cb)+sqrt(((Ct+Cb)**2)-2*k*((v-Vg0)*Ct+(vbg-Vb0)*Cb)))/(-k)))}\n " )
372
+ f .write (".func g(vc) {(-(vc**3)/3)-sgn(vc)*((k*(vc**4))/4*(Ct+Cb))}\n " )
373
+
342
374
# Write model definition
343
375
f .write (modelDef + "\n " )
344
376
f .write (endsLine + "\n " )
0 commit comments