blob: 282b201676c95728ae49b7a225c170215b2e7d73 [file] [log] [blame]
import os
import pandas as pd
from spice import NgSpice
def plotGmIdCurves(transistor_type, vsb):
from matplotlib import pyplot as plt
#TRANSISTOR_TYPES=['nfet_01v8_lvt', 'pfet_01v8_lvt', 'pfet_01v8_hvt', 'nfet_01v8', 'pfet_01v8']
#TRANSISTOR_TYPE='pfet_01v8'
#TRANSISTOR_TYPE='nfet_01v8'
TRANSISTOR_TYPE=transistor_type
#file_in='/home/simon/code/asic/analog/transistors/test_nmos4.spice'
#workingDir='/home/simon/code/asic/analog/transistors/outdata_nmos_lvt_US_0_6V'
#workingDir='/home/simon/code/asic/analog/transistors/outdata_nmos_lvt'
workingDir='/home/simon/code/asic/analog/transistors/'
workingDir=os.path.join(workingDir, 'vsb_{}'.format(vsb))
if TRANSISTOR_TYPE=='pfet_01v8':
file_in='/home/simon/code/asic/analog/transistors/test_pmos.spice'
workingDirT='outdata_pmos'
l=[0.15, 0.2, 0.3, 0.5, 1, 2, 4, 6]
if TRANSISTOR_TYPE=='pfet_01v8_lvt':
file_in='/home/simon/code/asic/analog/transistors/test_pmos_lvt.spice'
workingDirT='outdata_pmos_lvt'
l=[0.35, 0.5, 1, 2, 4, 6]
if TRANSISTOR_TYPE=='pfet_01v8_hvt':
file_in='/home/simon/code/asic/analog/transistors/test_pmos_hvt.spice'
workingDirT='outdata_pmos_hvt'
l=[0.15, 0.2, 0.3, 0.5, 1, 2, 4, 6]
if TRANSISTOR_TYPE=='nfet_01v8':
file_in='/home/simon/code/asic/analog/transistors/test_nmos.spice'
workingDirT='outdata_nmos'
l=[0.15, 0.2, 0.3, 0.5, 1, 2, 4, 6]
if TRANSISTOR_TYPE=='nfet_01v8_lvt':
file_in='/home/simon/code/asic/analog/transistors/test_nmos_lvt.spice'
workingDirT='outdata_nmos_lvt'
l=[0.15, 0.2, 0.3, 0.5, 1, 2, 4, 6]
vsb=[vsb]*len(l)
width={'L': l, 'VSB': vsb}
if not os.path.exists(workingDir):
os.mkdir(workingDir)
workingDir=os.path.join(workingDir, workingDirT)
if not os.path.exists(workingDir):
os.mkdir(workingDir)
#workingDir='/home/simon/code/asic/analog/transistors/outdata_nmos'
# Generate parameter map.
df=pd.DataFrame(width)
# Replace the spice specific names by something human readable
# nfet
#spiceReplace={'var_vgs': 'V_GS', 'var_vdb': 'V_DS', 'i(V_ID)' : 'I_D', '@m.xm1.msky130_fd_pr__nfet_01v8[gm]': 'gm', '@m.xm1.msky130_fd_pr__nfet_01v8[gds]': 'gds'}
# nfet_lvt
#spiceReplace={'var_vgb': 'V_GB', 'var_vds': 'V_DS', 'i(V_ID)' : 'I_D', '@m.xm1.msky130_fd_pr__nfet_01v8_lvt[gm]': 'gm', '@m.xm1.msky130_fd_pr__nfet_01v8_lvt[gds]': 'gds'}
spiceReplace={'var_vgb': 'V_GB', 'var_vds': 'V_DS', 'i(V_ID)' : 'I_D', f'@m.xm1.msky130_fd_pr__{TRANSISTOR_TYPE}[gm]': 'gm', f'@m.xm1.msky130_fd_pr__{TRANSISTOR_TYPE}[gds]': 'gds'}
# Run spice
ngspice=NgSpice(file_in, workingDir, parallel=True)
try:
result=ngspice.run(df, delete=True, rename=spiceReplace)
except:
print(TRANSISTOR_TYPE)
raise
for r in result:
df=r['results'][0]
u_GS_unique=df['V_GB'].unique()
# First plot: For a given transistor length plot gm as a function of the Gate voltage.
fig, ax = plt.subplots()
for u_GS_filter in u_GS_unique:
myfilter = df['V_GB'].values == u_GS_filter
I_D=df['I_D'].values[myfilter]
gm=df['gm'].values[myfilter]
ax.plot(I_D, gm, label=f'U_GB={u_GS_filter}')
ax.set_xlabel('I_D') # Add an x-label to the axes.
ax.set_ylabel('gm') # Add a y-label to the axes.
ax.set_title("Lenght={:.2f}".format(r['param']['L'])) # Add a title to the axes.
ax.legend() # Add a legend.
#plt.show()
file=os.path.join(workingDir, "gm vs ID, Lenght={:.2f}.png".format(r['param']['L']))
plt.savefig(file)
plt.close(fig)
# Second plot: For a given transistor length plot gds as a function of the Gate voltage.
fig, ax = plt.subplots()
for u_GS_filter in u_GS_unique:
myfilter = df['V_GB'].values == u_GS_filter
I_D=df['I_D'].values[myfilter]
gds=df['gds'].values[myfilter]
rds=1/gds
plt.semilogy(I_D, rds, label=f'U_GB={u_GS_filter}')
ax.set_xlabel('I_D') # Add an x-label to the axes.
ax.set_ylabel('1/gds') # Add a y-label to the axes.
ax.set_title("Lenght={:.2f}".format(r['param']['L'])) # Add a title to the axes.
ax.legend() # Add a legend.
file=os.path.join(workingDir, "gds vs ID, Lenght={:.2f}.png".format(r['param']['L']))
plt.savefig(file)
plt.close(fig)
# Third plot: For a given transistor length plot the intrinsic amplification as a function of the Gate voltage.
fig, ax = plt.subplots()
for u_GS_filter in u_GS_unique:
myfilter = df['V_GB'].values == u_GS_filter
I_D=df['I_D'].values[myfilter]
gds=df['gds'].values[myfilter]
gm=df['gm'].values[myfilter]
gain=gm/gds
plt.plot(I_D, gain, label=f'U_GB={u_GS_filter}')
ax.set_xlabel('I_D') # Add an x-label to the axes.
ax.set_ylabel('gm/gds') # Add a y-label to the axes.
ax.set_title("Lenght={:.2f}".format(r['param']['L'])) # Add a title to the axes.
ax.legend() # Add a legend.
file=os.path.join(workingDir, "gain vs ID, Lenght={:.2f}.png".format(r['param']['L']))
plt.savefig(file)
plt.close(fig)
# Fourth plot: For a given transistor length plot gm as a function of the Drain Source voltage. The gate voltage.
fig, ax = plt.subplots()
for u_GS_filter in u_GS_unique:
myfilter = df['V_GB'].values == u_GS_filter
V_DS=df['V_DS'].values[myfilter]
gds=df['gds'].values[myfilter]
gm=df['gm'].values[myfilter]
gain=gm/gds
ax.plot(V_DS, gm, label=f'U_GB={u_GS_filter}')
ax.set_xlabel('V_DS') # Add an x-label to the axes.
ax.set_ylabel('gm') # Add a y-label to the axes.
ax.set_title("Lenght={:.2f}".format(r['param']['L'])) # Add a title to the axes.
ax.legend() # Add a legend.
file=os.path.join(workingDir, "gm vs UDS, Lenght={:.2f}.png".format(r['param']['L']))
plt.savefig(file)
plt.close(fig)
# Fifth plot: For a given transistor length plot gds as a function of the Drain Source voltage. The gate voltage.
fig, ax = plt.subplots()
for u_GS_filter in u_GS_unique:
myfilter = df['V_GB'].values == u_GS_filter
V_DS=df['V_DS'].values[myfilter]
gds=df['gds'].values[myfilter]
gm=df['gm'].values[myfilter]
gain=gm/gds
plt.semilogy(V_DS, gds, label=f'U_GB={u_GS_filter}')
ax.set_xlabel('V_DS') # Add an x-label to the axes.
ax.set_ylabel('gds') # Add a y-label to the axes.
ax.set_title("Lenght={:.2f}".format(r['param']['L'])) # Add a title to the axes.
ax.legend() # Add a legend.
file=os.path.join(workingDir, "gds vs UDS, Lenght={:.2f}.png".format(r['param']['L']))
plt.savefig(file)
plt.close(fig)
# Sixth plot: For a given transistor length plot the intrinsic gain as a function of the Drain Source voltage. The gate voltage.
fig, ax = plt.subplots()
for u_GS_filter in u_GS_unique:
myfilter = df['V_GB'].values == u_GS_filter
V_DS=df['V_DS'].values[myfilter]
gds=df['gds'].values[myfilter]
gm=df['gm'].values[myfilter]
gain=gm/gds
plt.semilogy(V_DS, gain, label=f'U_GB={u_GS_filter}')
ax.set_xlabel('V_DS') # Add an x-label to the axes.
ax.set_ylabel('gm/gds') # Add a y-label to the axes.
ax.set_title("Lenght={:.2f}".format(r['param']['L'])) # Add a title to the axes.
ax.legend() # Add a legend.
file=os.path.join(workingDir, "gain, Lenght={:.2f}.png".format(r['param']['L']))
plt.savefig(file)
plt.close(fig)