Skip to content

Commit 34212aa

Browse files
author
Morvidus
committed
added prebuilt Windows and Mac executables, fixed some minor bugs
1 parent 1b0c5a5 commit 34212aa

38 files changed

+176027
-1421
lines changed

Dielectrics.txt

100644100755
Lines changed: 10 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,10 @@
1-
Material,Relative Permittivity
2-
SiO2,3.9
3-
Al2O3,9.1
4-
HfO2,23
5-
1L h-BN, 2.31
1+
Material,Relative Permittivity,Phonon Energy
2+
SiO2,3.9,59.98
3+
SiC,9.7,116
4+
Al2O3,12.53,55.01
5+
AlN,9.14,83.60
6+
HfO2,22.0,19.42
7+
ZrO2,24.0,25.02
8+
h-BN,5.09,101.6
9+
Air,1,0
10+
None,1,0

GFET Lab.spec

Lines changed: 44 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,44 @@
1+
# -*- mode: python ; coding: utf-8 -*-
2+
3+
4+
block_cipher = None
5+
6+
7+
a = Analysis(
8+
['main.py'],
9+
pathex=[],
10+
binaries=[],
11+
datas=[('Dielectrics.txt', '.')],
12+
hiddenimports=[],
13+
hookspath=[],
14+
hooksconfig={},
15+
runtime_hooks=[],
16+
excludes=[],
17+
win_no_prefer_redirects=False,
18+
win_private_assemblies=False,
19+
cipher=block_cipher,
20+
noarchive=False,
21+
)
22+
pyz = PYZ(a.pure, a.zipped_data, cipher=block_cipher)
23+
24+
exe = EXE(
25+
pyz,
26+
a.scripts,
27+
a.binaries,
28+
a.zipfiles,
29+
a.datas,
30+
[],
31+
name='GFET Lab',
32+
debug=False,
33+
bootloader_ignore_signals=False,
34+
strip=False,
35+
upx=True,
36+
upx_exclude=[],
37+
runtime_tmpdir=None,
38+
console=True,
39+
disable_windowed_traceback=False,
40+
argv_emulation=False,
41+
target_arch=None,
42+
codesign_identity=None,
43+
entitlements_file=None,
44+
)

GFET_IO.py

Lines changed: 86 additions & 54 deletions
Original file line numberDiff line numberDiff line change
@@ -5,10 +5,14 @@
55

66
import tkinter as tk
77
from tkinter import filedialog
8+
from tkinter import messagebox
9+
import os
10+
import sys
811

912
import numpy as np
1013
import itertools
1114
import csv
15+
import re
1216

1317
class GFET_IO:
1418

@@ -18,18 +22,41 @@ def __init__(self, *args, **kwargs):
1822
self.extTransSweep = False
1923
self.extIVSweep = False
2024

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+
2140
# 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+
2552

2653
def exportTransferChars(self, data):
2754
filename = filedialog.asksaveasfilename()#mode='w', defaultextension=".csv")
2855
if filename is None:
2956
return
30-
57+
3158
self.transData.update(data["TransChars"])
32-
59+
3360
dataPairs = []
3461

3562
for index, Id in enumerate(self.transData["Ids"]): # for each entry in Ids
@@ -50,7 +77,7 @@ def exportTransferChars(self, data):
5077
for dp in self.transData["Vds"]:
5178
row = "Vtg (V):" + "," + "Ids (A):"
5279
titlerow.append(row)
53-
80+
5481
with open(filename + '.csv', 'w') as f:
5582
writer = csv.writer(f, quoting=csv.QUOTE_NONE, escapechar=" ")
5683
writer.writerow(headerRow)
@@ -65,9 +92,9 @@ def exportIVChars(self, data):
6592

6693
if filename is None:
6794
return
68-
95+
6996
self.ivData.update(data["IVChars"])
70-
97+
7198
dataPairs = []
7299

73100
for index, Id in enumerate(self.ivData["Ids"]): # for each entry in Ids
@@ -78,7 +105,7 @@ def exportIVChars(self, data):
78105
dataPairs.append(column)
79106

80107
rows = list(zip(*itertools.chain(dataPairs)))
81-
108+
82109
headerRow = []
83110
for dp in self.ivData["Vtg"]:
84111
row = "Vtg:" + ',' + str(dp)
@@ -88,7 +115,7 @@ def exportIVChars(self, data):
88115
for dp in self.ivData["Vtg"]:
89116
row = "Vds (V):" + "," + "Ids (A):"
90117
titlerow.append(row)
91-
118+
92119
with open(filename + '.csv', 'w') as f:
93120
writer = csv.writer(f, quoting=csv.QUOTE_NONE, escapechar=" ")
94121
writer.writerow(headerRow)
@@ -102,11 +129,11 @@ def exportFreq(self, data):
102129
filename = filedialog.asksaveasfilename()#mode='w', defaultextension=".csv")
103130
if filename is None:
104131
return
105-
132+
106133
self.transData.update(data["TransChars"])
107-
134+
108135
dataPairs = []
109-
136+
110137

111138
for index, Id in enumerate(self.transData["Ids"]): # for each entry in Ids
112139
column = []
@@ -127,7 +154,7 @@ def exportFreq(self, data):
127154
for dp in self.transData["Vds"]:
128155
row = "Vtg (V):" + "," + "Ids (A):" + "," + "fT (Hz)"
129156
titlerow.append(row)
130-
157+
131158
with open(filename + '.csv', 'w') as f:
132159
writer = csv.writer(f, quoting=csv.QUOTE_NONE, escapechar=" ")
133160
writer.writerow(headerRow)
@@ -145,7 +172,7 @@ def loadSweep(self, sweepType):
145172

146173
if f == '':
147174
return
148-
175+
149176
# Get the bias voltage(s) first
150177
with open(f, newline='') as csvfile:
151178
reader1, reader2 = itertools.tee(csv.reader(csvfile, delimiter=','))
@@ -164,18 +191,18 @@ def loadSweep(self, sweepType):
164191
if sweepType == "Gate":
165192
for column in range(columns):
166193
Vds.append(float(row1[column]))
167-
elif sweepType == "Drain":
194+
elif sweepType == "Drain":
168195
for column in range(columns):
169196
Vtg.append(float(row1[column]))
170197

171198
sweep = False
172-
199+
173200
while sweep == False:
174201
row1 = next(reader2) # iterate row in csv
175-
202+
176203
# if the first number can be converted to a float,
177204
# i.e. is a number, not a heading, break loop
178-
try:
205+
try:
179206
float(row1[0])
180207
sweep = True
181208
except (ValueError, IndexError) as e:
@@ -192,15 +219,15 @@ def loadSweep(self, sweepType):
192219
Vtg.append(float(row1[0]))
193220
elif sweepType == "Drain":
194221
Vds.append(float(row1[0]))
195-
222+
196223
# Now get the sweeps. Should be third row onwards
197224
if sweepType == "Gate":
198225
for row in reader2:
199226
Vtg.append(float(row[0]))
200-
elif sweepType == "Drain":
227+
elif sweepType == "Drain":
201228
for row in reader2:
202229
Vds.append(float(row[0]))
203-
230+
204231
# Finally, update sweep data
205232
if sweepType == "Gate":
206233
self.extTransSweep = True
@@ -217,8 +244,8 @@ def expTemp(self, biasVoltage, sweepVoltage):
217244
filename = filedialog.asksaveasfilename() #Maybe Give a default name, but choose location
218245
if filename is None:
219246
return
220-
221-
# First few rows as an example:
247+
248+
# First few rows as an example:
222249
with open(filename + '.csv', 'w') as f:
223250
writer = csv.writer(f, quoting=csv.QUOTE_NONE, escapechar=" ")
224251
writer.writerow([biasVoltage])
@@ -230,7 +257,7 @@ def expTemp(self, biasVoltage, sweepVoltage):
230257
writer.writerow("x")
231258
writer.writerow(["..."])
232259
f.close()
233-
260+
234261
def exportSPICEModel(self, model, params, eps1, eps2):
235262
if model == "Rodriguez":
236263
filename = filedialog.asksaveasfilename()
@@ -239,7 +266,7 @@ def exportSPICEModel(self, model, params, eps1, eps2):
239266

240267
# Parse model parameters from variables
241268
parameters = []
242-
269+
243270
parameters.append("+L= " + str(float(params[3])*10**(-6)))
244271
parameters.append("+W=" + str(float(params[2])*10**(-6)))
245272
parameters.append("+Tox=" + str(float(params[0])*10**(-9)))
@@ -250,13 +277,13 @@ def exportSPICEModel(self, model, params, eps1, eps2):
250277

251278
# Probably will want to make the models a bit more dynamic
252279
# in terms of loads, rather than hard-coding
253-
280+
254281
headerLine = "* G D S"
255282
subcktLine = ".subckt GFET_Rodriguez n1 n2 n3"
256283
paramsLine = ".params"
257284
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))))"
258285
endsLine = ".ends GFET_Rodriguez"
259-
286+
260287
with open(filename + '.lib', 'w') as f:
261288
f.write(headerLine + "\n")
262289
f.write(subcktLine + "\n")
@@ -269,13 +296,13 @@ def exportSPICEModel(self, model, params, eps1, eps2):
269296
# Write constants
270297
f.write("+e0 = 8.854e-12\n")
271298
f.write("+pi = 3.141\n")
272-
299+
273300
# Write calculations
274301
f.write("+eox = {er*e0}\n")
275302
f.write("+Ctg = {eox/Tox}\n")
276303
f.write("+Vth = {(echarge*Nf)/Ctg}\n")
277304
f.write("+omega={hw/(2*pi*planck)}\n")
278-
305+
279306
# Write model definition
280307
f.write(modelDef + "\n")
281308
f.write(endsLine + "\n")
@@ -288,26 +315,27 @@ def exportSPICEModel(self, model, params, eps1, eps2):
288315

289316
# Parse model parameters from variables
290317
parameters = []
291-
292-
parameters.append("+L= " + str(float(params[3])*10**(-6)))
293-
parameters.append("+W=" + str(float(params[2])*10**(-6)))
318+
294319
parameters.append("+Tox1=" + str(float(params[0])*10**(-9)))
295320
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])))
301330

302331
# Probably will want to make the models a bit more dynamic
303332
# 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"
307335
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))))"
309337
endsLine = ".ends GFET_Jimenez"
310-
338+
311339
with open(filename + '.lib', 'w') as f:
312340
f.write(headerLine + "\n")
313341
f.write(subcktLine + "\n")
@@ -317,28 +345,32 @@ def exportSPICEModel(self, model, params, eps1, eps2):
317345
for parameter in parameters:
318346
f.write(parameter + "\n")
319347

320-
f.write("+vF=1e6\n")
321348
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+
326350
# Write calculations
327351
f.write("+hbar={planck/(2*pi)}\n")
328352
f.write("+omega={hw/hbar}\n")
329353
f.write("+eox1={er1*e0}\n")
330354
f.write("+eox2={er2*e0}\n")
331355
f.write("+Ct={eox1/Tox1}\n")
332356
f.write("+Cb={eox2/Tox2}\n")
357+
f.write("+Vg0={(echarge*Nf)/Ct}\n")
358+
f.write("+Vb0={(echarge*Nf)/Cb}\n")
333359
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")
334365

335366
# 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+
342374
# Write model definition
343375
f.write(modelDef + "\n")
344376
f.write(endsLine + "\n")

0 commit comments

Comments
 (0)