Skip to content

Instantly share code, notes, and snippets.

@themperek
Last active March 7, 2018 22:33
Show Gist options
  • Save themperek/660ecfc40e7b7b3d32e8283a8aa2558a to your computer and use it in GitHub Desktop.
Save themperek/660ecfc40e7b7b3d32e8283a8aa2558a to your computer and use it in GitHub Desktop.
Data flow simulation model for Monopix chip
import numpy as np
import random
import numba
@numba.njit
def monopix_sim(SIM_TIME = 1000000, LATENCY = 400, TRIGGER_RATE = 4.0/40, PIXEL_AREA = 36.0*40.0, READ_COL = 4, LOGIC_COLUMNS = 512/4, PIXEL_NO = 4*512, HIT_RATE_CM = 100*(10**6), MEAN_TOT = 15, READ_TRIGER_MEM = 1, TRIG_MEM_SIZE = 96, READ_OUTPUT_FIFO = 1, OUT_FIFO_SIZE = 128):
# Average hit rate L4: 0.021/mm2/BC
PIXEL_MAX_LATENCY = 63 #6-bit ToT
#LATENCY = 400 10us
#TRIGGER_RATE = 4.0/40 4MHz
#PIXEL_NO = 2*512 #512*512/LOGIC_COLUMNS #number of pixle per readout unit
# READ_TRIGER_MEM = 1 #1- 40 / 4 - 160MHz
# READ_OUTPUT_FIFO = 1 #40MHz @ 32bit
WAIT_FOR_TRIG_MEM = False #wait with in the array or read and losse
analog_pileup = 0.0
digital_pileup = 0.0
late_copy = 0.0
total_hits = 0.0
trig_mem_pileup = 0.0
trig_count = 0
pixel_hit_rate_bx = ((float(PIXEL_AREA)/(10000*10000)) * HIT_RATE_CM )/ (40*(10**6))
pix_mem_tot = np.zeros((LOGIC_COLUMNS, PIXEL_NO) ,dtype=np.int32)
pix_mem_bx = np.zeros((LOGIC_COLUMNS, PIXEL_NO) ,dtype=np.int32)
trig_mem = np.zeros((LOGIC_COLUMNS, TRIG_MEM_SIZE) ,dtype=np.int32)
out_mem = np.zeros((OUT_FIFO_SIZE) ,dtype=np.int32)
out_mem_hist = np.zeros((OUT_FIFO_SIZE+1) ,dtype=np.uint)
trig_mem_hist = np.zeros((TRIG_MEM_SIZE+1) ,dtype=np.uint)
trig_mem_fill_mon = np.zeros((LOGIC_COLUMNS, SIM_TIME) ,dtype=np.uint)
out_mem_fill_mon = np.zeros((SIM_TIME) ,dtype=np.uint)
to_read_mon = np.zeros((SIM_TIME) ,dtype=np.uint)
col_ro_delay_hist = np.zeros((PIXEL_MAX_LATENCY+1), dtype=np.uint)
read_cnt = 0
read_cnt_out = 0
for bx in range(SIM_TIME):
#histogram
if len(np.nonzero(out_mem)[0]) != 0: #ignore the counts with fully empty output fifo
out_mem_hist[len(np.nonzero(out_mem)[0])] += 1
#OUT_MEM_READ
if read_cnt_out >= READ_OUTPUT_FIFO-1:
out_mem_occ = np.where(out_mem==True)[0] #occupied output fifo
out_mem_fill_mon[bx] += len(out_mem_occ)
if len(out_mem_occ):
out_mem[out_mem_occ[:1]] = 0 #clear fist occupied output fifo
read_cnt_out = 0
else:
read_cnt_out += 1
#OUT_MEM_FILL
max_trig_latency = np.max(trig_mem)
to_read = np.where((trig_mem > LATENCY) & (trig_mem == max_trig_latency))
to_read_len = len(to_read[0])
to_read_mon[bx] = to_read_len
for read_trig_mem in range(to_read_len):
#print (bx, max_trig_latency, np.where((trig_mem > LATENCY) & (trig_mem == max_trig_latency)), read_trig_mem)
if read_trig_mem >= READ_TRIGER_MEM:
break
empty_out_mem = np.where(out_mem==0)[0]
#print (bx, empty_out_mem)
if len(empty_out_mem) > 0:
trig_mem[to_read[0][read_trig_mem],to_read[1][read_trig_mem]] = 0 #remove triggered data
out_mem[empty_out_mem[:1]] = 1
#print out_mem
no_trigger = random.random() > TRIGGER_RATE
if no_trigger == False: trig_count += 1
for col in range(LOGIC_COLUMNS):
#hit counter/tot
pix_mem_tot[col][pix_mem_tot[col]>0] -= 1
#bx counter
pix_mem_bx[col][pix_mem_bx[col] > 0] += 1
#remove hits after latency if no trigger
if no_trigger:
trig_mem[col][trig_mem[col] == LATENCY] = 0
trig_mem[col][trig_mem[col] > 0] += 1
late_copy += len(np.where(pix_mem_bx[col] == PIXEL_MAX_LATENCY)[0]) #Late copy
#histogram
trig_mem_occ = len(np.nonzero(trig_mem[col])[0])
trig_mem_hist[trig_mem_occ] += 1
trig_mem_fill_mon[col][bx] += trig_mem_occ
#process eoc
if read_cnt >= READ_COL-1:
max_bx_latency = np.max(pix_mem_bx[col])
for read_pix in np.where((pix_mem_bx[col] > 0) & (pix_mem_tot[col]==0) & (pix_mem_bx[col]==max_bx_latency) )[0]: #something to read
#TODO:Read regions?
empty_mems = np.where(trig_mem[col] == 0)[0]
if len(empty_mems):
mem_loc = empty_mems[0]
val = pix_mem_bx[col][read_pix] % (PIXEL_MAX_LATENCY +1)
trig_mem[col][mem_loc] = val
col_ro_delay_hist[val] += 1
if WAIT_FOR_TRIG_MEM == True:
pix_mem_bx[col][read_pix] = 0 #clear this pixel
read_cnt = 0
else:
trig_mem_pileup += 1
if WAIT_FOR_TRIG_MEM == False:
pix_mem_bx[col][read_pix] = 0 #clear this pixel
read_cnt = 0
break
else:
read_cnt += 1
#process hits
for pix in np.where(np.random.rand(pix_mem_bx[col].size) < pixel_hit_rate_bx)[0]:
total_hits += 1
if pix_mem_tot[col][pix] > 0:
analog_pileup += 1 #Analog pielup
#pix_mem_tot[col][pix] += MEAN_TOT +1 #paralyzable deadtime
else:
pix_mem_tot[col][pix] = pix_mem_tot[col][pix] + MEAN_TOT +1
if pix_mem_bx[col][pix] > 0:
digital_pileup += 1 #Digital pielup
elif pix_mem_bx[col][pix] == 0: #start bx_cnt
pix_mem_bx[col][pix] = 1
return analog_pileup, digital_pileup, late_copy, trig_mem_pileup, total_hits, out_mem_hist, trig_mem_hist, trig_count, trig_mem_fill_mon, out_mem_fill_mon, to_read_mon, col_ro_delay_hist
if __name__ == "__main__":
#print (36.4*36.4*512*2)/(1000*1000)
hit_rate = 4.0
attr = {'SIM_TIME': 1000000,
'LATENCY': 400,
'TRIGGER_RATE': 4.0/40,
'PIXEL_AREA': 36.0*40.0,
'READ_COL': 4,
'LOGIC_COLUMNS': 1,
'PIXEL_NO': 2*512,
'HIT_RATE_CM': hit_rate*100*(10**6),
'MEAN_TOT': 15,
'READ_TRIGER_MEM': 1,
'TRIG_MEM_SIZE': 96,
'READ_OUTPUT_FIFO': 1,
'OUT_FIFO_SIZE': 2048
}
analog_pileup, digital_pileup, late_copy, trig_mem_pileup, total_hits, out_mem_hist, trig_mem_hist, trig_count, trig_mem_fill_mon, out_mem_fill_mon, to_read_mon, col_ro_delay_hist = monopix_sim(**attr)
print 'analog pileup @ %d*100MHz/cm2: '%hit_rate, (100*analog_pileup/total_hits)
print 'digital pileup @ %d*100MHz/cm2: '%hit_rate, (100*digital_pileup/total_hits)
print 'late copy @ %d*100MHz/cm2: '%hit_rate, (100*late_copy/total_hits)
print 'trig mem pileup @ %d*100MHz/cm2: '%hit_rate, (100*trig_mem_pileup/total_hits)
print 'total hits @ %d*100MHz/cm2: '%hit_rate, total_hits
print 'trig count @ %d*100MHz/cm2: '%hit_rate, trig_count
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment