Skip to content

Commit

Permalink
Add files via upload
Browse files Browse the repository at this point in the history
  • Loading branch information
Fican1 authored Sep 12, 2024
1 parent addde5b commit 17f1c40
Show file tree
Hide file tree
Showing 11 changed files with 1,526 additions and 0 deletions.
Binary file not shown.
Binary file not shown.
241 changes: 241 additions & 0 deletions AnalogGym/Charge Pump/chargepump.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,241 @@
import os
import shutil
import subprocess
# import pickle
# import time
import math
import numpy as np
import re

class ChargePump:
def __init__(self, index=0):
self.name = "ChargePump"
self.suffix = ""
self.index = index
self.dir = os.path.dirname(__file__)
assert os.path.exists(os.path.join(self.dir, "circuit"))
# self.database = "ChargePump.pkl"
self.mode = "spice" # or "ocean"
self.del_folders = True

# Design Variables
## DX = [('name',L,U,step,init,[discrete list]),....] if there is no discrete, do not write
self.DX = [
('q_llower', 3e-6, 9e-6, 1.0e-8, 6.9e-6, 'NO'),
('q_wlower', 1e-6, 4e-6, 1.0e-8, 3e-6, 'NO'),
('q_lupper', 1e-6, 2e-6, 1.0e-8, 1.5e-6, 'NO'),
('q_wupper', 5e-6, 20e-6, 1.0e-8, 10e-6, 'NO'),
('q_lc', 1e-6, 4e-6, 1.0e-8, 3e-6, 'NO'),
('q_wc', 5e-6, 20e-6, 1.0e-8, 10e-6, 'NO'),
('q_lref', 1e-6, 4e-6, 1.0e-8, 3e-6, 'NO'),
('q_wref', 5e-6, 20e-6, 1.0e-8, 6e-6, 'NO'),
('q_lq', 1e-6, 4e-6, 1.0e-8, 3e-6, 'NO'),
('q_wq', 5e-6, 20e-6, 1.0e-8, 6e-6, 'NO'),
('lpdbin', 0.55e-6, 2e-6, 1.0e-8, 1e-6, 'NO'),
('wpdbin', 4e-6, 15e-6, 1.0e-8, 10e-6, 'NO'),
('lpdin', 0.55e-6, 2e-6, 1.0e-8, 1e-6, 'NO'),
('wpdin', 2e-6, 6e-6, 1.0e-8, 3e-6, 'NO'),
('luumid', 0.6e-6, 1.2e-6, 1.0e-8, 1e-6, 'NO'),
('wuumid', 5e-6, 20e-6, 1.0e-8, 10e-6, 'NO'),
('lumid', 0.55e-6, 2e-6, 1.0e-8, 1e-6, 'NO'),
('wumid', 8e-6, 25e-6, 1.0e-8, 10e-6, 'NO'),
('lp4', 0.5e-6, 2e-6, 1.0e-8, 1e-6, 'NO'),
('wp4', 1e-6, 4e-6, 1.0e-8, 2e-6, 'NO'),
('ln4', 0.55e-6, 2e-6, 1.0e-8, 1e-6, 'NO'),
('wn4', 1e-6, 4e-6, 1.0e-8, 2e-6, 'NO'),
('lnsupp', 0.5e-6, 2e-6, 1.0e-8, 1e-6, 'NO'),
('wnsupp', 1e-6, 4e-6, 1.0e-8, 2e-6, 'NO'),
('lnsupp2', 0.8e-6, 2.4e-6, 1.0e-8, 1e-6, 'NO'),
('wnsupp2', 1e-6, 4e-6, 1.0e-8, 2e-6, 'NO'),
('li10', 2e-6, 10e-6, 1.0e-8, 3e-6, 'NO'),
('wi10', 0.8e-6, 4e-6, 1.0e-8, 2e-6, 'NO'),
('lb1', 2e-6, 10e-6, 1.0e-8, 3e-6, 'NO'),
('wb1', 5e-6, 25e-6, 1.0e-8, 10e-6, 'NO'),
('lb2', 2e-6, 8e-6, 1.0e-8, 3e-6, 'NO'),
('wb2', 1e-6, 3e-6, 1.0e-8, 2e-6, 'NO'),
('lb3', 0.5e-6, 2e-6, 1.0e-8, 1e-6, 'NO'),
('wb3', 1e-6, 6e-6, 1.0e-8, 2e-6, 'NO'),
('lb4', 0.55e-6, 3e-6, 1.0e-8, 1e-6, 'NO'),
('wb4', 4e-6, 16e-6, 1.0e-8, 8e-6, 'NO'),
]

self.in_dim = len(self.DX)
self.real_init = np.array([dx[4] for dx in self.DX])
self.real_lb = np.array([dx[1] for dx in self.DX])
self.real_ub = np.array([dx[2] for dx in self.DX])
self.init = (self.real_init-self.real_lb)/(self.real_ub - self.real_lb)

self.run_file = "sim.sh"
self.result_file = "de_result.po"

self.perform_setting = {
"diff1": ("<", 20, None, None, "diff1", 200, 10),
"diff2": ("<", 20, None, None, "diff2", 200, 10),
"diff3": ("<", 5, None, None, "diff3", 50, 10),
"diff4": ("<", 5, None, None, "diff4", 50, 10),
"deviation": ("<", 5, None, None, "deviation", 50, 10),
"obj": (None, None, None, None, "obj", 1000, None)
}

self.fom_setting = (100, None)

def cal_fom(self, meas_dict):
fom = meas_dict["obj"]
return fom

def write_param(self, dx_real_dict):
if self.mode == "spice":
with open("param", "w") as handler:
for dx_name, dx_real in dx_real_dict.items():
handler.write(".param {}={}\n".format(dx_name, dx_real))
elif self.mode == "ocean":
handler.write('ocnxlSweepVar(\"' + str(dx_name) + '\" ' + '\"' + str(dx_real) + '\")\n')
else:
raise Exception("unknown self.mode")

def extract_perf(self, file_name, perf):
pattern_str = perf+'\s*=\s*([\d.eE+\-]+)'
pattern = re.compile(pattern_str)
with open(file_name, 'r') as f:
lines = f.readlines()
for line in lines:
result = pattern.search(line)
if result:
val = result.group(1)
return float(val)
return False

##################################################################

def set_name_suffix(self, suffix):
self.suffix = suffix
return self

def __call__(self, x, realx=False, index=None):
# while(os.path.exists("index_lock")):
# print("index is locked, wait for 1s")
# time.sleep(1)
# open("index_lock", "a").close()
# if os.path.exists("index.pkl"):
# with open("index.pkl", "rb") as fr:
# old_index = pickle.load(fr)
# tmp_index = old_index + 1
# else:
# tmp_index = 0
# with open("index.pkl", "wb") as fw:
# pickle.dump(tmp_index, fw)
# os.remove("index_lock")
if index is None: # sequentially
tmp_index = self.index
self.index += 1
else: # parallel with index updated in global
tmp_index = index
tmp_dir = "{}_{}_{}".format(self.name, self.suffix, tmp_index)
if os.path.exists(tmp_dir):
shutil.rmtree(tmp_dir)
cwd = os.getcwd()
shutil.copytree(
os.path.join(self.dir, "circuit"),
os.path.join(cwd, tmp_dir)
)
print("{} is created, waiting for simulation".format(tmp_dir))
os.chdir(tmp_dir)
if not realx:
x_01 = x
dx_real_dict = self.dx_map(x_01)
else:
x_real = x
x_name = [dx[0] for dx in self.DX]
dx_real_dict = dict(zip(x_name,x_real))
self.write_param(dx_real_dict)
subprocess.Popen([self.run_file]).wait()
print("{} simulation done".format(tmp_dir))
meas_dict = self.read_meas(self.result_file)
fom = self.cal_fom(meas_dict)
cost = self.cal_cost(meas_dict, fom)
print("{} get cost {}".format(tmp_dir, cost))
os.chdir(cwd)
# self.update_database(tmp_index, dx_real_dict, meas_dict, fom, cost)
if self.del_folders:
shutil.rmtree(tmp_dir)
return cost

def dx_map(self, x_01):
dx_real_dict = {}
for dx_tup, dx_01 in zip(self.DX, x_01):
dx_name = dx_tup[0]
dx_lb = dx_tup[1]
dx_ub = dx_tup[2]
dx_step = dx_tup[3]
dx_real_range = dx_01*(dx_ub-dx_lb)
plus = 1 if (dx_real_range%dx_step)/dx_step >= 0.5 else 0
round_range = dx_real_range//dx_step*dx_step + plus*dx_step
dx_real = round_range + dx_lb
if dx_real > dx_ub:
dx_real = dx_ub
if dx_real < dx_lb:
dx_real = dx_lb
dx_real_dict[dx_name] = dx_real
return dx_real_dict

def read_meas(self, file_name):
meas_dict = {}
for perform_name, perform_tup in self.perform_setting.items():
perform_value = self.extract_perf(file_name, perform_tup[4])
if not perform_value:
perform_value = perform_tup[5]
meas_dict[perform_name] = perform_value
return meas_dict

def cal_cost(self, meas_dict, fom):
cons_list = []
for perform_name, perform_value in meas_dict.items():
tup = self.perform_setting[perform_name]
spec_weight= tup[-1] if tup[-1] else 1
if "<" in tup:
if tup[1] != 0:
cons_list.append(
(perform_value - tup[1])/abs(tup[1])*spec_weight
)
else:
cons_list.append(
(2/(1+math.exp(-1*perform_value))-1)*spec_weight
)
if ">" in tup:
if tup[3] != 0:
cons_list.append(
-(perform_value - tup[3])/abs(tup[3])*spec_weight
)
else:
cons_list.append(
-(2/(1+math.exp(-1*perform_value))+1)*spec_weight
)
if ("<" not in tup) and (">" not in tup):
continue
cons_cost = sum([x if x>0 else 0 for x in cons_list])
fom_weight = self.fom_setting[-1] if self.fom_setting[-1] else 1
fom_cost = (fom - self.fom_setting[0])/abs(self.fom_setting[0])*fom_weight
cost = cons_cost + fom_cost
return cost

# def update_database(self, index, dx_real_dict, meas_dict, fom, cost):
# # Prepare datas
# x_real = [dx_real for dx_real in dx_real_dict.values()]
# while(os.path.exists("database_lock")):
# print("database is locked, wait for 1s")
# time.sleep(1)
# open("database_lock", "a").close()
# if os.path.exists(self.database):
# with open(self.database, "rb") as fr:
# datas = pickle.load(fr)
# datas.append(dict(index=index, x_real=x_real, meas=meas_dict, fom=fom, cost=cost, time=time.time()))
# else:
# datas = [dict(index=index, x_real=x_real, meas=meas_dict, fom=fom, cost=cost, time=time.time())]
# with open(self.database, "wb") as fw:
# pickle.dump(datas, fw)
# os.remove("database_lock")

if __name__ == '__main__':
accia = ACCIA()
accia(accia.real_init, realx=True)
accia([0.5]*accia.in_dim)
5 changes: 5 additions & 0 deletions AnalogGym/Charge Pump/circuit/clear.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
rm -f *.info *.mt* *.ma* *.ms* *.lis
rm -f chgp.*
rm -f run_sim.info
rm -f result.po
rm -f de_result.po
92 changes: 92 additions & 0 deletions AnalogGym/Charge Pump/circuit/measure.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,92 @@
import numpy as np
import re
import sys


def get_simple_mt(mtName):
'''
read simulation result from one .mt* file
'''
pattern = re.compile(r'[\s\t]*([\de.-]+)[\s\t]+([\de.-]+)[\s\t]+([\de.-]+)[\s\t]+([\de.-]+).+')

with open(mtName) as f:
lines = f.readlines()
result0 = pattern.match(lines[4])
result1 = pattern.match(lines[5])

up_imin = float(result0.group(1))*1e6
up_iavg = float(result0.group(2))*1e6
up_imax = float(result0.group(3))*1e6
lo_imin = float(result0.group(4))*1e6
lo_iavg = float(result1.group(1))*1e6
lo_imax = float(result1.group(2))*1e6

const = 40
diff1 = up_imax - up_iavg
diff2 = up_iavg - up_imin
diff3 = lo_imax - lo_iavg
diff4 = lo_iavg - lo_imin
diff = diff1+diff2+diff3+diff4
deviation = abs(up_iavg-const) + abs(lo_iavg-const)
fom = 0.3*diff+0.5*deviation
return fom,diff1,diff2,diff3,diff4,deviation


def get_result_mt(mtNameBas, num):
results = np.zeros((num,5))
for i in range(num):
mtName = mtNameBas + str(i)
fom,diff1,diff2,diff3,diff4,deviation = get_simple_mt(mtName)

results[i,0] = diff1
results[i,1] = diff2
results[i,2] = diff3
results[i,3] = diff4
results[i,4] = deviation

diff1 = max(results[:,0])
diff2 = max(results[:,1])
diff3 = max(results[:,2])
diff4 = max(results[:,3])
diff = diff1+diff2+diff3+diff4
deviation = max(results[:,4])
fom = 0.3*diff+0.5*deviation
return fom,diff1,diff2,diff3,diff4,deviation


def write_de_result(fom, diff1, diff2, diff3, diff4, deviation):
with open('de_result.po','w') as f:
f.write('obj= '+str(fom)+'\n')
f.write('diff1= '+str(diff1)+'\n')
f.write('diff2= '+str(diff2)+'\n')
f.write('diff3= '+str(diff3)+'\n')
f.write('diff4= '+str(diff4)+'\n')
f.write('dev= '+str(deviation)+'\n')

def write_resultpo(fom, diff1, diff2, diff3, diff4, deviation):
fom_cons = fom
diff1_cons = diff1 - 20
diff2_cons = diff2 - 20
diff3_cons = diff3 - 5
diff4_cons = diff4 - 5
dev_cons = deviation - 5
content = str(fom_cons) +' '+ str(diff1_cons) +' '+ str(diff2_cons) +' '+ str(diff3_cons) +' '+ str(diff4_cons) +' '+ str(dev_cons)
with open('result.po','w') as f:
f.write(content)


def get_result(cornerNum, resultForm='de'):
if cornerNum==1:
fom,diff1,diff2,diff3,diff4,deviation = get_simple_mt('chgp.mt0')
else:
fom,diff1,diff2,diff3,diff4,deviation = get_result_mt('chgp.mt', cornerNum)
if resultForm=='de':
write_de_result(fom, diff1, diff2, diff3, diff4, deviation)
elif resultForm=='weibo':
write_resultpo(fom, diff1, diff2, diff3, diff4, deviation)


argv = sys.argv[1:]
cornerNum = argv[0]
resultForm = argv[1]
get_result(int(cornerNum), resultForm)
Loading

0 comments on commit 17f1c40

Please sign in to comment.