blob: 6d8c5f2cc3822f919cbe5cee2eb6bd45d12a13eb [file] [log] [blame]
"""
Usage:
models_regression.py [--num_cores=<num>]
-h, --help Show help text.
-v, --version Show version.
--num_cores=<num> Number of cores to be used by simulator
"""
from cmath import inf
from re import T
from docopt import docopt
import pandas as pd
import numpy as np
import os
from jinja2 import Template
import concurrent.futures
import shutil
import warnings
warnings.simplefilter(action='ignore', category=FutureWarning)
def call_simulator(file_name):
"""Call simulation commands to perform simulation.
Args:
file_name (str): Netlist file name.
"""
os.system(f"ngspice -b -a {file_name} -o {file_name}.log > {file_name}.log")
def ext_measured(device,vb,step,Id_sim,list_devices,vc):
# Get dimensions used for each device
dimensions = pd.read_csv(f"{device}/{device}.csv",usecols=["corners"])
loops = dimensions["corners"].count()
# Extracting measured values for each Device
for i in range (loops):
k = i
if i >= len(list_devices):
while k >= len(list_devices):
k = k - len(list_devices)
# Special case for 1st measured values
if i == 0 :
if device == "pnp":
temp_vb = vb
vb = "-vb "
# measured Id_sim 0
col_list = [f"{vb}",f"{vc}{step[0]}",f"{vc}{step[1]}",f"{vc}{step[2]}"]
df_measured = pd.read_csv(f"{device}/{device}.csv",usecols=col_list)
df_measured.columns = [f"{vb}",f"{vc}{step[0]}",f"{vc}{step[1]}",f"{vc}{step[2]}"]
df_measured.to_csv(f"{device}/measured_{Id_sim[0]}/{i}_measured_{list_devices[k]}.csv", index = False)
if device == "pnp":
vb = temp_vb
# measured Id_sim 1
col_list = [f"{vb}",f"{vc}{step[0]}.{2*i+1}",f"{vc}{step[1]}.{2*i+1}",f"{vc}{step[2]}.{2*i+1}"]
df_measured = pd.read_csv(f"{device}/{device}.csv",usecols=col_list)
df_measured.columns = [f"{vb}",f"{vc}{step[0]}",f"{vc}{step[1]}",f"{vc}{step[2]}"]
df_measured.to_csv(f"{device}/measured_{Id_sim[1]}/{i}_measured_{list_devices[k]}.csv", index = False)
else:
# measured Id_sim 0
col_list = [f"{vb}",f"{vc}{step[0]}.{2*i}",f"{vc}{step[1]}.{2*i}",f"{vc}{step[2]}.{2*i}"]
df_measured = pd.read_csv(f"{device}/{device}.csv",usecols=col_list)
df_measured.columns = [f"{vb}",f"{vc}{step[0]}",f"{vc}{step[1]}",f"{vc}{step[2]}"]
df_measured.to_csv(f"{device}/measured_{Id_sim[0]}/{i}_measured_{list_devices[k]}.csv", index = False)
# measured Id_sim 1
col_list = [f"{vb}",f"{vc}{step[0]}.{2*i+1}",f"{vc}{step[1]}.{2*i+1}",f"{vc}{step[2]}.{2*i+1}"]
df_measured = pd.read_csv(f"{device}/{device}.csv",usecols=col_list)
df_measured.columns = [f"{vb}",f"{vc}{step[0]}",f"{vc}{step[1]}",f"{vc}{step[2]}"]
df_measured.to_csv(f"{device}/measured_{Id_sim[1]}/{i}_measured_{list_devices[k]}.csv", index = False)
def ext_simulated(device,vc,step,sweep,Id_sim,list_devices,ib):
# Get dimensions used for each device
dimensions = pd.read_csv(f"{device}/{device}.csv",usecols=["corners"])
loops = dimensions["corners"].count()
temp_range = int(loops/4)
netlist_tmp = f"./device_netlists/{device}.spice"
for i in range (loops):
if i in range (0,temp_range): temp = 25
elif i in range (temp_range,2*temp_range): temp = -40
elif i in range (2*temp_range,3*temp_range):temp = 125
else: temp = 175
k = i
if i >= len(list_devices):
while k >= len(list_devices):
k = k - len(list_devices)
with open(netlist_tmp) as f:
tmpl = Template(f.read())
os.makedirs(f"{device}/{device}_netlists_sim",exist_ok=True)
with open(f"{device}/{device}_netlists_sim/{i}_{device}_netlist_{list_devices[k]}.spice", "w") as netlist:
netlist.write(tmpl.render(device = list_devices[k], i = i , temp = temp ))
netlist_path = f"{device}/{device}_netlists_sim/{i}_{device}_netlist_{list_devices[k]}.spice"
# Running ngspice for each netlist
with concurrent.futures.ProcessPoolExecutor(max_workers=workers_count) as executor:
executor.submit(call_simulator, netlist_path)
# Writing simulated data 0
df_simulated = pd.read_csv(f"{device}/simulated_{Id_sim[0]}/{i}_simulated_{list_devices[k]}.csv",header=None, delimiter=r"\s+")
# empty array to append in it shaped (sweep, number of trials + 1)
new_array = np.empty((sweep, 1+int(df_simulated.shape[0]/sweep)))
new_array[:, 0] = df_simulated.iloc[:sweep, 0]
times = int(df_simulated.shape[0]/sweep)
for j in range(times):
new_array[:, (j+1)] = df_simulated.iloc[j*sweep:(j+1)*sweep, 1]
# Writing final simulated data 0
df_simulated = pd.DataFrame(new_array)
df_simulated.to_csv(f"{device}/simulated_{Id_sim[0]}/{i}_simulated_{list_devices[k]}.csv",index= False)
df_simulated.columns = [f"{vc}",f"{ib}{step[0]}",f"{ib}{step[1]}",f"{ib}{step[2]}"]
df_simulated.to_csv(f"{device}/simulated_{Id_sim[0]}/{i}_simulated_{list_devices[k]}.csv",index= False)
# Writing simulated data 1
df_simulated = pd.read_csv(f"{device}/simulated_{Id_sim[1]}/{i}_simulated_{list_devices[k]}.csv",header=None, delimiter=r"\s+")
# empty array to append in it shaped (sweep, number of trials + 1)
new_array = np.empty((sweep, 1+int(df_simulated.shape[0]/sweep)))
new_array[:, 0] = df_simulated.iloc[:sweep, 0]
times = int(df_simulated.shape[0]/sweep)
for j in range(times):
new_array[:, (j+1)] = df_simulated.iloc[j*sweep:(j+1)*sweep, 1]
# Writing final simulated data 1
df_simulated = pd.DataFrame(new_array)
df_simulated.to_csv(f"{device}/simulated_{Id_sim[1]}/{i}_simulated_{list_devices[k]}.csv",index= False)
df_simulated.columns = [f"{vc}",f"{ib}{step[0]}",f"{ib}{step[1]}",f"{ib}{step[2]}"]
df_simulated.to_csv(f"{device}/simulated_{Id_sim[1]}/{i}_simulated_{list_devices[k]}.csv",index= False)
def error_cal(device,vb,step,Id_sim,list_devices,vc):
df_final = pd.DataFrame()
# Get dimensions used for each device
dimensions = pd.read_csv(f"{device}/{device}.csv",usecols=["corners"])
loops = dimensions["corners"].count()
temp_range = int(loops/4)
for i in range (loops):
if i in range (0,temp_range): temp = 25
elif i in range (temp_range,2*temp_range): temp = -40
elif i in range (2*temp_range,3*temp_range):temp = 125
else: temp = 175
k = i
if i >= len(list_devices):
while k >= len(list_devices):
k = k - len(list_devices)
measured = pd.read_csv(f"{device}/measured_{Id_sim}/{i}_measured_{list_devices[k]}.csv")
simulated = pd.read_csv(f"{device}/simulated_{Id_sim}/{i}_simulated_{list_devices[k]}.csv")
error_1 = round (100 * abs((abs(measured.iloc[0:, 1]) - abs(simulated.iloc[0:, 1]))/abs(measured.iloc[:, 1])),6)
error_2 = round (100 * abs((abs(measured.iloc[0:, 2]) - abs(simulated.iloc[0:, 2]))/abs(measured.iloc[:, 2])),6)
error_3 = round (100 * abs((abs(measured.iloc[0:, 3]) - abs(simulated.iloc[0:, 3]))/abs(measured.iloc[:, 3])),6)
df_error = pd.DataFrame(data=[measured.iloc[:, 0],error_1,error_2,error_3]).transpose()
df_error.replace([np.inf, -np.inf], df_error.max().nlargest(2).iloc[1], inplace=True)
df_error.to_csv(f"{device}/error_{Id_sim}/{i}_{device}_error_{list_devices[k]}.csv",index= False)
# Mean error
mean_error = (df_error[f"{vc}{step[0]}"].mean() + df_error[f"{vc}{step[1]}"].mean() + df_error[f"{vc}{step[2]}"].mean())/6
# Max error
max_error = df_error[[f"{vc}{step[0]}",f"{vc}{step[1]}",f"{vc}{step[2]}"]].max().max()
# Max error location
max_index = max((df_error == max_error).idxmax())
max_location_vc = (df_error == max_error).idxmax(axis=1)[max_index]
if Id_sim == "Ic":
if i == 0 :
if device == "pnp":
temp_vb = vb
vb = "-vb "
else:
if device == "pnp":
vb = temp_vb
max_location_vb = df_error[f"{vb}"][max_index]
df_final_ = {'Run no.': f'{i}', 'Temp': f'{temp}', 'Device name': f'{device}', 'device': f'{list_devices[k]}','Simulated_Val':f'{Id_sim}','Mean error%':f'{"{:.2f}".format(mean_error)}', 'Max error%':f'{"{:.2f}".format(max_error)} @ {max_location_vc} & Vc (V) = {max_location_vb}'}
df_final = df_final.append(df_final_, ignore_index = True)
# Max mean error
print (df_final)
df_final.to_csv (f"{device}/Final_report_{Id_sim}.csv", index = False)
out_report = pd.read_csv (f"{device}/Final_report_{Id_sim}.csv")
print ("\n",f"Max. mean error = {out_report['Mean error%'].max()}%")
print ("=====================================================================================================================================================")
def main():
devices = ["npn","pnp"]
list_devices = [["vnpn_10x10" , "vnpn_5x5" , "vnpn_0p54x16" , "vnpn_0p54x8" , "vnpn_0p54x4", "vnpn_0p54x2"],
["vpnp_0p42x10" , "vpnp_0p42x5", "vpnp_10x10" , "vpnp_5x5"]]
vb = ["vbp ","-vb (V)"]
vc = ["vcp =","vc =-"]
Id_sim = ["Ic","Ib"]
sweep = 101
step = [1, 2, 3]
for i, device in enumerate(devices):
# Folder structure of measured values
dirpath = f"{device}"
if os.path.exists(dirpath) and os.path.isdir(dirpath):
shutil.rmtree(dirpath)
os.makedirs(f"{device}/measured_{Id_sim[0]}",exist_ok=False)
os.makedirs(f"{device}/measured_{Id_sim[1]}",exist_ok=False)
# From xlsx to csv
read_file = pd.read_excel (f"../../180MCU_SPICE_DATA/BJT/bjt_{device}_beta_f.nl_out.xlsx")
read_file.to_csv (f"{device}/{device}.csv", index = False, header=True)
# Folder structure of simulated values
os.makedirs(f"{device}/simulated_{Id_sim[0]}",exist_ok=False)
os.makedirs(f"{device}/error_{Id_sim[0]}",exist_ok=False)
os.makedirs(f"{device}/simulated_{Id_sim[1]}",exist_ok=False)
os.makedirs(f"{device}/error_{Id_sim[1]}",exist_ok=False)
# =========== Simulate ==============
ext_measured (device,vb[i],step,Id_sim,list_devices[i],vc[i])
ext_simulated(device,vb[i],step,sweep,Id_sim,list_devices[i],vc[i])
# ============ Results =============
error_cal (device,vb[i],step,Id_sim[0],list_devices[i],vc[i])
error_cal (device,vb[i],step,Id_sim[1],list_devices[i],vc[i])
# ================================================================
# -------------------------- MAIN --------------------------------
# ================================================================
if __name__ == "__main__":
# Args
arguments = docopt(__doc__, version='comparator: 0.1')
workers_count = os.cpu_count()*2 if arguments["--num_cores"] == None else int(arguments["--num_cores"])
# Calling main function
main()