From 44377b41da12b9bfb26359c8012e4233eeddd442 Mon Sep 17 00:00:00 2001 From: Gregor Vollmer Date: Mon, 20 Feb 2017 13:54:18 +0100 Subject: [PATCH 01/10] =?UTF-8?q?Current=20state=20of=20the=20analysis.=20?= =?UTF-8?q?A=20horrible,=20horrible=20state=E2=80=A6?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Moritz, y u no managed you're code?! This place is cluttered with temporary debugging and sh*t I have to clean out now. Tnx a lot! --- .gitignore | 15 +- KeithleyControl | 1 + MPACalibration.py | 530 +++++++ MPAPlot.py | 195 +++ MPAThreshold.py | 42 + __init__.py | 0 advancedTrimDacCalibration.py | 133 ++ bondTest.py | 61 + calDACTest.py | 52 + calibration.py | 124 +- classes/MAPSA_config.py | 4 +- classes/MAPSA_functions.py | 5 +- classes/MPA_config.py | 38 +- common_noise/common_noise.py | 19 + common_noise/old/common_noise_2d.py | 23 + common_noise/old/common_noise_counter_dump.py | 126 ++ common_noise/old/common_noise_histogram.py | 35 + .../old/common_noise_histogram_memory.py | 41 + common_noise/old/common_noise_memory_dump.py | 116 ++ daq.py | 4 +- daq/.daq_counter_2MPA_xray.py.swp | Bin 0 -> 12288 bytes daq/daq_buffer_duplication.py | 164 +++ daq/daq_continuous_2MPA.py | 268 ++++ daq/daq_counter_2MPA.py | 134 ++ daq/daq_counter_2MPA_xray.py | 97 ++ daq/daq_memory_2MPA.py | 104 ++ daq/daq_shuttertest_2MPA.py | 173 +++ daq/hits_MPA5 | 3 + daq/test_custom_register.py | 48 + data/Conf_default_MPA1_config1.xml | 2 +- data/Conf_default_MPA2_config1.xml | 2 +- fallingEdges_histogram.py | 32 + findMPA.py | 193 +++ findMPAnew.py | 127 ++ manualBondTest.py | 57 + old/bondTest.py | 95 ++ .../.Conf_calibrated_MPA2_config1.xml.swp | Bin 0 -> 16384 bytes .../Conf_calibrated_MPA1_config1.xml | 323 +++++ .../Conf_calibrated_MPA2_config1.xml | 323 +++++ .../Conf_calibrated_MPA3_config1.xml | 323 +++++ .../Conf_calibrated_MPA4_config1.xml | 323 +++++ .../Conf_calibrated_MPA5_config1.xml | 323 +++++ .../Conf_calibrated_MPA6_config1.xml | 323 +++++ old/calib_data/Conf_default_MPA1_config1.xml | 324 +++++ old/calib_data/Conf_default_MPA2_config1.xml | 324 +++++ old/calib_data/Conf_default_MPA3_config1.xml | 324 +++++ old/calib_data/Conf_default_MPA4_config1.xml | 324 +++++ old/calib_data/Conf_default_MPA5_config1.xml | 324 +++++ old/calib_data/Conf_default_MPA6_config1.xml | 324 +++++ old/calibration_2MPA_new.py | 523 +++++++ old/calibration_rewrite_moritz.py | 405 ++++++ old/calibration_rewrite_moritz_second_scan.py | 476 +++++++ old/mem_calibration.py | 184 +++ old/noise_calibration_mpa2_mpa5.py | 237 ++++ old/pix_mem_calibration.py | 451 ++++++ old/pixtest.py | 144 ++ old/thresholdscan.py | 70 + pixPlot.py | 57 + plot_generators/hits_over_vbias.py | 100 ++ plot_generators/hits_vs_thresholds.py | 97 ++ startDaq.sh | 7 + testBeam.py | 56 + testBeamAnalysis.py | 196 +++ testBeamCorrelate.py | 34 + test_address_table_v1.xml | 9 + threshscan.py | 4 - trimDACtest/plot_trim.py | 38 + trimDACtest/ratios | 98 ++ trimDACtest/trimDacFallingEdge.pickle | 1256 +++++++++++++++++ trimDACtest/trim_scan.py | 276 ++++ 70 files changed, 11567 insertions(+), 96 deletions(-) create mode 160000 KeithleyControl create mode 100644 MPACalibration.py create mode 100644 MPAPlot.py create mode 100644 MPAThreshold.py create mode 100644 __init__.py create mode 100644 advancedTrimDacCalibration.py create mode 100644 bondTest.py create mode 100644 calDACTest.py create mode 100644 common_noise/common_noise.py create mode 100644 common_noise/old/common_noise_2d.py create mode 100644 common_noise/old/common_noise_counter_dump.py create mode 100644 common_noise/old/common_noise_histogram.py create mode 100644 common_noise/old/common_noise_histogram_memory.py create mode 100644 common_noise/old/common_noise_memory_dump.py create mode 100644 daq/.daq_counter_2MPA_xray.py.swp create mode 100644 daq/daq_buffer_duplication.py create mode 100644 daq/daq_continuous_2MPA.py create mode 100644 daq/daq_counter_2MPA.py create mode 100644 daq/daq_counter_2MPA_xray.py create mode 100644 daq/daq_memory_2MPA.py create mode 100644 daq/daq_shuttertest_2MPA.py create mode 100644 daq/hits_MPA5 create mode 100644 daq/test_custom_register.py create mode 100644 fallingEdges_histogram.py create mode 100644 findMPA.py create mode 100644 findMPAnew.py create mode 100644 manualBondTest.py create mode 100644 old/bondTest.py create mode 100644 old/calib_data/.Conf_calibrated_MPA2_config1.xml.swp create mode 100644 old/calib_data/Conf_calibrated_MPA1_config1.xml create mode 100644 old/calib_data/Conf_calibrated_MPA2_config1.xml create mode 100644 old/calib_data/Conf_calibrated_MPA3_config1.xml create mode 100644 old/calib_data/Conf_calibrated_MPA4_config1.xml create mode 100644 old/calib_data/Conf_calibrated_MPA5_config1.xml create mode 100644 old/calib_data/Conf_calibrated_MPA6_config1.xml create mode 100644 old/calib_data/Conf_default_MPA1_config1.xml create mode 100644 old/calib_data/Conf_default_MPA2_config1.xml create mode 100644 old/calib_data/Conf_default_MPA3_config1.xml create mode 100644 old/calib_data/Conf_default_MPA4_config1.xml create mode 100644 old/calib_data/Conf_default_MPA5_config1.xml create mode 100644 old/calib_data/Conf_default_MPA6_config1.xml create mode 100644 old/calibration_2MPA_new.py create mode 100644 old/calibration_rewrite_moritz.py create mode 100644 old/calibration_rewrite_moritz_second_scan.py create mode 100644 old/mem_calibration.py create mode 100644 old/noise_calibration_mpa2_mpa5.py create mode 100644 old/pix_mem_calibration.py create mode 100644 old/pixtest.py create mode 100644 old/thresholdscan.py create mode 100644 pixPlot.py create mode 100644 plot_generators/hits_over_vbias.py create mode 100644 plot_generators/hits_vs_thresholds.py create mode 100755 startDaq.sh create mode 100644 testBeam.py create mode 100644 testBeamAnalysis.py create mode 100644 testBeamCorrelate.py create mode 100644 trimDACtest/plot_trim.py create mode 100644 trimDACtest/ratios create mode 100644 trimDACtest/trimDacFallingEdge.pickle create mode 100644 trimDACtest/trim_scan.py diff --git a/.gitignore b/.gitignore index 46214c7..3c181bd 100644 --- a/.gitignore +++ b/.gitignore @@ -1,6 +1,11 @@ -plots/ -data/*_calibrated* -daqlogs/ +plots/* +data/* *.pyc -*.~ -*# \ No newline at end of file +*~ +*.pdf +*#*# +daqlogs/* +decoded/* +*.root +logs/* +*.log diff --git a/KeithleyControl b/KeithleyControl new file mode 160000 index 0000000..663d063 --- /dev/null +++ b/KeithleyControl @@ -0,0 +1 @@ +Subproject commit 663d0634f2d001e3a69f1ad5cab59ce5a6ebd192 diff --git a/MPACalibration.py b/MPACalibration.py new file mode 100644 index 0000000..4833b27 --- /dev/null +++ b/MPACalibration.py @@ -0,0 +1,530 @@ +#!/usr/bin/python +from classes import * +import sys +import time + +class MPACalibration(object): + + # DAC steps in mV + thrVoltStep = 1.456 + trimVoltStep = 3.75 + + + def __init__(self, assembly): + + assembly = self.__wrap(assembly, 1) # Either pass single MPA as integer or array of ints for MAPSA + self._assembly = sorted(assembly) # Array with MPAs on board (e.g. [2,6] for two MPAs at positions 2 and 6). This is needed because how SPI chain is constructed depends on MPAs present. + self._nMPA = len(assembly) # Number of MPAs on the board. This is then also the length of the SPI chain + self._iMPA = range(self._nMPA) # This is the SPI-chain + + self._hitArraysMAPSA = None + self._trimScanHits = None + self._thrScanMAPSA = None + + # Connection and GLIB + a = uasic(connection="file://connections_test.xml",device="board0") + self._glib = a._hw + + # Source all classes + self._mapsaClasses = MAPSA(a) + + # Get all 6 MPAs and corresponding configs + self._mpa=[] + self._conf=[] + + for i in range(0,6): + self._mpa.append(MPA(self._glib,i+1)) # List of instances of MPA, one for each MPA + + for SPI in self._iMPA: # Config is written via the SPI-chain, therefore only an array with maximum length of chain is necessary + self._conf.append(self._mpa[SPI].config("data/Default_MPA.xml")) + + # Modify config + + self._glib.getNode("Control").getNode("MPA_clock_enable").write(0x1) + self._glib.dispatch() + + self._glib.getNode("Control").getNode('testbeam_clock').write(0x0) # Enable glib clock + self._glib.dispatch() + + self._glib.getNode("Configuration").getNode("num_MPA").write(self._nMPA) + self._glib.dispatch + + # Define default config + + self._prevTrim = 30 # Trimming value with which threshold scan is executed + + defaultPixelCfg = {'PML':1,'ARL':1,'CEL':0,'CW':0,'PMR':1,'ARR':1,'CER':0,'SP':0,'SR':1,'TRIMDACL':self._prevTrim,'TRIMDACR':self._prevTrim} + defaultPeripheryCfg = {'OM':3,'RT':0,'SCW':0,'SH2':0,'SH1':0,'THDAC':0,'CALDAC':0} + + # Upload (works for all MPAs, even if not all are present. Which ones is not critical as they all get the same config) + for SPI in self._iMPA: + for key in defaultPeripheryCfg: + self._conf[SPI].modifyperiphery(key,defaultPeripheryCfg[key]) + for pix in range(0,24): + for key in defaultPixelCfg: + self._conf[SPI].modifypixel(pix + 1,key,defaultPixelCfg[key]) + + self._conf[SPI].upload() + self._glib.getNode("Configuration").getNode("mode").write(self._nMPA - 1) + self._glib.dispatch() + + + def __wrap(self, arg, level): # This function is used to allow supplying single MPAs as arguments in the class methods. ( e.g. 5 instead of [5] to use only MPA5) + + def depth(l): + if isinstance(l, list): + return 1 + max(depth(item) for item in l) + else: + return 0 + + if level <= depth(arg): + return arg + + if level > depth(arg): + return(self.__wrap([arg], level)) + + + def thresholdScan(self, MAPSA=None, shutterDur=0xFFFF, calEnbl=False, calCharge=50, calNum=1000 , resolution=1, conf = None ): + + if MAPSA == None: + MAPSA = self._assembly + + MAPSA = self.__wrap(MAPSA,1) + + self._thrScanMAPSA = MAPSA # self.writeCalibrationToMPAs needs to know to which MPAs to apply the trimDACs. + + if len(MAPSA) > self._nMPA: + print "Can't do threshold scans on MPAs not declared for this assembly. Please do that when initializing" + + + if conf is not None: + self._conf = conf + + # Write to board whether calibration charge is wanted or not + #self._mapsaClasses.daq().Strobe_settings(calNum,0x8F,40,40,cal=int(calEnbl)) # Push number of pulses, delay between shutter open and first pulse, length of pulses, time between pulses, enable calibration (on GLIB) to GLIB (all MPAs) + self._mapsaClasses.daq().Strobe_settings(calNum,0x8F,40,40,cal=int(calEnbl)) + for SPI in self._iMPA: + self._conf[SPI].modifyperiphery('CALDAC',calCharge) + self._conf[SPI].upload() + for pix in range(0,24): # These are not the real pixel numbers because the middle row (pixel 17 - 32) is not flipped (see MPA-Light manual). + self._conf[SPI].modifypixel(pix+1, 'CER', int(calEnbl)) + self._conf[SPI].modifypixel(pix+1, 'CEL', int(calEnbl)) + self._conf[SPI].upload() + + self._glib.getNode("Configuration").getNode("mode").write(self._nMPA - 1) + self._glib.dispatch() + + # Arrays containing sub-arrays for each MPA, may contain only one MPA: [MPA1[Thld1[Pix1, Pix2,.., Pix48],Thld2[Pix1,...,Pix48]], MPA2[[],..,[]],...] + self._eventArrayMAPSA = [] # Total number of recorded events per threshold + self._bxArrayMAPSA = [] # Number of clock cycles until memory is filled + self._hitArrayCounterMAPSA = [] # Hits in ripple counter (asynchronous acquisition, usually more than synchronous) + self._hitArrayMemoryMAPSA = [] # Hits in memory (synchronous acquisition) + self._thrArrayMAPSA = [] # Thresholds over which will be scanned + + + for MPA in MAPSA: # MPA are absolute numbers for the actual MPAs on the board + SPI = self._assembly.index(MPA) # relative numbers, used for SPI chain + + # Arrays to be filled by threshold scan + eventArray = [] + bxArray = [] + hitArrayCounter = [] + hitArrayMemory = [] + thrArray = [] + + # Start threshold scan + for thr in range(0,255, resolution): # Only every 'resolution'-steps, reflected in precision of falling edges after trimming + + #time.sleep(0.1) + + self._conf[SPI].modifyperiphery('THDAC',thr) + self._conf[SPI].upload() + + self._glib.getNode("Configuration").getNode("mode").write(self._nMPA - 1) + self._conf[SPI].spi_wait() # includes dispatch + + + ########################## + ####### Sequencer ######## + ########################## + # Opens shutter (mode = 0x0 single shutter, 0x1 four (buffers) consequitive shutter) + # Set shutter duration + # Write in first buffer (default and therefore not necessary to be defined) + # Readout has to be enabled in order to get the data. Default. + self._mapsaClasses.daq().Sequencer_init(0, shutterDur ) + + counter = self._glib.getNode("Readout").getNode("Counter").getNode("MPA"+str(SPI + 1)).getNode("buffer_1").readBlock(25) # Place in SPI-Chain is needed for ripple counter but 1-indexed + self._glib.dispatch() + + # Readout ripple counter + counterArray = [] + for x in range(1,len(counter)): # Skip header at [0] + counterArray.append(counter[x] & 0x7FFF) # Mask to select left pixel. First bit is not considered as this seems sometimes to be set erronously. (Lots of entries with 0b1000000000000000) + counterArray.append((counter[x] >> 16) & 0x7FFF) # Mask to select right pixel. Same as above. + + # Readout buffer (TRUE / FALSE : Wait for sequencer) with absolute MPA-values in array index. Parameter 'dcindex' in read_raw() has no function as it only affects ripple counter return + mem = self._mpa[MPA -1].daq().read_raw(1,1,True)[0] + + + # Mem integer array to binary string in readable order (header,bx,pix) + binMemStr= "" + for i in range(0,216): + binMemStr = binMemStr + '{0:032b}'.format(mem[215-i]) + + # String to binary array + binMem = [binMemStr[x:x+72] for x in range(0,len(binMemStr),72)] + + # Get elements of binary string + hd = [] + bx = [] + pix = [] + for entry in binMem[:-1]: # Discard last entry in memory as here the 48th - pixel is always set. This is intended as a workaround, the maximum number of hits per pixel and memory is now 95. + hd.append(entry[:8]) + bx.append(entry[8:24]) + pix.append(entry[24:40]+ "".join(reversed([entry[40:56][i:i+2] for i in range(0, 16, 2)])) + entry[56:]) # Row 2 is numbered from right to left while Rows 1 and 3 are numbered left-to-right. Therefore middle of array must be reversed in blocks of 2 + + # Count number of Events + nEvents = 0 + for event in hd: + if event == "11111111": + nEvents+=1 + + # Sum hits per pixel + sumPixHits = [0]*48 + for event in pix: + for i, ipix in enumerate(event): + sumPixHits[i]+=int(ipix) + + # bunch crossing from binary to int + bx=[int(ibx,2) for ibx in bx] + + eventArray.append(nEvents) + bxArray.append(bx) + hitArrayMemory.append(sumPixHits) + hitArrayCounter.append(counterArray) + thrArray.append(thr) + + + print "---END OF SCAN MPA: %s---" %MPA + + self._eventArrayMAPSA.append(eventArray) + self._bxArrayMAPSA.append(bxArray) + self._hitArrayCounterMAPSA.append(hitArrayCounter) + self._hitArrayMemoryMAPSA.append(hitArrayMemory) + self._thrArrayMAPSA.append(thrArray) + + self._hitArraysMAPSA = [self._hitArrayCounterMAPSA, self._hitArrayMemoryMAPSA] + + return True + + def getThrScanRawHits(self): + if self._hitArraysMAPSA == None: + print "No threshold scan done, nothing to return \n" + return self._hitArraysMAPSA + + def getThrScanMetadata(self): + return self._eventArrayMAPSA, self._bxArrayMAPSA, self._thrArrayMAPSA + + # Returns list of asynchronous and synchronous acquisition (counter, memory), each containing data for all MPAs (6 or less). Example for full assembly: [Counter[MPA1[Threshold1[Pix1,..,Pix48], Threshold2[...]],...,MPA6[]], Memory[MPA1, MPA2, ... , MPA6]] + def getThrScanPerPix(self): + pxlVsThrPixMem = [] + for i,hitArrayMAPSA in enumerate(self._hitArraysMAPSA): # Loop over data from asynchronous and synchronous acquisition + pxlVsThr = [] + for hitArray in hitArrayMAPSA: # Loop over hit arrays for each MPA + pxlVsThr.append([list(pix) for pix in zip(*hitArray)]) # Transpose sub-array [threshold1[pix1, pix2,...,pix48], threshold2[...], ..., threshold255[...]] to [pix1[threshold1, threshold2, ..., threshold255], pix2[...],...,pix48[...]] + pxlVsThrPixMem.append(pxlVsThr) + return pxlVsThrPixMem + + + def findHalfMaxEdges(self, counter = None): # Supply data from ripple counter in format [Pix1[Thr1, Thr2..], Pix2[..], Pix48[..]] or in format [MPA1[Pix1[Thr1, Thr2,...], Pix2[...],...], MPA2[...],...] + if counter == None: + counter, _ = self.getThrScanPerPix() # Returns data from ripple counter and from memory but memory is not needed for finding edges + + counter = self.__wrap(counter,3) # Wrap counter in list to allow iterating over it once + + edgesMAPSA = [] + for i,pxlVsThrCounter in enumerate(counter): # Loop over MAPSA (single MPAs) + risingEdges = [] + fallingEdges = [] + for pxlNum,pxl in enumerate(pxlVsThrCounter): + pxlMax = max(pxl) + thresholdValueAndPxl = zip(self._thrArrayMAPSA[i],pxl) # Match thresholds to amount of hits and create list of tuples + + maxBin = len(pxl) - pxl[::-1].index(pxlMax) - 1 # Find highest threshold with maximum number of hits, right before falling edge + halfMax = pxlMax/2 # Half maximum, either on rising or on falling edge + + pxlLeftOfPeak = thresholdValueAndPxl[:maxBin + 1] # Get rid of falling edge which has higher thresholds than maxBin + pxlRightOfPeak = thresholdValueAndPxl[maxBin:] # Get rid of rising edge which has lower thresholds than maxBin + + for thrIdx,threshold in enumerate(pxlLeftOfPeak): # Find first threshold with more hits than middle of rising edge, then get the one left of that. + if threshold[1] > halfMax: + risingEdges.append(pxlLeftOfPeak[thrIdx-1][0]) + break # Only one threshold is needed, leave loop + else: #nobreak + print "Something went wrong for pixel %s, not possible to find rising edge" %pxlNum + print pxl + risingEdges.append(None) + + for threshold in pxlRightOfPeak: # Find first threshold with less hits than middle of falling edge, then break + if threshold[1] < halfMax: + fallingEdges.append(threshold[0]) + break # Only one threshold is needed, leave loop + else: # nobreak, break condition has never been met as graph keeps rising constantly + print "Graph for Pixel %s has no falling edge, appending '254' as dummy value" %pxlNum + fallingEdges.append(254) + edgesMAPSA.append(zip(risingEdges, fallingEdges)) + return edgesMAPSA + + def findFallingEdges(self, counter = None): + edgesMAPSA = self.findHalfMaxEdges(counter) + + fallingEdgesMAPSA = [] + for edges in edgesMAPSA: + fallingEdgesMAPSA.append(list(zip(*edges)[1])) # Undo the zip in findHalfMaxEdges() as we only need the falling edges. + + return fallingEdgesMAPSA + + + + def getTrimBits(self, fallingEdgesMAPSA = None, trimThresholdMAPSA = None, minimize = True, ratioThrTrim = None ) : + if fallingEdgesMAPSA == None: # By default get falling edges from last threshold scan + fallingEdgesMAPSA = self.findFallingEdges() + print "Getting falling edges from last threshold scan" + + + if trimThresholdMAPSA == None: # Allow forcing a threshold on which to trim. + trimThresholdMAPSA = [min(fallingEdges) for fallingEdges in fallingEdgesMAPSA] + else: + minimize = False # When using minimizing it's not possible to guarantee a threshold on which is trimmed as all trimDACs are set as low as possible. Therefore disable minimizing when using explicit trimThreshold. + + fallingEdgesMAPSA = self.__wrap(fallingEdgesMAPSA, 2) + trimThresholdMAPSA = self.__wrap(trimThresholdMAPSA, 1) + + if ratioThrTrim is None: # As default, trim every pixel using the same ratio from the MPA manual + ratioThrTrim = self.thrVoltStep/self.trimVoltStep + + if isinstance(ratioThrTrim, int) or isinstance(ratioThrTrim, float): # If passed value is an int or a float the ratio is applied to all pixels and mpas + ratioThrTrim = [[ratioThrTrim] * len(fallingEdgesMAPSA[0])]*len(fallingEdgesMAPSA) + + + if len(trimThresholdMAPSA) != len(fallingEdgesMAPSA): + print "Number of supplied thresholds doesn't match number of given falling edges (%s thresholds and %s falling edges)." %(len(trimThresholdMAPSA), len(fallingEdgesMAPSA)) + + + trimDACMAPSA = [] + for nMPA,fallingEdges in enumerate(fallingEdgesMAPSA): + trimDACToTheLeft = [(edge - trimThresholdMAPSA[nMPA]) * ratioThrTrim[nMPA][pxl] for pxl, edge in enumerate(fallingEdges)] + + trimDAC = [max(0, (self._prevTrim - int(round(pxlTrimDac)))) for pxlTrimDac in trimDACToTheLeft] # Normalize trimDAC and take into account that we started with trimDAC set to some value 'self._prevTrim' (default 30) + + if minimize: + trimDAC = [pix - min(trimDAC) for pix in trimDAC] # Set all trimDAC as low as possible + trimDACMAPSA.append(trimDAC) + + return trimDACMAPSA + + + def writeCalibrationToMPA(self, MAPSA = None, trimDAC = None, debug = False): # Write trimDAC values to MPA + # Default: Write calibration values to all MPAs given in initialization and use trimDACs derived from threshold scan + if trimDAC == None: + trimDAC = self.getTrimBits() + print "Getting trim bits from last threshold scan" + if MAPSA == None: + MAPSA = self._thrScanMAPSA # If neither trimDAC nor MAPSA are supplied get them from the last threshold scan + else: # If trimDAC but no MAPSA is supplied use full assembly + if MAPSA == None: + MAPSA = self._assembly + + # Allow supplying only data for one MPA without unnecessary nested lists + MAPSA = self.__wrap(MAPSA,1) + trimDAC = self.__wrap(trimDAC, 2) + + if len(MAPSA) != len(trimDAC): + print "Error: Number of trimDACs doesn't match number of MPAs" + iMPA = [] + for MPA in MAPSA: + iMPA.append(self._assembly.index(MPA)) # construct SPI chain + for i,MPA in enumerate(iMPA): + for pix in range(0,24): + self._conf[MPA].modifypixel(pix + 1,'TRIMDACL',trimDAC[i][2*pix]) + self._conf[MPA].modifypixel(pix + 1,'TRIMDACR',trimDAC[i][2*pix + 1]) + + self._conf[MPA].upload() + self._glib.getNode("Configuration").getNode("mode").write(self._nMPA - 1) + self._conf[MPA].spi_wait() # includes dispatch + + + # Debug mode, verify written TrimDACs + if debug == True: + readconfMAPSA = [] + for iMPA, _ in enumerate(MAPSA): + readconf = [] + + # Write twice to push config to Memory_OutConf to check what has been written + self._glib.getNode("Configuration").getNode("mode").write(self._nMPA - 1) + self._conf[iMPA].spi_wait() + self._glib.getNode("Configuration").getNode("mode").write(self._nMPA - 1) + self._conf[iMPA].spi_wait() + outConf = self._glib.getNode("Configuration").getNode("Memory_OutConf").getNode("MPA"+str(iMPA + 1)).getNode("config_1").readBlock(0x19) # Get written config + self._glib.dispatch() + for pix in outConf: # Format this config to extract trimDac values + readconf.append((pix >> 2) & 0b11111) + readconf.append((pix >> 12) & 0b11111) + readconfMAPSA.append(readconf[2:]) # Drop header, append one config for each MPA + + return trimDAC, readconfMAPSA + else: + return True + + + def trimScan(self, MAPSA = None, resolution = 1): + + if MAPSA == None: + MAPSA = self._assembly + MAPSA = self.__wrap(MAPSA, 1) + + self._trimScanHits = [] + self._trimScanTrimDACs = [] + for trimDAC in range(0,32, resolution): + print "Setting all trimDACs to %s" %trimDAC + self.writeCalibrationToMPA(MAPSA, [[trimDAC]*48]*len(MAPSA)) # Write same trimDAC to all pixels and to number of MPAs specified in MAPSA + self.thresholdScan(MAPSA, calEnbl = True) + counter, _ = self.getThrScanPerPix() + self._trimScanHits.append(counter) + self._trimScanTrimDACs.append(trimDAC) + return True + + def getTrimScanHits(self): + + MAPSAtrimScan = [list(mpa) for mpa in zip(*self._trimScanHits)] # MPA[Trim[ThrScanPerPix]] (swap highest and second-highest order of nesting) + return MAPSAtrimScan + + def getTrimScanEdges(self): + trimScanEdges = [] + for trim in self._trimScanHits: + trimScanEdges.append(self.findFallingEdges(trim)) + MAPSAtrimScanEdges = [list(mpa) for mpa in zip(*trimScanEdges)] # MPA[Trim[Pix]] + return MAPSAtrimScanEdges + + def getTrimScanMetadata(self): + return self._trimScanTrimDACs + + def voltTest(self, MAPSA = None): + + if MAPSA == None: + MAPSA = self._assembly + + + MAPSA = self.__wrap(MAPSA, 1) + self.thresholdScan(MAPSA) + edgesMAPSA = self.findHalfMaxEdges() + fwhmMAPSA = [] + for edges in edgesMAPSA: + fwhm = [pix[1] - pix[0] for pix in edges] # Loop over edge-tuples for each pixel and subtract rising edges from falling edge. This is the full width at half maximum. + fwhmMAPSA.append(fwhm) + + return fwhmMAPSA + + + def automaticBondTest(self, MAPSA = None, resolution = 5, voltMin = 5): + + if MAPSA == None: + MAPSA = self._assembly + + try: + from KeithleyControl.keithleyControl import keithley + except ImportError: + print "No automatic bond test without power supply with RS232" + return False # Can't do automatic bond test without variable bias voltage. + + MAPSA = self.__wrap(MAPSA, 1) + + voltSource = keithley() + voltSource.init() + + self._counterArray = [] + self._edgesVoltScan = [] + self._voltArray = [] + + + for voltStep in range(voltMin, 111, resolution): # Loop over bias voltage in steps of 'resolution'. Start with 5V to avoid strange behaviour of sensor. + + self._voltArray.append(voltStep) + voltSource.setVoltage(voltStep) + + self.thresholdScan(MAPSA) + + self._counterArray.append(self.getThrScanPerPix()[0]) + self._edgesVoltScan.append(self.findHalfMaxEdges()) + + print voltSource.readVoltage() + voltSource.close() + + return True + + def bondTestGetThrScanPerVolt(self): + + return self._counterArray + + + def bondTestGetFwhmPerVolt(self): + + fwhmMAPSAVolt = [] # Volt[MPA[Pix]] + + for edgesMAPSA in self._edgesVoltScan: + fwhmVolt = [] + for edges in edgesMAPSA: + fwhm = [pix[1] - pix[0] for pix in edges] # Loop over edge-tuples for each pixel and subtract rising edges from falling edge. This is the full width at half maximum. + fwhmVolt.append(fwhm) + fwhmMAPSAVolt.append(fwhmVolt) + + MAPSAVoltFWHM = [list(volt) for volt in zip(*fwhmMAPSAVolt)] # MPA[Volt[Pix]] (swap highest and second-highest order of nesting) + + MAPSAFWHMVolt = [] + for MPA in MAPSAVoltFWHM: # MPA[Pix[Volt]] (swap third-highest and second-highest order of nesting) + MAPSAFWHMVolt.append([list(pix) for pix in zip(*MPA)]) + + return self._voltArray, MAPSAFWHMVolt + + def bondTestGetDiff(self): + + _, MAPSAFWHMVolt = self.bondTestGetFwhmPerVolt() + + + fwhmDiffMAPSA = [] + for MPA in MAPSAFWHMVolt: + fwhmDiff = [] + for pix in MPA: + fwhmDiff.append(sum(sorted(pix)[-2:])/2 - sum(sorted(pix)[:2])/2) # Average two highest and two lowest fwhms + fwhmDiffMAPSA.append(fwhmDiff) + + return fwhmDiffMAPSA + + +if __name__ == "__main__": + + from MPAPlot import MPAPlot + plot = MPAPlot() + assembly = [2,5] + nMPA = 2 + + calibration = MPACalibration(assembly) + calibration.thresholdScan(None, calEnbl = False, shutterDur=0xFFFF, calCharge = 100, calNum = 10000) + + + counter, mem = calibration.getThrScanPerPix() + _,_,threshold = calibration.getThrScanMetadata() + for pix in counter[0]: + plot.createGraph(threshold[0], pix) + plot.draw() + plot.clear() + trimDac = calibration.getTrimBits() + print trimDac + calibration.writeCalibrationToMPA(None, trimDAC = trimDac) + + calibration.thresholdScan(None) + counter, mem = calibration.getThrScanPerPix() + _,_,threshold = calibration.getThrScanMetadata() + for pix in counter[0]: + plot.createGraph(threshold[0], pix) + plot.draw() diff --git a/MPAPlot.py b/MPAPlot.py new file mode 100644 index 0000000..15f2813 --- /dev/null +++ b/MPAPlot.py @@ -0,0 +1,195 @@ +#!/usr/bin/python +import sys +import ROOT + +class MPAPlot(object): + + def __init__(self): + ROOT.gStyle.SetPalette(55) + self.__plots = [] + + def createHitMap(self, hitArray): + + x = [ix for ix in range(0,16)] + y = [0,1,2] + + hits = [] + + if len(hitArray) is 48: + hits.append(hitArray[:16]) + hits.append(list(reversed(hitArray[16:32]))) + hits.append(hitArray[32:]) + else: + sys.exit("Hit array must contain 48 entries") + + histo = ROOT.TH2F("h1","HitMap",16,0.5,16.5,3,0.5,3.5) + mask = [(12,1)] + mask = [] + + for iy in y: + for ix in x: + masked = False + for m in mask: + if ix == m[0] and iy == m[1]: + masked = True + break + if masked: + continue + binNo = histo.FindBin(ix+0.5, iy+0.5) + histo.SetBinContent(binNo, hits[iy][ix]) + histo.Rebuild() + histo.GetYaxis().SetNdivisions(3) + + self.__plots.append(histo) + + def createCorrelationPlot(self, mpa, ref, axis, offset=0): + + if axis == "Y": + histo = ROOT.TH2F("h1",axis + " Correlation of MPA and REF ;MPA (DUT); REF",3,0.5,3.5,80,0.5,80.5) + else: + histo = ROOT.TH2F("h1",axis + " Correlation of MPA and REF ;MPA (DUT); REF",16,0.5,16.5,52,0.5,52.5) + + for iEvent,event in enumerate(ref): + for refHit in event: + if iEvent+offset < len(mpa) and iEvent+offset > 0: + for mpaHit in range(len(mpa[iEvent+offset])): + histo.Fill(mpa[iEvent+offset][mpaHit]+0.5, refHit+0.5) + + self.__plots.append(histo) + + def fillHisto(self, hitArray, xMin=0, xMax=255, nBins=255): + + histo = ROOT.TH1F("h1","Histogram",nBins,xMin,xMax) + + for hit in hitArray: + histo.Fill(hit) + + self.__plots.append(histo) + + def createHisto(self, hitArray, xMin=0, xMax=255, nBins=255): + + histo = ROOT.TH1F("h1","Histogram",nBins,xMin,xMax) + + for ibin, hit in enumerate(hitArray): + histo.SetBinContent(ibin,hit) + + self.__plots.append(histo) + + def fitHisto(self, fitparam = "gaus"): + for plot in self.__plots: + if isinstance(plot, ROOT.TH1F): + result = plot.Fit(fitparam, "S") + else: + print "Not a TH1F histogram" + return False + return result + + def createGraph(self, x, y): + + if isinstance(x,list) or isinstance(y, list): + from array import array + if isinstance(x,list): + x = array('d',x) + if isinstance(y,list): + y = array('d',y) + + self.__plots.append(ROOT.TGraph(len(x),x,y)) + + def getPlot(self, iPlot=None): + + if iPlot is None: + return self.__plots + else: + return self.__plots[iPlot] + + def draw(self, arg="APL", name="c1"): + + if isinstance(self.__plots[0],ROOT.TH2F): + c1 = ROOT.TCanvas(name, "Canvas", 600, 800) + else: + c1 = ROOT.TCanvas(name, "Canvas", 800, 600) + c1.cd() + ROOT.gPad.SetLogz(True) + + if isinstance(self.__plots[0],ROOT.TH2F): + c1.SetRightMargin(0.15) + for plot in self.__plots: + plot.Draw("colz") + elif isinstance(self.__plots[0],ROOT.TH1F): + for i,plot in enumerate(self.__plots): + if i is 0: + plot.Draw() + else: + plot.Draw("SAME") + elif isinstance(self.__plots[0],ROOT.TGraph): + + for i,plot in enumerate(self.__plots): + if i is 0: + plot.Draw(arg) + else: + plot.Draw(arg.replace("A","") + "SAME") + + else: + sys.exit("Unknown plot type") + + img = ROOT.TImage.Create() + img.FromPad(c1) + img.WriteImage("plots/hitmap.png") + + raw_input() + + def setLineColor(self, colors): + + if len(colors) is not len(self.__plots): + sys.exit("Not enough or too many colors! Colors has length %s and there are %s plots" %(len(colors), len(self.__plots))) + else: + for i,plot in enumerate(self.__plots): + plot.SetLineColor(colors[i]) + return True + + def setTitle(self, title): + self.__plots[0].SetTitle(title) + + return True + + def setRange(self, xRange = None, yRange = None, zRange = None): + + if xRange is not None: + self.__plots[0].GetXaxis().SetRangeUser(xRange[0],xRange[1]) + if yRange is not None: + self.__plots[0].GetYaxis().SetRangeUser(yRange[0],yRange[1]) + if zRange is not None: + self.__plots[0].GetZaxis().SetRangeUser(zRange[0],zRange[1]) + + + return True + + def clear(self): + self.__plots = [] + + def save(self, fileName): + for i, plot in enumerate(self.__plots): + plot.SaveAs(fileName+("%s.png" %i)) + + + +if __name__ == "__main__": + + plot = MPAPlot() + + if len(sys.argv)>1: + print("Reading file {0} ...".format(sys.argv[1])) + fname = sys.argv[1] + hits = [0]*48 + with open(fname) as f: + for line in f: + line = line[1:-2].split(",") # remove [ and ], split by , + for i, count in enumerate(line): + hits[i] += int(count) + print(" ... done!") + else: + hits = [80, 40, 44, 43, 30, 34, 0, 46, 0, 64, 0, 75, 0, 0, 59, 108, 88, 27, 25, 38, 34, 30, 39, 28, 23, 30, 28, 30, 35, 35, 31, 54, 61, 28, 31, 30, 35, 41, 41, 0, 43, 0, 48, 38, 40, 36, 35, 83] + #hits = [89, 32, 33, 49, 35, 34, 28, 38, 55, 37, 38, 35, 25, 22, 43, 92, 70, 35, 35, 31, 22, 23, 21, 24, 23, 32, 26, 31, 34, 39, 45, 103, 107, 42, 41, 29, 21, 30, 27, 33, 30, 34, 34, 24, 28, 44, 41, 63] + plot.createHitMap(hits) + #plot.fillHisto(hits) + plot.draw() diff --git a/MPAThreshold.py b/MPAThreshold.py new file mode 100644 index 0000000..fb1e382 --- /dev/null +++ b/MPAThreshold.py @@ -0,0 +1,42 @@ +from classes import * +from MPACalibration import MPACalibration +from MPAPlot import MPAPlot + +assembly = [2,5] + +# Connection and GLIB +a = uasic(connection="file://connections_test.xml",device="board0") +glib = a._hw + +# Enable clock on MPA +glib.getNode("Control").getNode("MPA_clock_enable").write(0x1) +glib.dispatch() + +# Reset all logic on GLIB +glib.getNode("Control").getNode("logic_reset").write(0x1) +glib.dispatch() + +# Source all classes +mapsaClasses = MAPSA(a) + +calibration = MPACalibration(assembly) + +conf = [] +mpa = [] +for iMPA, nMPA in enumerate(assembly): + mpa.append(MPA(glib, iMPA+1)) # List of instances of MPA, one for each MPA. SPI-chain numbering! + conf.append(mpa[iMPA].config("data/Conf_trimcalib_MPA" + str(nMPA)+ "_masked.xml")) # Use trimcalibrated config + +calibration.thresholdScan(calEnbl = False, conf = conf) + + +counter, mem = calibration.getThrScanPerPix() +_,_,threshold = calibration.getThrScanMetadata() + +for i, nMPA in enumerate(counter): + plot = MPAPlot() + for pix in nMPA[1:]: + plot.createGraph(threshold[i], pix) + plot.draw() + + diff --git a/__init__.py b/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/advancedTrimDacCalibration.py b/advancedTrimDacCalibration.py new file mode 100644 index 0000000..ed83474 --- /dev/null +++ b/advancedTrimDacCalibration.py @@ -0,0 +1,133 @@ +from MPACalibration import MPACalibration +from MPAPlot import MPAPlot +from ROOT import gStyle, TGraph, TCanvas, TLine, TF1, TFile +import xml.etree.ElementTree as ET + +assembly = [2,5] +calibration = MPACalibration(assembly) +mpaConfig = [] + +for MPA in assembly: + mpaConfig.append(ET.parse("data/Conf_default_MPA"+str(MPA)+"_config1.xml")) # Construct list of XML files, one for each MPA + +calibration.thresholdScan(calEnbl = True) +calibration.writeCalibrationToMPA() + +calibration.thresholdScan() +counter, _ = calibration.getThrScanPerPix() +preScanEdges = calibration.findFallingEdges() + +rootFile = TFile("plots_kit/Trim_Scan_results.root", "recreate") + +RMS = [] + +for iMPA, edge in enumerate(preScanEdges): + plot = MPAPlot() + plot.fillHisto(edge) + plot.setTitle('Falling edges of MPA ' + str(assembly[iMPA]) + ' after calibration with fixed ThrDAC/TrimDAC-ratio; Threshold (DAC);# of Pixels') + plot.draw() + histo = plot.getPlot(0) + RMS.append(histo.GetRMS()) + histo.Write() + + +calibration.trimScan(resolution = 1) + +trimScanEdges = calibration.getTrimScanEdges() # MPA[trim[pix]] +trimArray = calibration.getTrimScanMetadata() + +fitvalsMPA = [] +for nMPA, MPA in enumerate(trimScanEdges): + MPA = [list(pix) for pix in zip(*MPA)] #Turn trim[pix] into pix[trim] for easier plotting + plot = MPAPlot() + for pix in MPA: + plot.createGraph(trimArray, pix) + plot.draw() + + graphs = plot.getPlot() + fitFunc = TF1("fa1","[0]+x*[1]",0,32) + fitvals = [] + mpaDir = rootFile.mkdir("Edges vs Trim "+str(assembly[nMPA]), "Edges vs Trim"+str(assembly[nMPA])) + print graphs + for i,graph in enumerate(graphs): + graph.SetLineColor(i+1) + graph.SetMarkerStyle(8) + fitFunc.SetName("Fit for pixel "+str(i+1)) + result = graph.Fit(fitFunc.GetName(), "S") + graph.GetYaxis().SetRangeUser(0,255) + graph.GetXaxis().SetRangeUser(0,220) + if i==0: + graph.SetTitle('Trim Scan of MPA '+str(assembly[nMPA])+';Trim (DAC);Falling Edge (Threshold)') + mpaDir.Add(graph) + graph.Draw("APL") + else: + graph.SetTitle('Pixel ' +str(i+1)) + mpaDir.Add(graph) + graph.Draw("PL") + fitvals.append(1/result.Parameter(1)) + + mpaDir.Write() + raw_input("Press any key to proceed") + fitvalsMPA.append(fitvals) + +for MPA in fitvalsMPA: + plot = MPAPlot() + plot.fillHisto(MPA, 0.3, 0.5, 50) + plot.setTitle("Ratio of ThrDAC and TrimDAC; Ratio; Number of Pixels") + plot.draw() + histo = plot.getPlot(0) + histo.Write() + +calibration.thresholdScan(calEnbl = True) + +trimDac = calibration.getTrimBits(ratioThrTrim = fitvalsMPA) + +calibration.writeCalibrationToMPA(trimDAC = trimDac) + +for iMPA, MPAtree in enumerate(mpaConfig): # loop over configs for individual MPAs + MPA = MPAtree.getroot() + for iPix,pixel in enumerate(MPA.findall('pixel')): + pixel.find('TRIMDACL').text = str(trimDac[iMPA][2*iPix]) + pixel.find('TRIMDACR').text = str(trimDac[iMPA][2*iPix+1]) + if pixel.find('THRTRIMRATIOL') is None: + ET.SubElement(pixel, 'THRTRIMRATIOL') + if pixel.find('THRTRIMRATIOR') is None: + ET.SubElement(pixel, 'THRTRIMRATIOR') + pixel.find('THRTRIMRATIOL').text = '{0:.5}'.format(str(fitvalsMPA[iMPA][2*iPix])) + pixel.find('THRTRIMRATIOR').text = '{0:.5}'.format(str(fitvalsMPA[iMPA][2*iPix + 1 ])) + + MPAtree.write('data/Conf_trimcalib_MPA'+str(assembly[iMPA])+'_config1.xml') + + +calibration.thresholdScan() + +counter, _ = calibration.getThrScanPerPix() +postScanEdges = calibration.findFallingEdges() + +for mpa in counter: + plot = MPAPlot() + for pix in mpa: + plot.createGraph(range(0,255), pix) + graphs = plot.getPlot() + for i, graph in enumerate(graphs): + graph.SetTitle('Pixel ' +str(i+1)) + if i == 0: + graph.Draw("APL") + else: + graph.Draw("PL") + +raw_input() + +for iMPA,edge in enumerate(postScanEdges): + plot = MPAPlot() + plot.fillHisto(edge) + plot.setTitle('Falling edges of MPA ' + str(assembly[iMPA]) + ' after calibration with ThrDAC/TrimDAC-ratios from trim scan; Threshold (DAC);# of Pixels') + histo = plot.getPlot(0) + RMS.append(histo.GetRMS()) + histo.Write() + plot.draw() +rootFile.Close() + +print trimDac + +print "Root mean squares before trim scan: %s and %s. Root mean squares after trim scan: %s and %s." %(RMS[0], RMS[1], RMS[2], RMS[3]) diff --git a/bondTest.py b/bondTest.py new file mode 100644 index 0000000..d5a7272 --- /dev/null +++ b/bondTest.py @@ -0,0 +1,61 @@ +from MPACalibration import MPACalibration +from MPAPlot import MPAPlot +from KeithleyControl.keithleyControl import keithley +from ROOT import TCanvas + +k = keithley() +k.init() +k.setVoltage(110) +assembly = [2,5] + +calibration = MPACalibration(assembly) + +calibration.thresholdScan(calEnbl = 1) +k.close() +calibration.writeCalibrationToMPA() + + +calibration.automaticBondTest(resolution = 2, voltMin = 0) + +voltArray, fwhmPerVolt = calibration.bondTestGetFwhmPerVolt() # MPA[Pix[Volt]] + +## Data from measurement with Sr90 source on MPA5 to allow comparison with confirmed dead pixels +hits = [24535, 15100, 16743, 14068, 17042, 14568, 22333, 17551, 0, 19322, 0, 19147, 0, 0, 19984, 24712, 24401, 15963, 15078, 16422, 13774, 14310, 13577, 15085, 11354, 14313, 13706, 14324, 12457, 14413, 14432, 23665, 24579, 12675, 13340, 12612, 15251, 10976, 15562, 0, 16572, 0, 16463, 13214, 15304, 13793, 15967, 24799] +colors = [1 if pix > 10 else 2 for pix in hits] + +for nMPA, MPA in enumerate(fwhmPerVolt): # Loop over MPAs + plot = MPAPlot() + for fwhm in MPA: # Loop over pix + plot.createGraph(voltArray, fwhm) + plot.setTitle("Bond test for MPA" + str(assembly[nMPA]) +" ; Bias voltage / V ; FWHM of noise from threshold scan / thrDACs") + if nMPA == 1: # Mark MPA5 with confirmed bad bonds + plot.setLineColor(colors) + plot.setRange(yRange = [0,100]) + plot.draw() + +#thrScansPerBiasVolt = calibration.bondTestGetThrScanPerVolt() +# +#bondTestGraphs = [] +#for volt in thrScansPerBiasVolt: +# plot = MPAPlot() +# for pix in volt[0]: +# plot.createGraph(pix, range(0,255)) +# bondTestGraphs.append(plot.getPlot()) + +diffs = calibration.bondTestGetDiff() +print diffs[0] +print diffs[1] + +maxMPA = max([max(mpa) for mpa in diffs]) +print maxMPA + +scaledDiffs = [] +for mpa in diffs: + scaledDiffs.append([(pix*1000/maxMPA) for pix in mpa]) +print scaledDiffs + +for mpa in scaledDiffs: + plot = MPAPlot() + plot.createHitMap(mpa) + plot.setRange(zRange = [0,1000]) + plot.draw() diff --git a/calDACTest.py b/calDACTest.py new file mode 100644 index 0000000..234302e --- /dev/null +++ b/calDACTest.py @@ -0,0 +1,52 @@ +from MPACalibration import MPACalibration +from MPAPlot import MPAPlot +from KeithleyControl.keithleyControl import keithley +from ROOT import TFile + +voltSource = keithley() +voltSource.init() +voltSource.setVoltage(110) +print voltSource.readCurrent() + +rootFile = TFile("plots_kit/CalDAC_test_results.root", "recreate") +assembly = [2,5] +calibration = MPACalibration(assembly) +calibration.thresholdScan(calEnbl = True) +calibration.writeCalibrationToMPA() + +## Data from measurement with Sr90 source on MPA5 to allow comparison with confirmed dead pixels +hits = [24535, 15100, 16743, 14068, 17042, 14568, 22333, 17551, 0, 19322, 0, 19147, 0, 0, 19984, 24712, 24401, 15963, 15078, 16422, 13774, 14310, 13577, 15085, 11354, 14313, 13706, 14324, 12457, 14413, 14432, 23665, 24579, 12675, 13340, 12612, 15251, 10976, 15562, 0, 16572, 0, 16463, 13214, 15304, 13793, 15967, 24799] +colors = [1 if pix > 10 else 2 for pix in hits] + +calScanEdges = [] +for calDAC in range(0,255, 10): + + calibration.thresholdScan(calEnbl = True, calCharge = calDAC) + + calScanEdges.append(calibration.findFallingEdges()) + + +MAPSACalPix = [list(cal) for cal in zip(*calScanEdges)] + +MAPSAPixCal = [] +for MPA in MAPSACalPix: + + MAPSAPixCal.append([list(pix) for pix in zip(*MPA)]) + +for i,MPA in enumerate(MAPSAPixCal): + plot = MPAPlot() + + for pix in MPA: + plot.createGraph(range(0,255,10), pix) + if i == 1: + plot.setLineColor(colors) + plot.setTitle("Caldac linearity scan for MPA "+str(assembly[i])+"; Calibration charge / calDACs; Falling edge position / thrDACs") + plot.draw() + + graphs = plot.getPlot() + mpaDir = rootFile.mkdir("MPA "+str(assembly[i]), "MPA "+str(assembly[i])) + for graph in graphs: + mpaDir.Add(graph) + mpaDir.Write() + +rootFile.Close() diff --git a/calibration.py b/calibration.py index 786889a..cd6d2bf 100644 --- a/calibration.py +++ b/calibration.py @@ -1,10 +1,10 @@ from classes import * -from xml.dom import minidom -#import elementtree.ElementTree -#from elementtree.ElementTree import Element, SubElement, Comment import xml.etree.ElementTree +from xml.dom import minidom from xml.etree.ElementTree import Element, SubElement, Comment +#import ROOT +#from ROOT import TGraph import sys, select, os, array from array import array import ROOT @@ -16,7 +16,6 @@ from matplotlib.pyplot import show, plot from optparse import OptionParser - parser = OptionParser() parser.add_option('-s', '--setting', metavar='F', type='string', action='store', default = 'none', @@ -60,39 +59,50 @@ a._hw.dispatch() print "Running firmware version " + str(read) + + #a._hw.getNode("Control").getNode("logic_reset").write(0x1) #a._hw.dispatch() a._hw.getNode("Control").getNode("MPA_clock_enable").write(0x1) a._hw.dispatch() -smode = 0x0 # shutter options + +smode = 0x0 sdur = options.shutterdur -snum = options.number # strobe settings + +snum = options.number sdel = 0xF slen = 0xF sdist = 0xFF + + dcindex=1 buffnum=1 -mpa = [] # get all MPAs + + +mpa = [] for i in range(1,7): mpa.append(mapsa.getMPA(i)) + Confnum=1 configarr = [] if options.setting=='calibration': - CE=1 # Set Calibration Enable bit + CE=1 else: CE=0 -SP=0 # Signal polarity +SP=0 + -config = mapsa.config(Config=1,string='default') # load default cfg + +config = mapsa.config(Config=1,string='default') config.upload() @@ -100,36 +110,32 @@ config.modifyfull(confdict) mapsa.daq().Strobe_settings(snum,sdel,slen,sdist,cal=CE) - x1 = array('d') y1 = [] -for x in range(0,256): # start threshold scan +for x in range(0,256): if x%options.res!=0: continue if x%10==0: print "THDAC " + str(x) - config.modifyperiphery('THDAC',[x]*6) # change threshold for all 6 MPAs + config.modifyperiphery('THDAC',[x]*6) config.upload() config.write() mapsa.daq().Sequencer_init(smode,sdur) - pix,mem = mapsa.daq().read_data(buffnum) # pix = [[MPA1_header,MPA1_header,MPA1_pix1,..,MPA1_pix48],..,[MPA6]] - - + pix,mem = mapsa.daq().read_data(buffnum) ipix=0 - for p in pix: # Loop over MPAs + for p in pix: - p.pop(0) # Drop double header p.pop(0) - y1.append([]) # Append an empty array - y1[ipix].append(array('d',p)) # Append array of 48 pixels for each MPA and THDAC [MPA1[THDAC1[Pix1,..,Pix48] , .. , THDAC256[Pix1,..,Pix48]],..,MPA6[],[][]..] + p.pop(0) + y1.append([]) + y1[ipix].append(array('d',p)) ipix+=1 - x1.append(x) # Array of THDAC 0-255 + x1.append(x) - print "Generating nominal per pixel trimdac values" calibconfs = config._confs @@ -145,20 +151,18 @@ grarr = [] xdvals = [] -for i in range(0,6): # loop over MPA +for i in range(0,6): backup=TFile("plots/backup_preCalibration_"+options.string+"_MPA"+str(i)+".root","recreate") calibconfxmlroot = calibconfsxmlroot[i] xdvals.append(0.) c1.cd(i+1) thdacv = [] - yarr = np.array(y1[i]) # [ THDAC1[Pix1,..,Pix48] , .. , THDAC256[Pix1,..,Pix48] ] + yarr = np.array(y1[i]) grarr.append([]) gr1 = [] - yarrv.append(yarr) # Equivalent to y1 without empty brackets at the end - - - for iy1 in range(0,len(yarr[0,:])): # loop over 48 pixels - yvec = yarr[:,iy1] # loop over 256 THDAC for one pixel + yarrv.append(yarr) + for iy1 in range(0,len(yarr[0,:])): + yvec = yarr[:,iy1] if max(yvec)==0: print "zero" gr1.append(TGraph(len(x1)-1,array('d',xvec),array('d',yvec))) @@ -175,44 +179,41 @@ gPad.Update() + halfmax = max(yvec)/2.0 maxbin = np.where(yvec==max(yvec)) - for ibin in range(0,len(xvec)-1): # Loop over all THDAC + for ibin in range(0,len(xvec)-1): xval = xvec[ibin] xval1 = xvec[ibin+1] yval = yvec[ibin] yval1 = yvec[ibin+1] - if (yval1-halfmax)<0.0 and ibin>maxbin[0][0]: # Falling edge right before half maximum - if iy1%2==0: # Left pixel (config always for two pixels (32bit)) + if (yval1-halfmax)<0.0 and ibin>maxbin[0][0]: + if iy1%2==0: prev_trim = int(calibconfxmlroot[(iy1)/2+1].find('TRIMDACL').text) - else: # Right pixel + else: prev_trim = int(calibconfxmlroot[(iy1+1)/2].find('TRIMDACR').text) + #print "ptrim " + str(prev_trim) + #print "halfmax " + str(halfmax) - xdacval = (abs(yval-halfmax)*xval + abs(yval1-halfmax)*xval1)/(abs(yval-halfmax) + abs(yval1-halfmax)) # calculate x @ half maximum + xdacval = (abs(yval-halfmax)*xval + abs(yval1-halfmax)*xval1)/(abs(yval-halfmax) + abs(yval1-halfmax)) #if abs(yval-halfmax)> 2) & 0b11111) + readconf.append((pix >> 12) & 0b11111) + +print "Written TrimDAC: %s" %readconf[2:] + +hitArray = [] +sumArray = [] +for i in range(0,5000): + + # Start acquisition (sequencer) (Enable single (0) or four (4) consequitive buffers for shutter. Set Shutter duration and do final 'write' to push config to MPA) + mapsa.daq().Sequencer_init(0,shutterDur) + + + ################################## + ######## Wait for sequencer ###### + ################################## + busySeq = glib.getNode("Control").getNode("Sequencer").getNode("busy").read() + glib.dispatch() + while busySeq: + time.sleep(0.001) + busySeq = glib.getNode("Control").getNode("Sequencer").getNode("busy").read() + glib.dispatch() + ##################################### + ##### Sequencer not busy anymore #### + ##################################### + + # Readout ripple counter + counter = glib.getNode("Readout").getNode("Counter").getNode("MPA"+str(iMPA + 1)).getNode("buffer_1").readBlock(25) + glib.dispatch() + + counterArray = [] + + + for x in range(1,len(counter)): # Skip header at [0] + counterArray.append(counter[x] & 0x7FFF) # Mask to select left pixel, drop first bit because for some readon this can sometimes be set although it shouldn't. We don't see that many hits anyway so mask it away for now. + counterArray.append((counter[x] >> 16) & 0x7FFF) # Mask to select right pixel. Same as above + counterFile.write(str(sum(counterArray))) + counterFile.write('\n') + sumArray.append(sum(counterArray)) + +counterFile.close() +print sumArray diff --git a/common_noise/old/common_noise_histogram.py b/common_noise/old/common_noise_histogram.py new file mode 100644 index 0000000..3d14ca8 --- /dev/null +++ b/common_noise/old/common_noise_histogram.py @@ -0,0 +1,35 @@ +from ROOT import TH1F, TCanvas, TAxis, gStyle, gPad + +gStyle.SetOptFit() +numMPA = 2 # Number of installed MPAs + +c1 = TCanvas("hist", "hist", 1024, 768) +c1.Divide(2) + +histo = [] +for iMPA in range(0, numMPA): + c1.cd(iMPA+1) + memory = open('data/asynchronous_data_noise_MPA'+str(iMPA+1)).read().splitlines() + threshold = int(memory[1]) + events = [int(event) for event in memory[3:]] # Skip first 3 lines, here the threshold is stored + + histData = [[hits,events.count(hits)] for hits in set(events)] # Calculate how often each number of hits occurs + print histData + + histo.append(TH1F("h1","Common noise analysis for MPA" +str(iMPA+1)+" at Threshold "+ str(threshold), max(events), 0, max(events))) + for hits in histData: + for i in range(0,hits[1]): + histo[iMPA].Fill(hits[0]) + + XRange = int(histo[iMPA].GetMean() * 2) + histo[iMPA].SetBins(XRange, 0, XRange) + histo[iMPA].GetYaxis().SetTitle("Number of events") + histo[iMPA].GetXaxis().SetTitle("Number of hits") + + # Gauss fit + fit = histo[iMPA].Fit("gaus") + histo[iMPA].Draw() + gPad.Update() + +c1.Print('plots/common_noise_counter.pdf', 'pdf') +raw_input() diff --git a/common_noise/old/common_noise_histogram_memory.py b/common_noise/old/common_noise_histogram_memory.py new file mode 100644 index 0000000..b899ac8 --- /dev/null +++ b/common_noise/old/common_noise_histogram_memory.py @@ -0,0 +1,41 @@ +from ROOT import TH1F, TCanvas, TAxis, gStyle, gPad + +gStyle.SetOptFit() +#gStyle.SetOptStat(0) +numMPA = 2 # Number of installed MPAs + +c1 = TCanvas("hist", "hist", 1024, 768) +c1.Divide(2) + +histo = [] +for iMPA in range(0, numMPA): + c1.cd(iMPA+1) + memory = open('data/synchronous_data_noise_MPA'+str(iMPA+1)).read().splitlines() + events = [] + for event in memory[:-1]: # Get everything but the last entry + events.append(sum([int(pix) for pix in event])) + + histData = [[0,int(memory[-1])-len(events)]] # Last entry which contains the number of empty events + for hits in set(events): + histData.append([hits,events.count(hits)]) + #histData = [[hits,events.count(hits)] for hits in set(events)] # Calculate how often each number of hits occurs + print histData + + histo.append(TH1F("h1","Common noise analysis for MPA" +str(iMPA+1), 10, 0, 10)) + #histo.append(TH1F("h1","Common noise analysis for MPA" +str(iMPA+1), max(events), 0, max(events))) + for hits in histData: + for i in range(0,hits[1]): + histo[iMPA].Fill(hits[0]) + + # XRange = int(histo[iMPA].GetMean() * 2) + # histo[iMPA].SetBins(XRange, 0, XRange) + histo[iMPA].GetYaxis().SetTitle("Number of events") + histo[iMPA].GetXaxis().SetTitle("Number of hits") + + # Gauss fit + fit = histo[iMPA].Fit("gaus") + histo[iMPA].Draw() + gPad.Update() + +c1.Print('plots/common_noise_memory.pdf', 'pdf') +raw_input() diff --git a/common_noise/old/common_noise_memory_dump.py b/common_noise/old/common_noise_memory_dump.py new file mode 100644 index 0000000..72eb72c --- /dev/null +++ b/common_noise/old/common_noise_memory_dump.py @@ -0,0 +1,116 @@ +import sys +from classes import * +from array import array +from optparse import OptionParser +from ROOT import TGraph, TCanvas, TLine + +# Connection and GLIB +a = uasic(connection="file://connections_test.xml",device="board0") +glib = a._hw + +# Source all classes +mapsa = MAPSA(a) + +# Get all 6 MPAs and corresponding configs +mpa=[] +conf=[] + +for i in range(0,6): + mpa.append(MPA(glib,i+1)) + conf.append(mpa[i].config("data/Default_MPA.xml")) + + +# Define MPA (1-6) (iMPA 2 or 5 for double assembly) +mpaDict = {0:2,1:5} + +iMPA = 1 # Zero-indexed (from 0 to 5 on full assembly) + +# File to which data from synchronous acquision will be written +memoryFile = open('data/synchronous_data_noise_MPA'+str(iMPA+1),'w') + +# Set voltage steps of threshold DAC and trimming DAC (in mV/Step) +thrVoltStep = 1.456 +trimVoltStep = 3.75 + +# Modify config + +glib.getNode("Control").getNode("MPA_clock_enable").write(0x1) +glib.dispatch() +glib.getNode("Configuration").getNode("num_MPA").write(0x2) + +##### Define default config +threshold = 47 + +# Load trimDac config and convert to int +trimDac = open('trimDac_MPA'+str(iMPA+1)).read().splitlines() +trimDac = [int(pxl) for pxl in trimDac] + +shutterDur = 0xFFF #0xFFFF is maximum, in clock cycles + +defaultPixelCfg = {'PML':1,'ARL':1,'CEL':0,'CW':0,'PMR':1,'ARR':1,'CER':0,'SP':0,'SR':1,'TRIMDACL':30,'TRIMDACR':30} +defaultPeripheryCfg = {'OM':3,'RT':0,'SCW':0,'SH2':0,'SH1':0,'THDAC':threshold,'CALDAC':30} + + +# Upload +for key in defaultPeripheryCfg: + conf[iMPA].modifyperiphery(key,defaultPeripheryCfg[key]) +for pix in range(0,24): + for key in defaultPixelCfg: + conf[iMPA].modifypixel(pix + 1,key,defaultPixelCfg[key]) + + +# Write trimDac values to MPA +for pix in range(0,24): + conf[iMPA].modifypixel(pix + 1,'TRIMDACL',trimDac[2*pix]) + conf[iMPA].modifypixel(pix + 1,'TRIMDACR',trimDac[2*pix + 1]) + +conf[iMPA].upload() +glib.getNode("Configuration").getNode("mode").write(0x1) +glib.dispatch() + + +# Write twice to push config to Memory_OutConf to check what has been written +glib.getNode("Configuration").getNode("mode").write(0x1) +conf[iMPA].spi_wait() + +outConf = glib.getNode("Configuration").getNode("Memory_OutConf").getNode("MPA"+str(iMPA + 1)).getNode("config_1").readBlock(0x19) # Get written config +glib.dispatch() +readconf = [] +for pix in outConf: # Format this config to extract trimDac values +# print '{0:020b}'.format(pix) + readconf.append((pix >> 2) & 0b11111) + readconf.append((pix >> 12) & 0b11111) + +print "Written TrimDAC: %s" %readconf + +hitArray = [] +sumArray = [] +emptyEvents = [] +for i in range(0,500): + + # Start acquisition (sequencer) (Enable single (0) or four (4) consequitive buffers for shutter. Set Shutter duration and do final 'write' to push config to MPA) + mapsa.daq().Sequencer_init(0,shutterDur) + + # Read data from memory (sync acquisition) + mem = mpa[mpaDict[iMPA]-1].daq().read_raw(1,1,True)[0] + # Mem integer array to binary string in readable order (header,bx,pix) + binMemStr= "" + for i in range(0,216): + binMemStr = binMemStr + '{0:032b}'.format(mem[215-i]) + + # String to binary array + binMem = [binMemStr[x:x+72] for x in range(0,len(binMemStr),72)] + + emptyEvents.append(int(binMem[-1][9:24],2)) # Get total number of events in this iteration, convert it to an int from binary string and append. First bit of BX-Id is skipped as this can be faulty + + # Get elements of binary string + for entry in binMem: + memoryFile.write(entry[24:72]) + memoryFile.write('\n') + + time.sleep(0.1) # If this is not here strange values appear in array, maybe GLIB isn't ready + +memoryFile.write(str(sum(emptyEvents))) # Sum empty events and write to file +memoryFile.close() + + diff --git a/daq.py b/daq.py index 309d90f..a1e9dd2 100644 --- a/daq.py +++ b/daq.py @@ -1,8 +1,6 @@ from classes import * -from xml.dom import minidom -#import elementtree.ElementTree -#from elementtree.ElementTree import Element, SubElement, Comment import xml.etree.ElementTree +from xml.dom import minidom from xml.etree.ElementTree import Element, SubElement, Comment import ROOT from ROOT import TH2F, TCanvas, TTree, TBranch, TFile diff --git a/daq/.daq_counter_2MPA_xray.py.swp b/daq/.daq_counter_2MPA_xray.py.swp new file mode 100644 index 0000000000000000000000000000000000000000..5dc552dfe88ffd449b86aabb239b02aa3abb8bc7 GIT binary patch literal 12288 zcmeHNO^hQ)6|Ut!3A=})1GhzX;$mpx3pR=K-um!{p_ zTh+ZY&H)5MLV`0$ARz=2LWvM4IfVlkxDqLx;F=2p0pdaq-1uHqx2NshS>+nhEq!iR z)qAgAef3^dS*~IG>wEkBYU>Ka^DJXm|8W1_@1FYkx%)9=T8bdfQfhhPqmCw0$5&dT z*N$3&JX`b|xxw}Q?St<2pc{|UW1;1GARZ6~ew;q_ z;HSVtAOrfq4sa7#1ug*Rf%iVm*l&Pe13v`51^B@8Kn=JEy!Q-a?*I|72mI@4#@+(n z1Pq{oA#fMy0b9T&-~#aPrx<$|coX;)a17iBwt+7LzyB0tZva07z6*Q>_|GTd3!s1r z@FlcAVHVC;3^$G~@h3D5)9f#-ntKMsB1ufV&&Tfk3%Zvz^50DJ-XJn*-VG4?ia z0DKmB2XpX8;B|oJ;}<~n{GT!~QR%J{Mp{0|WaQ5pm+P-a z^#)^!R#D1pyF~+!M;v-)i(fJ|e#tZ0)SD)v7pEd@teZ)e;=0YPOz%Zq>BmuE8oaP! zWq5vJho@>P$p|-2j=vhg-eU}~mE4Eh=$4OS&86@sJW(eyY;yEJl>v_*N=?QJ>;B9S zrFGKT^+FkW@OxY14$zLf6x6WV2kOLDHWuBCvgr^e7e~7=ST-k%Une)7OaqpcN4X)z zdF|@sT;!{~v+i|XXv-HGe1-2~^rzkC&N0UEBw?Jk0xga)vGcMIK2izd_C-Seoi?Fs zT!}h>QZ8RiVoM~6jDlif8x2O3qm`?OUfpbZCyTaNArC``edofwwPXXbu2b@f9x#Qv zL)GV(uhS$lTZ<3sMm14G9ZB#nHGKCp3~X5;5=M`n+>FfWN@QyH#aa;+qg90r=yyR#E6|x7$Z#!_aD7R ztLs*DbfqGddTlIv^Cic{n>D#|=2JBDn{o_iu;`e=B!^Pbe1^WwL{%O|r`<+EF9o?9 z0#+}0nPjO~>)yWG>%Da6;>8;`Zq$%0L$^vhIr&gVZYg)=(%OoO_6g#3cbD^({2LXN z;Zt#7y?6W8_D;Q-PP80(D?)oCym#GLuDnNPOU6T*als=Fe8v|rn z+1h+GWDt!j{FWT4Nb*3AL>8u4a41}$g!htd8 4: + ibuffer = 1 + + shutterCounter+=1 + + # Only contains valVectors: + counterArray.append(MAPSACounter) + memoryArray.append(MAPSAMemory) + print "Shutter counter: %s Free buffers: %s " %(shutterCounter, freeBuffers) + + if shutterCounter > 1: + break + +except KeyboardInterrupt: + pass + +finally: + print "Turning off continous datataking" + glib.getNode("Control").getNode('Sequencer').getNode('datataking_continuous').write(0) + glib.dispatch() + #glib.getNode("Configuration").getNode("mode").write(len(assembly) - 1) # This is a 'write' and pushes the configuration to the glib. Write must happen before starting the sequencer. + #conf[0].spi_wait() # includes dispatch + + for endBuffer in range(0,2): # Read remaining two buffer + freeBuffers = glib.getNode("Control").getNode('Sequencer').getNode('buffers_num').read() + glib.dispatch() + MAPSACounter = [] + MAPSAMemory = [] + for iMPA, nMPA in enumerate(assembly): + counterData = glib.getNode("Readout").getNode("Counter").getNode("MPA"+str(iMPA + 1)).getNode("buffer_"+str(ibuffer)).readBlock(25) + memoryData = glib.getNode("Readout").getNode("Memory").getNode("MPA"+str(nMPA)).getNode("buffer_"+str(ibuffer)).readBlock(216) + glib.dispatch() + + print "Buffer: %s iMPA: %s nMPA: %s" %(ibuffer, iMPA, nMPA) + print counterData + #print memoryData + + MAPSACounter.append(counterData.value()) + MAPSAMemory.append(memoryData.value()) + + shutterCounter += 1 + ibuffer += 1 + if ibuffer > 4: + ibuffer = 1 + + # Only contains valVectors: + counterArray.append(MAPSACounter) + memoryArray.append(MAPSAMemory) + print "Shutter counter: %s Buffers num: %s " %(shutterCounter, freeBuffers) + +freeBuffers = glib.getNode("Control").getNode('Sequencer').getNode('buffers_num').read() +lastBuffer = glib.getNode("Control").getNode('Sequencer').getNode('buffers_index').read() +glib.dispatch() +print freeBuffers +print lastBuffer + 1 +print len(counterArray) + + +nHitMax = 95 +nPixMax = 48 +nMPA = 2 + +############### + +counter = 0 + +buffTest = counterArray[:4] +cycleIndex = 0 + +for k in range(len(counterArray)/4): + for i, buff in enumerate(buffTest): + if cycleIndex == k: + continue + if buff == counterArray[k*4+i]: + print "Error, buffer %s from cycle %s and cycle %s are the same" %(i, cycleIndex, k) + print counterArray[k*4+i] + else: + buff = counterArray[k*4+i] + cycleIndex = k + diff --git a/daq/daq_continuous_2MPA.py b/daq/daq_continuous_2MPA.py new file mode 100644 index 0000000..3994a29 --- /dev/null +++ b/daq/daq_continuous_2MPA.py @@ -0,0 +1,268 @@ +import sys +import os +from classes import * +from array import array +from ROOT import TGraph, TCanvas, TLine, TTree, TFile +import time + +assembly = [2,5] + +# Connection and GLIB +a = uasic(connection="file://connections_test.xml",device="board0") +glib = a._hw + +# Enable clock on MPA +glib.getNode("Control").getNode("MPA_clock_enable").write(0x1) +glib.dispatch() + +# Reset all logic on GLIB +glib.getNode("Control").getNode("logic_reset").write(0x1) +glib.dispatch() + +# Source all classes +mapsaClasses = MAPSA(a) + +conf = [] +mpa = [] +for iMPA, nMPA in enumerate(assembly): + mpa.append(MPA(glib, iMPA+1)) # List of instances of MPA, one for each MPA. SPI-chain numbering! + #conf.append(mpa[iMPA].config("data/Conf_trimcalib_MPA" + str(nMPA)+ "_masked.xml")) # Use trimcalibrated config + conf.append(mpa[iMPA].config("data/Conf_default_MPA" + str(nMPA)+ "_config1.xml")) + +threshold = 100 +print "Threshold:", threshold + +# Define default config +for iMPA in range(0,len(assembly)): + conf[iMPA].modifyperiphery('THDAC',threshold) # Write threshold to MPA 'iMPA' + conf[iMPA].modifypixel(range(1,25), 'SR', 1) # Enable synchronous readout on all pixels + conf[iMPA].upload() # Push configuration to GLIB +glib.getNode("Configuration").getNode("mode").write(len(assembly) - 1) +conf[iMPA].spi_wait() # includes dispatch + +glib.getNode("Configuration").getNode("num_MPA").write(len(assembly)) +glib.getNode("Configuration").getNode("mode").write(len(assembly) - 1) # This is a 'write' and pushes the configuration to the glib. Write must happen before starting the sequencer. +conf[0].spi_wait() # includes dispatch + +glib.getNode("Control").getNode('testbeam_clock').write(0x0) # Enable external clock +#glib.getNode("Control").getNode('testbeam_clock').write(0x1) # Enable external clock +glib.getNode("Configuration").getNode("mode").write(len(assembly) - 1) +glib.dispatch() + +#shutterDur = 0xFFFFFFFF #0xFFFFFFFF is maximum, in clock cycles +shutterDur = 0xFFFFFF #0xFFFFFFFF is maximum, in clock cycles +mapsaClasses.daq().Sequencer_init(0x1,shutterDur, mem=1) # Start sequencer in continous daq mode. Already contains the 'write' + +ibuffer = 1 +shutterCounter = 0 +counterArray = [] +memoryArray = [] +frequency = "Wait" + +triggerStop = 500000 + +try: + while True: + freeBuffers = glib.getNode("Control").getNode('Sequencer').getNode('buffers_num').read() + glib.dispatch() + + if freeBuffers < 3: # When set to 4 this produces duplicate entries, 3 (= 2 full buffers) avoids this. + + if shutterCounter%2000 == 0: + startTime = time.time() + shutterTimeStart = shutterCounter + + if shutterCounter%100 == 0 and (shutterCounter - shutterTimeStart) >= 0.1: + frequency = (shutterCounter - shutterTimeStart)/(time.time() - startTime) + + + MAPSACounter = [] + MAPSAMemory = [] + for iMPA, nMPA in enumerate(assembly): + counterData = glib.getNode("Readout").getNode("Counter").getNode("MPA"+str(iMPA + 1)).getNode("buffer_"+str(ibuffer)).readBlock(25) + memoryData = glib.getNode("Readout").getNode("Memory").getNode("MPA"+str(nMPA)).getNode("buffer_"+str(ibuffer)).readBlock(216) + glib.dispatch() + + #print "Buffer: %s iMPA: %s nMPA: %s" %(ibuffer, iMPA, nMPA) + #print counterData + #print '{0:032b}'.format(counterData[0]) + #print memoryData + #print "\n" + + MAPSACounter.append(counterData) + MAPSAMemory.append(memoryData) + + ibuffer += 1 + if ibuffer > 4: + ibuffer = 1 + + shutterCounter+=1 + + # Only contains valVectors: + counterArray.append(MAPSACounter) + memoryArray.append(MAPSAMemory) + print "Shutter counter: %s Free buffers: %s Frequency: %s " %(shutterCounter, freeBuffers, frequency) + + + ############## Continuous operation in bash loop + + if shutterCounter == triggerStop: + endTimeStamp = time.time() + if shutterCounter > triggerStop: + if time.time() - endTimeStamp > 2: + break + + +except KeyboardInterrupt: + pass + +#finally: +# while ibuffer <= 4: +# +# freeBuffers = glib.getNode("Control").getNode('Sequencer').getNode('buffers_num').read() +# glib.dispatch() +# if freeBuffers < 3: +# MAPSACounter = [] +# MAPSAMemory = [] +# for iMPA, nMPA in enumerate(assembly): +# counterData = glib.getNode("Readout").getNode("Counter").getNode("MPA"+str(iMPA + 1)).getNode("buffer_"+str(ibuffer)).readBlock(25) +# memoryData = glib.getNode("Readout").getNode("Memory").getNode("MPA"+str(nMPA)).getNode("buffer_"+str(ibuffer)).readBlock(216) +# glib.dispatch() +# +# MAPSACounter.append(counterData) +# MAPSAMemory.append(memoryData) +# +# shutterCounter += 1 +# ibuffer += 1 +# +# # Only contains valVectors: +# counterArray.append(MAPSACounter) +# memoryArray.append(MAPSAMemory) +# print "Shutter counter: %s Buffers num: %s " %(shutterCounter, freeBuffers) +# + +runNumber = 0 +runNumberFile = '/home/readout/TBdata/currentRun.txt' + +with open(runNumberFile,'r') as runFile: + runNumber = int(runFile.read()) + +with open(runNumberFile,'w') as newRunFile: + newRunFile.write(str(runNumber+1)) + + +print "End of Run %s" %runNumber + +memoryFile = open('/home/readout/TBdata/run%s_memory.txt' %('{0:04d}'.format(runNumber)), 'w') +counterFile = open('/home/readout/TBdata/run%s_counter.txt' %('{0:04d}'.format(runNumber)), 'w') + +for i, shutter in enumerate(counterArray): + for j,mpa in enumerate(shutter): + counterFile.write(str(mpa.value())+"\n") + memoryFile.write(str(memoryArray[i][j].value())+"\n") + +counterFile.close() +memoryFile.close() + + +print "All files saved" + + +# nHitMax = 95 +# nPixMax = 48 +# nMPA = 2 + +# # Create File + +# tFile = TFile("output.root","RECREATE") + +# # Initialize trees + +# treeMPA1 = TTree("MPA1","MPA1 event tree") +# treeMPA2 = TTree("MPA2","MPA2 event tree") + +# nEvents = [array('i',[0]) for x in range(0,nMPA)] +# nHits = [array('i',[0]) for x in range(0,nMPA)] +# headerArray = [array('i',[0 for x in range(0,nHitMax)]) for x in range(0,nMPA)] +# bxArray = [array('i',[0 for x in range(0,nHitMax)]) for x in range(0,nMPA)] +# hitArrayMemory = [array('i',[0 for x in range(0,nPixMax)]) for x in range(0,nMPA)] +# hitArrayCounter = [array('i',[0 for x in range(0,nPixMax)]) for x in range(0,nMPA)] + + +# print("Hd: %s" %len(headerArray[0])) +# print("Bx: %s" %len(bxArray[0])) +# print("Px: %s" %len(hitArrayMemory[0])) + +# treeMPA1.Branch("nEvents", nEvents[0], "nEvents/I") +# treeMPA1.Branch("nHits", nHits[0], "nHits/I") +# treeMPA1.Branch("header", headerArray[0], "header[nHits]/I") +# treeMPA1.Branch("bx", bxArray[0], "bx[nHits]/I") +# treeMPA1.Branch("pixelHits", hitArrayMemory[0], "pixelHits[nHits]/I") +# treeMPA1.Branch("pixelCounter",hitArrayCounter[0],"pixelCounter[nHits]/I") + +# treeMPA2.Branch("nEvents", nEvents[1], "nEvents/I") +# treeMPA2.Branch("nHits", nHits[1], "nHits/I") +# treeMPA2.Branch("header", headerArray[1], "header[nHits]/I") +# treeMPA2.Branch("bx", bxArray[1], "bx[nHits]/I") +# treeMPA2.Branch("pixelHits", hitArrayMemory[1], "pixelHits[nHits]/I") +# treeMPA2.Branch("pixelCounter",hitArrayCounter[1],"pixelCounter[nHits]/I") + +# ############### + +# counter = 0 + +# for k, event in enumerate(memoryArray): +# for i,mpa in enumerate(event): + +# ############################################# +# ### Counter: Array[24] -> Array[48] (int) ### +# ############################################# +# counterData = [] + +# for x in range(1,len(counterArray[k][i])): # Skip header at [0] +# counterData.append(counterArray[k][i][x] & 0x7FFF) # Mask to select left pixel. First bit is not considered as this seems sometimes to be set erronously. (Lots of entries with 0b1000000000000000) +# counterData.append((counterArray[k][i][x] >> 16) & 0x7FFF) # Mask to select right pixel. Same as above. + +# ########################################################################################## +# ### Memory: 216x 32-Bit Words -> Array of Hits (Header,BunchCrossing,Pixarray) (Bits) ### +# ########################################################################################## + +# # Mem integer array to binary string in readable order (header,bx,pix) +# binMemStr= "" +# for j in range(0,216): +# binMemStr = binMemStr + '{0:032b}'.format(mpa[215-j]) + +# # String to binary array +# binMem = [binMemStr[x:x+72] for x in range(0,len(binMemStr),72)] + +# # Get elements of binary string +# hd = [] +# bx = [] +# pix = [] + +# for entry in binMem[:-1]: # Discard last entry in memory as here the 48th - pixel is always showing a hit, even if pixel is disabled. This is intended as a workaround, the maximum number of hits per pixel and memory is now 95. +# hd.append(entry[:8]) +# bx.append(entry[8:24]) +# pix.append(entry[24:]) + +# ##################################################################### + +# # Tree stuff + +# nHitsTmp = 0 +# for hit in hd: +# if hit == "11111111": +# nHitsTmp+=1 + +# nHits[i][0] = 95 +# headerArray[i]=[int(ihd,2) for ihd in hd] +# bxArray[i]=[int(ibx,2) for ibx in bx] +# hitArrayMemory[i]=pix +# hitArrayCounter[i]=counterData + + +# treeMPA1.Fill() +# treeMPA2.Fill() + +# tFile.Write() +# tFile.Close() diff --git a/daq/daq_counter_2MPA.py b/daq/daq_counter_2MPA.py new file mode 100644 index 0000000..aa9efad --- /dev/null +++ b/daq/daq_counter_2MPA.py @@ -0,0 +1,134 @@ +import sys +from classes import * +from array import array +from optparse import OptionParser +from ROOT import TGraph, TCanvas, TLine + +# Connection and GLIB +a = uasic(connection="file://connections_test.xml",device="board0") +glib = a._hw + +# Get all 6 MPAs and corresponding configs +mpa=[] +conf=[] + +for i in range(0,6): + mpa.append(MPA(glib,i+1)) + conf.append(mpa[i].config("data/Default_MPA.xml")) + +# Define MPA (1-6) (iMPA 2 or 5 for double assembly) + +mpaDict = {0:2,1:5} + +iMPA = 0 # Zero-indexed (from 0 to 5 on full assembly) + +# Set voltage steps of threshold DAC and trimming DAC (in mV/Step) +thrVoltStep = 1.456 +trimVoltStep = 3.75 + +# Modify config + +glib.getNode("Control").getNode("MPA_clock_enable").write(0x1) +glib.dispatch() +glib.getNode("Configuration").getNode("num_MPA").write(0x2) + +# Define default config +threshold = 70 + +## Load trimDac config +trimDac = open('trimDac_MPA'+str(iMPA+1)).read().splitlines() # Open file with trimDac values for MPA +trimDac = [int(pxl) for pxl in trimDac] + + +shutterDur = 0xFF #0xFFFF is maximum, in clock cycles + +defaultPixelCfg = {'PML':1,'ARL':1,'CEL':0,'CW':0,'PMR':1,'ARR':1,'CER':0,'SP':0,'SR':1,'TRIMDACL':30,'TRIMDACR':30} +defaultPeripheryCfg = {'OM':3,'RT':0,'SCW':0,'SH2':0,'SH1':0,'THDAC':threshold,'CALDAC':30} + + +# Upload +for key in defaultPeripheryCfg: + conf[iMPA].modifyperiphery(key,defaultPeripheryCfg[key]) +for pix in range(0,24): + for key in defaultPixelCfg: + conf[iMPA].modifypixel(pix + 1,key,defaultPixelCfg[key]) + + +# Write trimDac values to MPA +for pix in range(0,24): + conf[iMPA].modifypixel(pix + 1,'TRIMDACL',trimDac[2*pix]) + conf[iMPA].modifypixel(pix + 1,'TRIMDACR',trimDac[2*pix + 1]) + +conf[iMPA].upload() +glib.getNode("Configuration").getNode("mode").write(0x1) +glib.dispatch() + + +# Write twice to push config to Memory_OutConf to check what has been written +glib.getNode("Configuration").getNode("mode").write(0x1) +conf[iMPA].spi_wait() + +outConf = glib.getNode("Configuration").getNode("Memory_OutConf").getNode("MPA"+str(iMPA + 1)).getNode("config_1").readBlock(0x19) # Get written config +glib.dispatch() +readconf = [] +for pix in outConf: # Format this config to extract trimDac values +# print '{0:020b}'.format(pix) + readconf.append((pix >> 2) & 0b11111) + readconf.append((pix >> 12) & 0b11111) + +print "Written Trim DAC: %s" %readconf[2:] # Skip periphery config (first two entries) + +hitArrayCounter = [] +sumArray = [] +for i in range(0,500000): + ########################## + ### Begin of sequencer ### + ########################## + + # Set shutter duration + glib.getNode("Shutter").getNode("time").write(shutterDur) + + # Opens shutter (mode = 0x0 single shutter, 0x1 four (buffers) consequitive shutter) + glib.getNode("Control").getNode("Sequencer").getNode('datataking_continuous').write(0) + + # Write in first buffer (default and therefore not necessary to be defined) + #glib.getNode("Control").getNode("Sequencer").getNode('buffers_index').write(0) + + # Readout has to be enabled in order to get the data + glib.getNode("Control").getNode("readout").write(1) + conf[iMPA].spi_wait() + + + ######################## + ### End of sequencer ### + ######################## + counter = glib.getNode("Readout").getNode("Counter").getNode("MPA"+str(iMPA + 1)).getNode("buffer_1").readBlock(25) + glib.dispatch() + + counterArray = [] + for x in range(1,len(counter)): # Skip header at [0] + counterArray.append(counter[x] & 0xFFFF) # Mask to select left pixel + counterArray.append((counter[x] >> 16) & 0xFFFF) # Mask to select right pixel + counterArray = [pix if pix < 20000 else 0 for pix in counterArray] + hitArrayCounter.append(counterArray) + sumArray.append(sum(counterArray)) + #time.sleep(0.5) # If this is not here strange values appear in array, maybe GLIB isn't ready + + +#################### +### Analyse hits ### +#################### + + +# Sum over all loops for each pixel +sumPixArray = hitArrayCounter[1] +for i in range(1,len(hitArrayCounter)): + for j in range(len(hitArrayCounter[i])): + sumPixArray[j] += hitArrayCounter[i][j] + +shutterDurInSeconds = shutterDur*len(hitArrayCounter) * 1/(160e6) # For frequency of hits + +print hitArrayCounter +print "Hits for each pixel, summed over %s readout cycles: %s \n" %(len(hitArrayCounter), sumPixArray) +print "Average hits for all pixels: %s Total readout time: %s seconds \n" %((sum(sumPixArray)/len(sumPixArray)), shutterDurInSeconds) +print "Frequency of hits: %s" %(sum(sumArray)/shutterDurInSeconds) diff --git a/daq/daq_counter_2MPA_xray.py b/daq/daq_counter_2MPA_xray.py new file mode 100644 index 0000000..efad6c9 --- /dev/null +++ b/daq/daq_counter_2MPA_xray.py @@ -0,0 +1,97 @@ +import sys +import time +from array import array +from MPACalibration import MPACalibration +from MPAPlot import MPAPlot + +#iMPA = 1 # Only do this for MPA 5, the 2nd MPA in the SPI-chain (0-indexed) +#MPANum = 4 # 0-indexed absolute number of MPA 5 + +hitFile = open('data/synchronous_data_xray', 'a') + +# Calibrate MPA (only use MPA 5 as it has confirmed failed bonds) +calibration = MPACalibration([2,5]) # Argument reflects assembly which is actually on board +calibration.thresholdScan(calEnbl = 1) +calibration.writeCalibrationToMPA() + +# Take connection, GLIB and MPA from calibration +glib = calibration._glib +mapsaClasses = calibration._mapsaClasses + +mpa = calibration._mpa +conf = calibration._conf + +# Define default config +calibration.thresholdScan() + +counter, _ = calibration.getThrScanPerPix() +_,_,thresholds = calibration.getThrScanMetadata() + +for iMPA in range(0,2): + plot = MPAPlot() + for pix in counter[iMPA]: + plot.createGraph(thresholds[iMPA], pix) + #plot.draw() + + #threshold = input("Which global threshold should be set?") + threshold = 150 + calibration._conf[iMPA].modifyperiphery('THDAC',threshold) # Write threshold to MPA 'iMPA' + calibration._conf[iMPA].upload() + calibration._glib.getNode("Configuration").getNode("mode").write(calibration._nMPA - 1) + calibration._conf[iMPA].spi_wait() # includes dispatch + +shutterDur = 0xFFFFF #0xFFFFFFFF is maximum, in clock cycles + +eventArray = [] +bxArray = [] + +raw_input("SHUTTER!!???") +hitArrayCounter = [] +for i in range(0,100): + ########################## + ### Begin of sequencer ### + ########################## + + mapsaClasses.daq().Sequencer_init(0, shutterDur) + mpaArrayCounter = [] + for iMPA in range(0,2): + + counter = glib.getNode("Readout").getNode("Counter").getNode("MPA"+str(iMPA + 1)).getNode("buffer_1").readBlock(25) + glib.dispatch() + + counterArray = [] + for x in range(1,len(counter)): # Skip header at [0] + counterArray.append(counter[x] & 0x7FFF) # Mask to select left pixel + counterArray.append((counter[x] >> 16) & 0x7FFF) # Mask to select right pixel + mpaArrayCounter.append(counterArray) + + hitArrayCounter.append(mpaArrayCounter) + time.sleep(0.1) + +mpaRunPix = [list(run) for run in zip(*hitArrayCounter)] # MPA[Run[Pix]] (swap highest and second-highest order of nesting) + +mpaSumRun = [] +for mpa in mpaRunPix: + sumRun = [0]*48 + for run in mpa: + for i,pix in enumerate(run): + sumRun[i] += pix + mpaSumRun.append(sumRun) + +mpaTotal = [] +for mpa in mpaSumRun: + mpaTotal.append(sum(mpa)) + plot = MPAPlot() + plot.createHitMap(mpa) + plot.draw() + +shutterDurInSeconds = shutterDur*len(hitArrayCounter) * 1/(160e6) # For frequency of hits + +frequency = sum(mpaTotal)/shutterDurInSeconds +print "Total number of hits: %s" %sum(mpaTotal) +#print "Hits for each pixel, summed over %s readout cycles: %s \n" %(len(hitArrayCounter), sumPixArray) +print "Total readout time: %s seconds \n" %shutterDurInSeconds +print "Frequency of hits: %s" %(sum(mpaTotal)/shutterDurInSeconds) + +hitFile.write(str(frequency)+'\n') +hitFile.close() diff --git a/daq/daq_memory_2MPA.py b/daq/daq_memory_2MPA.py new file mode 100644 index 0000000..e291777 --- /dev/null +++ b/daq/daq_memory_2MPA.py @@ -0,0 +1,104 @@ +import sys +from classes import * +from array import array +from optparse import OptionParser +from ROOT import TGraph, TCanvas, TLine +from MPACalibration import MPACalibration + +iMPA = 1 # Only do this for MPA 5, the 2nd MPA in the SPI-chain (0-indexed) +MPANum = 4 # 0-indexed absolute number of MPA 5 + +hitFile = open('data/synchronous_data_noise_MPA'+str(MPANum+1),'w') + +# Calibrate MPA (only use MPA 5 as it has confirmed failed bonds) +calibration = MPACalibration([2,5]) # Argument reflects assembly which is actually on board +calibration.thresholdScan(MAPSA = 5, calEnbl = 1) +calibration.writeCalibrationToMPA() + +# Take connection, GLIB and MPA from calibration +glib = calibration._glib +mapsaClasses = calibration._mapsaClasses + +conf = [] +mpa = [] +for i in range(0,6): + mpa.append(MPA(glib,i+1)) # List of instances of MPA, one for each MPA + conf.append(mpa[i].config("data/Default_MPA.xml")) + +# Define default config +calibration.thresholdScan(MAPSA=5) +edges = calibration.findFallingEdges()[-1] #Get edges for the last MPA in the chain +edges.sort() +length = len(edges) +threshold = (edges[length/2] + edges[(length+1)/2])/2 # Set global threshold at median of falling edges +calibration._conf[iMPA].modifyperiphery('THDAC',threshold) # Write threshold to MPA 'iMPA' +calibration._conf[iMPA].upload() +calibration._glib.getNode("Configuration").getNode("mode").write(calibration._nMPA - 1) +calibration._conf[iMPA].spi_wait() # includes dispatch + +shutterDur = 0xFFF #0xFFFF is maximum, in clock cycles + +eventArray = [] +bxArray = [] +hitArrayMemory = [] +for i in range(0,1000): + ########################## + ### Begin of sequencer ### + ########################## + mapsaClasses.daq().Sequencer_init(0, shutterDur ) + + ######################## + ### End of sequencer ### + ######################## + + # Readout buffer (TRUE / FALSE : Wait for sequencer) with absolute MPA-values + mem = mpa[MPANum].daq().read_raw(1,1,True)[0] + + # Mem integer array to binary string in readable order (header,bx,pix) + binMemStr= "" + for i in range(0,216): + binMemStr = binMemStr + '{0:032b}'.format(mem[215-i]) + + # String to binary array + binMem = [binMemStr[x:x+72] for x in range(0,len(binMemStr),72)] + + # Get elements of binary string + hd = [] + bx = [] + hits = [] + for entry in binMem: + hd.append(entry[0:8]) + bx.append(entry[8:24]) + hits.append(entry[24:72]) + + # Put event string into lists, one entry per pixel + hitArrayRun = [] + for event in hits: + hitArrayEvent = [] + for pix in event: + hitArrayEvent.append(int(pix)) + hitArrayRun.append(hitArrayEvent) + + # Count number of Events + nEvents = 0 + for event in hd: + if event == "11111111": + nEvents+=1 + + # bunch crossing from binary to int + bx=[int(ibx,2) for ibx in bx] + + eventArray.append(nEvents) + bxArray.append(bx) + hitArrayMemory.append(hitArrayRun) + + for hit in hits: + hitFile.write(hit) + hitFile.write('\n') + hitFile.write('\n') + + time.sleep(0.1) # If this is not here strange values appear in array, maybe GLIB isn't ready + +hitFile.close() +print sum(eventArray)/len(eventArray) + diff --git a/daq/daq_shuttertest_2MPA.py b/daq/daq_shuttertest_2MPA.py new file mode 100644 index 0000000..9a463e9 --- /dev/null +++ b/daq/daq_shuttertest_2MPA.py @@ -0,0 +1,173 @@ +import sys +import numpy as np +from classes import * +from array import array +from optparse import OptionParser +from ROOT import TGraph, TCanvas, TLine, TTree, TFile +from MPACalibration import MPACalibration + +assembly = [2,5] + +# Connection and GLIB +a = uasic(connection="file://connections_test.xml",device="board0") +glib = a._hw + +# Source all classes +mapsaClasses = MAPSA(a) + +conf = [] +mpa = [] +for iMPA, nMPA in enumerate(assembly): + mpa.append(MPA(glib, nMPA)) # List of instances of MPA, one for each MPA + conf.append(mpa[iMPA].config("data/Conf_trimcalib_MPA" + str(nMPA)+ "_config1.xml")) # Use trimcalibrated config + +threshold = 120 + +# Define default config +for iMPA in range(len(assembly)): + conf[iMPA].modifyperiphery('THDAC',threshold) # Write threshold to MPA 'iMPA' + conf[iMPA].upload() + glib.getNode("Configuration").getNode("mode").write(nMPA - 1) + conf[iMPA].spi_wait() # includes dispatch + + +glib.getNode("Control").getNode('testbeam_clock').write(0x1) # Enable external clock +glib.dispatch() + + +shutterDur = 0xFFFFFFFF #0xFFFFFFFF is maximum, in clock cycles +mapsaClasses.daq().Sequencer_init(0x1,shutterDur, mem=1) # Start sequencer in continous daq mode + +ibuffer = 1 +shutterCounter = 0 +counterArray = [] +memoryArray = [] +try: + while True: + + freeBuffers = glib.getNode("Control").getNode('Sequencer').getNode('buffers_num').read() + glib.dispatch() + if freeBuffers < 4: + MAPSACounter = [] + MAPSAMemory = [] + for iMPA, MPA in enumerate(assembly): + counterData = glib.getNode("Readout").getNode("Counter").getNode("MPA"+str(MPA)).getNode("buffer_"+str(ibuffer)).readBlock(25) + memoryData = glib.getNode("Readout").getNode("Memory").getNode("MPA"+str(MPA)).getNode("buffer_"+str(ibuffer)).readBlock(216) + + MAPSACounter.append(counterData) + MAPSAMemory.append(memoryData) + glib.dispatch() + + shutterCounter += 1 + ibuffer += 1 + if ibuffer > 4: + ibuffer = 1 + + # Only contains valVectors: + counterArray.append(MAPSACounter) + memoryArray.append(MAPSAMemory) + print "Shutter counter: %s Buffers num: %s " %(shutterCounter, freeBuffers) + + # if shutterCounter > 1: + # print shutterCounter + # break +except KeyboardInterrupt: + + print len(counterArray) + print len(memoryArray) + + ttree = TTree("Events","MPA event tree") + + eventArray = np.array([0]) + bxArray = np.array([0]) + hitArrayMemory = np.array([0]) + hitArrayCounter = np.array([0]) + iMPA = np.array([0]) + headerArray = np.array([0]) + nHits = np.array([0]) + + ttree.Branch("header", headerArray, "header/I") + ttree.Branch("bx", bxArray, "bx/I") + ttree.Branch("pixelHits", hitArrayMemory, "pixelHits/I") + ttree.Branch("mpa", impa, "mpa/I") + ttree.Branch("nHits", nHits, "nHits/I") + + for event in memoryArray: + for i,mpa in enumerate(event): + + iMPA[0] = assembly[i] + + # Mem integer array to binary string in readable order (header,bx,pix) + binMemStr= "" + for i in range(0,216): + binMemStr = binMemStr + '{0:032b}'.format(mem[215-i]) + + # String to binary array + binMem = [binMemStr[x:x+72] for x in range(0,len(binMemStr),72)] + + # Get elements of binary string + hd = np.array() + bx = np.array() + pix = np.array() + + for entry in binMem[:-1]: # Discard last entry in memory as here the 48th - pixel is always showing a hit, even if pixel is disabled. This is intended as a workaround, the maximum number of hits per pixel and memory is now 95. + hd.append(entry[:8]) + bx.append(entry[8:24]) + pix.append(entry[24:]) + + headerArray[0]=[int(ihd,2) for ihd in hd] + bxArray[0]=[int(ibx,2) for ibx in bx] + + i+=1 + + #memoryArrayMAPSA = [list(mpa) for mpa in zip(*memoryArray)] # Switch hierarchy so that Shutter[MPA[Mem]] becomes MPA[Shutter[Mem]] + + #for mpa in memoryArrayMAPSA: + # for run in mpa: + # hitArrayShutter = [] + # for mem in run: + # ## Mem integer array to binary string in readable order (header,bx,pix) + # binMemStr= "" + # for i in range(0,216): + # binMemStr = binMemStr + '{0:032b}'.format(mem[215-i]) + + # # String to binary array + # binMem = [binMemStr[x:x+72] for x in range(0,len(binMemStr),72)] + + # # Get elements of binary string + # hd = [] + # bx = [] + # pix = [] + # + # for entry in binMem[:-1]: # Discard last entry in memory as here the 48th - pixel is always showing a hit, even if pixel is disabled. This is intended as a workaround, the maximum number of hits per pixel and memory is now 95. + # hd.append(entry[:8]) + # bx.append(entry[8:24]) + # pix.append(entry[24:]) + + # # Put event string into lists, one entry per pixel + # hitArrayShutter = [] + # for event in hits: + # hitArrayEvent = [] + # for pix in event: + # hitArrayEvent.append(int(pix)) + # hitArrayShutter.append(hitArrayEvent) + + # # Count number of Events + # nHitss = 0 + # for hit in hd: + # if hit == "11111111": + # nHits+=1 + + # # bunch crossing from binary to int + # bx=[int(ibx,2) for ibx in bx] + + # hitNumberArray.append(nHits) + # bxArray.append(bx) + # hitArrayMemory.append(hitArrayShutter) + # + + #for mpa in counterArray: + # for counter in mpa: + + # pix.append(entry[24:40]+ "".join(reversed([entry[40:56][i:i+2] for i in range(0, 16, 2)])) + entry[56:]) # Row 2 is numbered from right to left while Rows 1 and 3 are numbered left-to-right. Therefore middle of array must be reversed in blocks of 2 + diff --git a/daq/hits_MPA5 b/daq/hits_MPA5 new file mode 100644 index 0000000..6509405 --- /dev/null +++ b/daq/hits_MPA5 @@ -0,0 +1,3 @@ + +MPA5 hits with Sr90 source: +hits = [24535, 15100, 16743, 14068, 17042, 14568, 22333, 17551, 0, 19322, 0, 19147, 0, 0, 19984, 24712, 24401, 15963, 15078, 16422, 13774, 14310, 13577, 15085, 11354, 14313, 13706, 14324, 12457, 14413, 14432, 23665, 24579, 12675, 13340, 12612, 15251, 10976, 15562, 0, 16572, 0, 16463, 13214, 15304, 13793, 15967, 24799] diff --git a/daq/test_custom_register.py b/daq/test_custom_register.py new file mode 100644 index 0000000..e1eea07 --- /dev/null +++ b/daq/test_custom_register.py @@ -0,0 +1,48 @@ +import sys +from classes import * +from array import array +from optparse import OptionParser +from ROOT import TGraph, TCanvas, TLine, TTree, TFile +from MPACalibration import MPACalibration +import time + +assembly = [2,5] + +# Connection and GLIB +a = uasic(connection="file://connections_test.xml",device="board0") +glib = a._hw + +# Source all classes +mapsaClasses = MAPSA(a) + +conf = [] +mpa = [] +for iMPA, nMPA in enumerate(assembly): + mpa.append(MPA(glib, nMPA)) # List of instances of MPA, one for each MPA +# conf.append(mpa[iMPA].config("data/Conf_trimcalib_MPA" + str(nMPA)+ "_config1.xml")) # Use trimcalibrated config + conf.append(mpa[iMPA].config("data/Conf_default_MPA" + str(nMPA)+ "_config1.xml")) + + +threshold = 70 + +# Define default config +for iMPA in range(len(assembly)): + conf[iMPA].modifyperiphery('THDAC',threshold) # Write threshold to MPA 'iMPA' + conf[iMPA].upload() + glib.getNode("Configuration").getNode("mode").write(nMPA - 1) + conf[iMPA].spi_wait() # includes dispatch + + +glib.getNode("Control").getNode('testbeam_clock').write(0x1) # Enable external clock +glib.dispatch() + +r = glib.getNode("Custom").getNode("tel_busy_enable").read() +glib.dispatch() +print(r) +glib.getNode("Custom").getNode("tel_busy_enable").write(0x1) +glib.dispatch() +r = glib.getNode("Custom").getNode("tel_busy_enable").read() +glib.dispatch() +print(r) +sys.exit(0) + diff --git a/data/Conf_default_MPA1_config1.xml b/data/Conf_default_MPA1_config1.xml index af5ac25..cca0ed8 100644 --- a/data/Conf_default_MPA1_config1.xml +++ b/data/Conf_default_MPA1_config1.xml @@ -10,7 +10,7 @@ 33 - 1 + 0 1 15 1 diff --git a/data/Conf_default_MPA2_config1.xml b/data/Conf_default_MPA2_config1.xml index af5ac25..2ab7432 100644 --- a/data/Conf_default_MPA2_config1.xml +++ b/data/Conf_default_MPA2_config1.xml @@ -23,7 +23,7 @@ 0 - 1 + 0 1 15 1 diff --git a/fallingEdges_histogram.py b/fallingEdges_histogram.py new file mode 100644 index 0000000..d64ad98 --- /dev/null +++ b/fallingEdges_histogram.py @@ -0,0 +1,32 @@ +from ROOT import TCanvas, TH1F, gStyle, TAxis + +iMPA =1 + +gStyle.SetOptFit() + +# Load falling edges from threshold scan after trimming and convert to int +fallingEdges = open('data/fallingEdgeTrimmed_MPA'+str(iMPA+1)).read().splitlines() +fallingEdges = [int(edge) for edge in fallingEdges] + + +histData = [[edge,fallingEdges.count(edge)] for edge in set(fallingEdges)] # Calculate how often each number of hits occurs + +histo = TH1F("h1","Falling edges after trimming for MPA " +str(iMPA+1), max(fallingEdges), 0, max(fallingEdges)) +for threshold in histData: + for i in range(0,threshold[1]): + histo.Fill(threshold[0]) + +XRange = int(histo.GetMean() * 2) +histo.SetBins(XRange, 0, XRange) +histo.GetYaxis().SetTitle("Number of pixels") +histo.GetXaxis().SetTitle("Threshold value for falling edge") + +c1 = TCanvas("hist", "hist", 1024, 768) +c1.cd() + +# Gauss fit +fit = histo.Fit("gaus") +histo.Draw() + +c1.Print('plots/fallingEdgeHistogram_MPA'+str(iMPA+1)+'.pdf', 'pdf') +raw_input() diff --git a/findMPA.py b/findMPA.py new file mode 100644 index 0000000..c34971f --- /dev/null +++ b/findMPA.py @@ -0,0 +1,193 @@ +import sys +from classes import * +from array import array +from optparse import OptionParser +from ROOT import TGraph, TCanvas, TLine + +# Connection and GLIB +a = uasic(connection="file://connections_test.xml",device="board0") +glib = a._hw + +single = True + +# Get all 6 MPAs and corresponding configs +mpa=[] +conf=[] + +for i in range(0,6): + mpa.append(MPA(a._hw,i+1)) + conf.append(mpa[i].config("data/Default_MPA.xml")) + +# Define MPA (1-6) (nMPA 2 or 5 for double assembly) + +mpaDict = {0:2,1:5} +iMPA = 1 + +# Modify config + +glib.getNode("Control").getNode("MPA_clock_enable").write(0x1) +glib.dispatch() + +if single: + + glib.getNode("Configuration").getNode("num_MPA").write(0x2) + + # Define default config + defaultPixelCfg = {'PML':1,'ARL':1,'CEL':0,'CW':0,'PMR':1,'ARR':1,'CER':0,'SP':0,'SR':1,'TRIMDACL':30,'TRIMDACR':30} + defaultPeripheryCfg = {'OM':3,'RT':0,'SCW':0,'SH2':0,'SH1':0,'THDAC':0,'CALDAC':30} + + # Upload + for key in defaultPeripheryCfg: + conf[iMPA].modifyperiphery(key,defaultPeripheryCfg[key]) + for pix in range(0,24): + for key in defaultPixelCfg: + conf[iMPA].modifypixel(pix,key,defaultPixelCfg[key]) + + conf[iMPA].upload() + glib.getNode("Configuration").getNode("mode").write(0x1) + glib.dispatch() + +else: + + CE = 0 + + mapsa = MAPSA(a) + for i in range(1,7): + mpa.append(mapsa.getMPA(i)) + + config = mapsa.config(Config=1,string='default') + config.upload() + confdict = {'OM':[3]*6,'RT':[0]*6,'SCW':[0]*6,'SH2':[0]*6,'SH1':[0]*6,'THDAC':[0]*6,'CALDAC':[30]*6,'PML':[1]*6,'ARL':[1]*6,'CEL':[CE]*6,'CW':[0]*6,'PMR':[1]*6,'ARR':[1]*6,'CER':[CE]*6,'SP':[0]*6,'SR':[1]*6,'TRIMDACL':[30]*6,'TRIMDACR':[30]*6} + config.modifyfull(confdict) + + +eventArray = [] +hitArray = [] +thrArray = [] +bxArray = [] + + +# Start threshold scan +for thr in range(0,255): + + if thr%2 == 0: + print thr + + # Apply threshold + + if single: + conf[iMPA].modifyperiphery('THDAC',thr) + conf[iMPA].upload() + + glib.getNode("Configuration").getNode("mode").write(0x1) + conf[iMPA].spi_wait() + else: + config.modifyperiphery('THDAC',[thr]*6) + config.upload() + config.write() + + # Start acquisition (sequencer) + #mapsa.daq().Sequencer_init(options.continuous,options.shutterdur) + + ########################## + ### Begin of sequencer ### + ########################## + + # Set shutter duration + a._hw.getNode("Shutter").getNode("time").write(0xFFFF) + + # Opens shutter (mode = 0x0 single shutter, 0x1 four (buffers) consequitive shutter) + a._hw.getNode("Control").getNode("Sequencer").getNode('datataking_continuous').write(0) + + # Write in first buffer (default and therefore not necessary to be defined) + #a._hw.getNode("Control").getNode("Sequencer").getNode('buffers_index').write(0) + + # Readout has to be enabled in order to get the data + a._hw.getNode("Control").getNode("readout").write(1) + a._hw.dispatch() + + ######################## + ### End of sequencer ### + ######################## + + # Readout buffer (TRUE / FALSE : Wait for sequencer) + mem = mpa[mpaDict[iMPA]-1].daq().read_raw(1,1,True)[0] + + # Mem integer array to binary string in readable order (header,bx,pix) + binMemStr= "" + for i in range(0,216): + binMemStr = binMemStr + '{0:032b}'.format(mem[215-i]) + + # String to binary array + binMem = [binMemStr[x:x+72] for x in range(0,len(binMemStr),72)] + + # Get elements of binary string + hd = [] + bx = [] + pix = [] + for entry in binMem: + hd.append(entry[0:8]) + bx.append(entry[8:24]) + pix.append(entry[24:72]) + + # Count number of Events + nEvents = 0 + for event in hd: + if event == "11111111": + nEvents+=1 + + # Sum hits per pixel + sumPixHits = [0]*48 + for event in pix: + for i, ipix in enumerate(event): + sumPixHits[i]+=int(ipix) + + # bunch crossing from binary to int + bx=[int(ibx,2) for ibx in bx] + + eventArray.append(nEvents) + hitArray.append(sumPixHits) + thrArray.append(thr) + bxArray.append(bx) + + +print "---END OF SCAN---" + +for ithr in bxArray: + print max(ithr) + +# Generate new list [[pix1_ThScan],[pix2_ThScan],..] +pxlVsThr = [] +for ipix in range(0,len(hitArray[0])): + pxlVsThr.append([item[ipix] for item in hitArray]) + +# Generate graphs for each pixel +graphs = [] + +for ipixScan in pxlVsThr: + graphs.append(TGraph(len(thrArray),array('d',thrArray),array('d',ipixScan))) + +# Draw graphs on canvas +c1 = TCanvas("graph","graph",1024,768) +c1.cd() + +for i,graph in enumerate(graphs): + if i==0: + graph.SetTitle('Threshold Scan;Threshold (DAC);Number of Hits') + graph.GetYaxis().SetRangeUser(0,max(eventArray)*1.1) + graph.Draw("APL") + else: + graph.Draw("PL") + +# Add line for nMax +line = TLine(0,max(eventArray),graphs[0].GetXaxis().GetXmax(),max(eventArray)) +line.SetLineColor(2) +line.Draw() + +print "Max number of events during scan: %s" %max(eventArray) + +raw_input("Press any key to exit") + + + + diff --git a/findMPAnew.py b/findMPAnew.py new file mode 100644 index 0000000..b66f90f --- /dev/null +++ b/findMPAnew.py @@ -0,0 +1,127 @@ +import sys +from classes import * +from array import array +from optparse import OptionParser + +# Connection and GLIB +a = uasic(connection="file://connections_test.xml",device="board0") +glib = a._hw + +single = True + +# Get all 6 MPAs and corresponding configs +mpa=[] +conf=[] + +for i in range(0,6): + mpa.append(MPA(a._hw,i+1)) + conf.append(mpa[i].config("data/Conf_default_MPA" + str(i+1) +"_config1.xml")) + conf[i].clean_conf() + conf[i].upload(1) + glib.dispatch() + +#conf[confMPA-1].upload(1) +#glib.dispatch() + +# Define MPA (1-6) (nMPA 2 or 5 for double assembly) + +confMPA = 1 +#readMPA = +mode = 0x5 + +print 'confMPA' +print confMPA +#print 'readMPA' +#print readMPA +print 'Mode' +print mode + +glib.getNode("Control").getNode("logic_reset").write(0x1) +glib.dispatch() + +# Before write +dataConf = [] +for impa in range(1,7): + dataConf.append(glib.getNode("Configuration").getNode("Memory_DataConf").getNode("MPA"+str(impa)).getNode("config_1").readBlock(0x19)) + +glib.dispatch() + +print "\nDataConf before write: \n" +for impa in range(1,7): + print("MPA"+str(impa)+":\n %s" %dataConf[impa-1]) + +#a = glib.getNode("Configuration").getNode("Memory_DataConf").getNode("MPA"+str(readMPA)).getNode("config_1").readBlock(0x19) +#glib.dispatch() +#print("Dataconf:\n %s \n" %a) + +outConf = [] +for impa in range(1,7): + outConf.append(glib.getNode("Configuration").getNode("Memory_OutConf").getNode("MPA"+str(impa)).getNode("config_1").readBlock(0x19)) +glib.dispatch() + +print "\nOutConf before write\n" +for impa in range(1,7): + print("MPA"+str(impa)+":\n %s" %outConf[impa-1]) + +# WRITE Config +glib.getNode("Configuration").getNode("num_MPA").write(0x2) +glib.getNode("Configuration").getNode("mode").write(mode) +glib.dispatch() + +# Wait for SPI +busy = glib.getNode("Configuration").getNode("busy").read() +glib.dispatch() +while busy: + time.sleep(0.001) + busy = glib.getNode("Configuration").getNode("busy").read() + glib.dispatch() + +dataConf = [] +for impa in range(1,7): + dataConf.append(glib.getNode("Configuration").getNode("Memory_DataConf").getNode("MPA"+str(impa)).getNode("config_1").readBlock(0x19)) + +glib.dispatch() + +print "\nDataConf after write\n" +for impa in range(1,7): + print("MPA"+str(impa)+":\n %s" %dataConf[impa-1]) + +#a = glib.getNode("Configuration").getNode("Memory_DataConf").getNode("MPA"+str(readMPA)).getNode("config_1").readBlock(0x19) +#glib.dispatch() +#print("Dataconf:\n %s \n" %a) + +outConf = [] +for impa in range(1,7): + outConf.append(glib.getNode("Configuration").getNode("Memory_OutConf").getNode("MPA"+str(impa)).getNode("config_1").readBlock(0x19)) +glib.dispatch() + +print "\nOutConf after write\n" +for impa in range(1,7): + print("MPA"+str(impa)+":\n %s" %outConf[impa-1]) + +#b = glib.getNode("Configuration").getNode("Memory_OutConf").getNode("MPA"+str(readMPA)).getNode("config_1").readBlock(0x19) +#glib.dispatch() +#print("MemConf:\n %s \n" %b) + +print "\n" + +#conf[confMPA-1].upload(1) +#glib.dispatch() + + +# Wait for SPI +busy = glib.getNode("Configuration").getNode("busy").read() +glib.dispatch() +while busy: + time.sleep(0.001) + busy = glib.getNode("Configuration").getNode("busy").read() + glib.dispatch() + print busy + + +#c = glib.getNode("Configuration").getNode("Memory_OutConf").getNode("MPA"+str(readMPA)).getNode("config_1").readBlock(0x19) +#glib.dispatch() +#print("MemConf:\n %s \n" %c) + +raw_input("Press any key to exit") + diff --git a/manualBondTest.py b/manualBondTest.py new file mode 100644 index 0000000..d2ef3fd --- /dev/null +++ b/manualBondTest.py @@ -0,0 +1,57 @@ +from MPACalibration import MPACalibration +from MPAPlot import MPAPlot +from ROOT import TCanvas + +assembly = [2,5] + +calibration = MPACalibration(assembly) + +calibration.thresholdScan(calEnbl = 1) +calibration.writeCalibrationToMPA() + +fwhm = [] +raw_input("Please make sure HV is not connected to sensor") + +fwhm.append(calibration.voltTest()) + +raw_input("Please plug in HV now and set to specified voltage") +fwhm.append(calibration.voltTest()) + + +## Data from measurement with Sr90 source on MPA5 to allow comparison with confirmed dead pixels +hits = [24535, 15100, 16743, 14068, 17042, 14568, 22333, 17551, 0, 19322, 0, 19147, 0, 0, 19984, 24712, 24401, 15963, 15078, 16422, 13774, 14310, 13577, 15085, 11354, 14313, 13706, 14324, 12457, 14413, 14432, 23665, 24579, 12675, 13340, 12612, 15251, 10976, 15562, 0, 16572, 0, 16463, 13214, 15304, 13793, 15967, 24799] +colors = [1 if pix > 10 else 2 for pix in hits] + +fwhmMAPSA = [list(volt) for volt in zip(*fwhm)] + +fwhmPerVolt = [] +for mpa in fwhmMAPSA: + fwhmPerVolt.append([list(pix) for pix in zip(*mpa)]) + + +voltArray = [0, 110] + +for nMPA, MPA in enumerate(fwhmPerVolt): # Loop over MPAs + plot = MPAPlot() + for fwhm in MPA: # Loop over pix + plot.createGraph(voltArray, fwhm) + plot.setTitle("Bond test for MPA" + str(assembly[nMPA]) +" ; Bias voltage / V ; FWHM of noise from threshold scan / thrDACs") + if nMPA == 1: # Mark MPA5 with confirmed bad bonds + plot.setLineColor(colors) + plot.setRange(yRange = [0,100]) + plot.draw() + +# +#maxMPA = max([max(mpa) for mpa in diffs]) +#print maxMPA +# +#scaledDiffs = [] +#for mpa in diffs: +# scaledDiffs.append([(pix*1000/maxMPA) for pix in mpa]) +#print scaledDiffs +# +#for mpa in scaledDiffs: +# plot = MPAPlot() +# plot.createHitMap(mpa) +# plot.setRange(zRange = [0,1000]) +# plot.draw() diff --git a/old/bondTest.py b/old/bondTest.py new file mode 100644 index 0000000..743c7c7 --- /dev/null +++ b/old/bondTest.py @@ -0,0 +1,95 @@ +#!/usr/bin/python + +from array import array +from MPACalibration import MPACalibration +from MPAPlot import MPAPlot +from KeithleyControl.keithleyControl import keithley +import ROOT + +k = keithley() +k.init() +plot = MPAPlot() +k.setVoltage(110) +# Calibrate MPA (only use MPA 5 as it has confirmed failed bonds) +calibration = MPACalibration([2,5]) # Argument reflects assembly which is actually on board +calibration.thresholdScan(calEnbl = 1) +calibration.writeCalibrationToMPA() + + +# Start scan +resolution = 30 + +calibration.thresholdScan() +counter, _ = calibration.getThrScanPerPix() +_,_, threshold = calibration.getThrScanMetadata() +for pix in counter[0]: + plot.createGraph(array('d',threshold[0]), array('d', pix)) + + +maxHitsPerVolts = [] +edgesPerVolt = [] +thresholdScansPerBiasVolt = [] +voltArray = [] + + +for voltStep in range(5,111, resolution): # Loop over bias voltage in steps of 10 + voltArray.append(voltStep) + plot.clear() + k.setVoltage(voltStep) + print k.readVoltage() + + calibration.thresholdScan() + counter, _ = calibration.getThrScanPerPix() # No need to get memory, only ripple counter needed + _,_,threshold = calibration.getThrScanMetadata() + edgesPerVolt.append(calibration.findHalfMaxEdges()) + + maxHitsPerPix = [] + for pix in counter[0]: + plot.createGraph(array('d', threshold[0]), array('d', pix)) + maxHitsPerPix.append(max(pix)) + + thresholdScansPerBiasVolt.append(plot.getPlot()) + maxHitsPerVolts.append(max(maxHitsPerPix)) +k.close() +print "Keithley closed" +c1 = ROOT.TCanvas("c1", "Canvas", 800, 600) + +#c1.Divide(3,4) +# +#for i,graphs in enumerate(thresholdScansPerBiasVolt): +# c1.cd(i+1) +# for j,graph in enumerate(graphs): +# if j == 0: +# graph.SetTitle("Threshold scan at "+ str(i*10)+"V") +# graph.GetYaxis().SetRangeUser(0,maxHitsPerVolts[i]*1.1) +# graph.Draw("APL") +# else: +# graph.Draw("PL") + +#plot.clear() + +MAPSA = [2,5] +fwhmMAPSAVolt = [] # Volt[MPA[Pix]] + +for edgesMAPSA in edgesPerVolt: + fwhmVolt = [] + for edges in edgesMAPSA: + fwhm = [pix[1] - pix[0] for pix in edges] # Loop over edge-tuples for each pixel and subtract rising edges from falling edge. This is the full width at half maximum. + fwhmVolt.append(fwhm) + fwhmMAPSAVolt.append(fwhmVolt) + + +MAPSAVoltfwhm = list(zip(*fwhmMAPSAVolt)) # Swap MAPSA and Volt in nested-list-hierarchy +MAPSAfwhmVolt = [] +for a in MAPSAVoltfwhm: #iterate over MPAs + MAPSAfwhmVolt.append(list(zip(*a))) # Swap Volt and Pixel in nested-list-hierarchy. Result: [MPA1[Pix1[Volt1,Volt2,...], Pix2[],...,Pix48[]], MPA2[],..] + +MAPSAfwhmDiff = [] +for MPA in MAPSAfwhmVolt: + fwhmDiff = [] + for pix in MPA: + pixSorted = sorted(pix) + fwhmDiff.append(sum(pixSorted[-2:])/2 - sum(pixSorted[:2])/2) # Average two highest and two lowest fwhms + MAPSAfwhmDiff.append(fwhmDiff) + +raw_input() diff --git a/old/calib_data/.Conf_calibrated_MPA2_config1.xml.swp b/old/calib_data/.Conf_calibrated_MPA2_config1.xml.swp new file mode 100644 index 0000000000000000000000000000000000000000..90e90af1591ec65853a74471095c4e8b6d221f70 GIT binary patch literal 16384 zcmeI&e@xVM9LMnwAPOQun$wDnlW3F8?(Ta>f^}Y&{ypYNU0+-$DDtncT$J??Yg z&-Z)Z?|okTdi%UTSYxeR<1yu#a|K(v5ZlwPRQ|5*i94PrL@40%w>%$~NB(gOZmbW4 zT5`>G?HkShz|BwXh+WX)ag~+3s>@sI!kc}efW_|%`z-F3=DO-yUt_Q)J<)t)k! zt-6-Z;Io>!t*P5sK>H?#?{{hnBRC7=>e z38(~A0xAKOfJ#6ma2qDz^9vzs{V}-!z~BF`)&J9JLQG%`qZq~j4x$?!Xu>ln!U|*} z1=Dv3@e{tmAl^YYwjqQKD1{T*NXOMwAui&34B>sej_uft04m@{4i+K-k$HSa4C65N zV+XdP0Z*e4X551$Or;1hj#D^_x3C*8q6O>WfgPDh#pSt-2_qOpA9~P*FlymNKC&?% z0vD5o_!>hvguU2>EvQEoRw4(Bkcdc<5Z_@K{dfa=(19kb!z!4Ofw`EPBg79lg#q;9 zRlI}{e0UsoEI}GB&lci5MsN%Vu@5g}69RYwdAJ`7@MoeB7chz;9Kr$YLOX&e#ly(K zA|zm9mJp|L0*BFySI~hbl;aURfO|0qlPo%&!AX3CKJ=gy&!Gx#XvjngB0R_Xvn>Cu zB|F@!y-uscA{&#w(O2PJ<9W>G_B!pF!*YGc#1WU*>!eRM*Uv8V=zX%0ee#-B`X#I6 zesZ*Db#e4A#WSCaUAXw~cj2&pm*VJM^t0(G^XMJ2k#~T}(Hd+EG@6=MW@+{;XSBi?TZ``5h8F%Q*jXU%Q zjXU&Q;||@x6FMW$=Vl)GKq%PC|Crw*r}7nrlp;>e%H%!zmOi(uSa#;g!X^4vPVfsg zeTGk?@7bbzHhnKzl9bbM%v&K3@yh#BkJIk3@G4|o;Aow>wZmOnQs5M_{@+2(6rtXd z_5ZcM?@v<4pT!7{;XUkytos}A6bfL&V$4E>I{q9+F@z7XADw8%Iuv0!GLVEz)bQgt zjT1P6H_?Rp@;joFyynUc@dukzVan@ZqzNPyo|{fAHg zJv82uip{_iFPo8PUIw0e*$ljtW;5_onr7g&G|j+^X_|po(=-Dwr)dUWPt*S8yzVdE CfBo?Q literal 0 HcmV?d00001 diff --git a/old/calib_data/Conf_calibrated_MPA1_config1.xml b/old/calib_data/Conf_calibrated_MPA1_config1.xml new file mode 100644 index 0000000..05b3bca --- /dev/null +++ b/old/calib_data/Conf_calibrated_MPA1_config1.xml @@ -0,0 +1,323 @@ + + + 3 + 0 + 0 + 0 + 0 + 70 + 100 + + + 1 + 1 + 31 + 0 + 0 + 1 + 1 + 31 + 0 + 0 + 1 + + + 1 + 1 + 31 + 0 + 0 + 1 + 1 + 31 + 0 + 0 + 1 + + + 1 + 1 + 31 + 0 + 0 + 1 + 1 + 31 + 0 + 0 + 1 + + + 1 + 1 + 31 + 0 + 0 + 1 + 1 + 31 + 0 + 0 + 1 + + + 1 + 1 + 31 + 0 + 0 + 1 + 1 + 31 + 0 + 0 + 1 + + + 1 + 1 + 31 + 0 + 0 + 1 + 1 + 31 + 0 + 0 + 1 + + + 1 + 1 + 31 + 0 + 0 + 1 + 1 + 31 + 0 + 0 + 1 + + + 1 + 1 + 31 + 0 + 0 + 1 + 1 + 31 + 0 + 0 + 1 + + + 1 + 1 + 31 + 0 + 0 + 1 + 1 + 31 + 0 + 0 + 1 + + + 1 + 1 + 31 + 0 + 0 + 1 + 1 + 31 + 0 + 0 + 1 + + + 1 + 1 + 31 + 0 + 0 + 1 + 1 + 31 + 0 + 0 + 1 + + + 1 + 1 + 31 + 0 + 0 + 1 + 1 + 31 + 0 + 0 + 1 + + + 1 + 1 + 31 + 0 + 0 + 1 + 1 + 31 + 0 + 0 + 1 + + + 1 + 1 + 31 + 0 + 0 + 1 + 1 + 31 + 0 + 0 + 1 + + + 1 + 1 + 31 + 0 + 0 + 1 + 1 + 31 + 0 + 0 + 1 + + + 1 + 1 + 31 + 0 + 0 + 1 + 1 + 31 + 0 + 0 + 1 + + + 1 + 1 + 31 + 0 + 0 + 1 + 1 + 31 + 0 + 0 + 1 + + + 1 + 1 + 31 + 0 + 0 + 1 + 1 + 31 + 0 + 0 + 1 + + + 1 + 1 + 31 + 0 + 0 + 1 + 1 + 31 + 0 + 0 + 1 + + + 1 + 1 + 31 + 0 + 0 + 1 + 1 + 31 + 0 + 0 + 1 + + + 1 + 1 + 31 + 0 + 0 + 1 + 1 + 31 + 0 + 0 + 1 + + + 1 + 1 + 31 + 0 + 0 + 1 + 1 + 31 + 0 + 0 + 1 + + + 1 + 1 + 31 + 0 + 0 + 1 + 1 + 31 + 0 + 0 + 1 + + + 1 + 1 + 31 + 0 + 0 + 1 + 1 + 31 + 0 + 0 + 1 + + \ No newline at end of file diff --git a/old/calib_data/Conf_calibrated_MPA2_config1.xml b/old/calib_data/Conf_calibrated_MPA2_config1.xml new file mode 100644 index 0000000..05b3bca --- /dev/null +++ b/old/calib_data/Conf_calibrated_MPA2_config1.xml @@ -0,0 +1,323 @@ + + + 3 + 0 + 0 + 0 + 0 + 70 + 100 + + + 1 + 1 + 31 + 0 + 0 + 1 + 1 + 31 + 0 + 0 + 1 + + + 1 + 1 + 31 + 0 + 0 + 1 + 1 + 31 + 0 + 0 + 1 + + + 1 + 1 + 31 + 0 + 0 + 1 + 1 + 31 + 0 + 0 + 1 + + + 1 + 1 + 31 + 0 + 0 + 1 + 1 + 31 + 0 + 0 + 1 + + + 1 + 1 + 31 + 0 + 0 + 1 + 1 + 31 + 0 + 0 + 1 + + + 1 + 1 + 31 + 0 + 0 + 1 + 1 + 31 + 0 + 0 + 1 + + + 1 + 1 + 31 + 0 + 0 + 1 + 1 + 31 + 0 + 0 + 1 + + + 1 + 1 + 31 + 0 + 0 + 1 + 1 + 31 + 0 + 0 + 1 + + + 1 + 1 + 31 + 0 + 0 + 1 + 1 + 31 + 0 + 0 + 1 + + + 1 + 1 + 31 + 0 + 0 + 1 + 1 + 31 + 0 + 0 + 1 + + + 1 + 1 + 31 + 0 + 0 + 1 + 1 + 31 + 0 + 0 + 1 + + + 1 + 1 + 31 + 0 + 0 + 1 + 1 + 31 + 0 + 0 + 1 + + + 1 + 1 + 31 + 0 + 0 + 1 + 1 + 31 + 0 + 0 + 1 + + + 1 + 1 + 31 + 0 + 0 + 1 + 1 + 31 + 0 + 0 + 1 + + + 1 + 1 + 31 + 0 + 0 + 1 + 1 + 31 + 0 + 0 + 1 + + + 1 + 1 + 31 + 0 + 0 + 1 + 1 + 31 + 0 + 0 + 1 + + + 1 + 1 + 31 + 0 + 0 + 1 + 1 + 31 + 0 + 0 + 1 + + + 1 + 1 + 31 + 0 + 0 + 1 + 1 + 31 + 0 + 0 + 1 + + + 1 + 1 + 31 + 0 + 0 + 1 + 1 + 31 + 0 + 0 + 1 + + + 1 + 1 + 31 + 0 + 0 + 1 + 1 + 31 + 0 + 0 + 1 + + + 1 + 1 + 31 + 0 + 0 + 1 + 1 + 31 + 0 + 0 + 1 + + + 1 + 1 + 31 + 0 + 0 + 1 + 1 + 31 + 0 + 0 + 1 + + + 1 + 1 + 31 + 0 + 0 + 1 + 1 + 31 + 0 + 0 + 1 + + + 1 + 1 + 31 + 0 + 0 + 1 + 1 + 31 + 0 + 0 + 1 + + \ No newline at end of file diff --git a/old/calib_data/Conf_calibrated_MPA3_config1.xml b/old/calib_data/Conf_calibrated_MPA3_config1.xml new file mode 100644 index 0000000..05b3bca --- /dev/null +++ b/old/calib_data/Conf_calibrated_MPA3_config1.xml @@ -0,0 +1,323 @@ + + + 3 + 0 + 0 + 0 + 0 + 70 + 100 + + + 1 + 1 + 31 + 0 + 0 + 1 + 1 + 31 + 0 + 0 + 1 + + + 1 + 1 + 31 + 0 + 0 + 1 + 1 + 31 + 0 + 0 + 1 + + + 1 + 1 + 31 + 0 + 0 + 1 + 1 + 31 + 0 + 0 + 1 + + + 1 + 1 + 31 + 0 + 0 + 1 + 1 + 31 + 0 + 0 + 1 + + + 1 + 1 + 31 + 0 + 0 + 1 + 1 + 31 + 0 + 0 + 1 + + + 1 + 1 + 31 + 0 + 0 + 1 + 1 + 31 + 0 + 0 + 1 + + + 1 + 1 + 31 + 0 + 0 + 1 + 1 + 31 + 0 + 0 + 1 + + + 1 + 1 + 31 + 0 + 0 + 1 + 1 + 31 + 0 + 0 + 1 + + + 1 + 1 + 31 + 0 + 0 + 1 + 1 + 31 + 0 + 0 + 1 + + + 1 + 1 + 31 + 0 + 0 + 1 + 1 + 31 + 0 + 0 + 1 + + + 1 + 1 + 31 + 0 + 0 + 1 + 1 + 31 + 0 + 0 + 1 + + + 1 + 1 + 31 + 0 + 0 + 1 + 1 + 31 + 0 + 0 + 1 + + + 1 + 1 + 31 + 0 + 0 + 1 + 1 + 31 + 0 + 0 + 1 + + + 1 + 1 + 31 + 0 + 0 + 1 + 1 + 31 + 0 + 0 + 1 + + + 1 + 1 + 31 + 0 + 0 + 1 + 1 + 31 + 0 + 0 + 1 + + + 1 + 1 + 31 + 0 + 0 + 1 + 1 + 31 + 0 + 0 + 1 + + + 1 + 1 + 31 + 0 + 0 + 1 + 1 + 31 + 0 + 0 + 1 + + + 1 + 1 + 31 + 0 + 0 + 1 + 1 + 31 + 0 + 0 + 1 + + + 1 + 1 + 31 + 0 + 0 + 1 + 1 + 31 + 0 + 0 + 1 + + + 1 + 1 + 31 + 0 + 0 + 1 + 1 + 31 + 0 + 0 + 1 + + + 1 + 1 + 31 + 0 + 0 + 1 + 1 + 31 + 0 + 0 + 1 + + + 1 + 1 + 31 + 0 + 0 + 1 + 1 + 31 + 0 + 0 + 1 + + + 1 + 1 + 31 + 0 + 0 + 1 + 1 + 31 + 0 + 0 + 1 + + + 1 + 1 + 31 + 0 + 0 + 1 + 1 + 31 + 0 + 0 + 1 + + \ No newline at end of file diff --git a/old/calib_data/Conf_calibrated_MPA4_config1.xml b/old/calib_data/Conf_calibrated_MPA4_config1.xml new file mode 100644 index 0000000..05b3bca --- /dev/null +++ b/old/calib_data/Conf_calibrated_MPA4_config1.xml @@ -0,0 +1,323 @@ + + + 3 + 0 + 0 + 0 + 0 + 70 + 100 + + + 1 + 1 + 31 + 0 + 0 + 1 + 1 + 31 + 0 + 0 + 1 + + + 1 + 1 + 31 + 0 + 0 + 1 + 1 + 31 + 0 + 0 + 1 + + + 1 + 1 + 31 + 0 + 0 + 1 + 1 + 31 + 0 + 0 + 1 + + + 1 + 1 + 31 + 0 + 0 + 1 + 1 + 31 + 0 + 0 + 1 + + + 1 + 1 + 31 + 0 + 0 + 1 + 1 + 31 + 0 + 0 + 1 + + + 1 + 1 + 31 + 0 + 0 + 1 + 1 + 31 + 0 + 0 + 1 + + + 1 + 1 + 31 + 0 + 0 + 1 + 1 + 31 + 0 + 0 + 1 + + + 1 + 1 + 31 + 0 + 0 + 1 + 1 + 31 + 0 + 0 + 1 + + + 1 + 1 + 31 + 0 + 0 + 1 + 1 + 31 + 0 + 0 + 1 + + + 1 + 1 + 31 + 0 + 0 + 1 + 1 + 31 + 0 + 0 + 1 + + + 1 + 1 + 31 + 0 + 0 + 1 + 1 + 31 + 0 + 0 + 1 + + + 1 + 1 + 31 + 0 + 0 + 1 + 1 + 31 + 0 + 0 + 1 + + + 1 + 1 + 31 + 0 + 0 + 1 + 1 + 31 + 0 + 0 + 1 + + + 1 + 1 + 31 + 0 + 0 + 1 + 1 + 31 + 0 + 0 + 1 + + + 1 + 1 + 31 + 0 + 0 + 1 + 1 + 31 + 0 + 0 + 1 + + + 1 + 1 + 31 + 0 + 0 + 1 + 1 + 31 + 0 + 0 + 1 + + + 1 + 1 + 31 + 0 + 0 + 1 + 1 + 31 + 0 + 0 + 1 + + + 1 + 1 + 31 + 0 + 0 + 1 + 1 + 31 + 0 + 0 + 1 + + + 1 + 1 + 31 + 0 + 0 + 1 + 1 + 31 + 0 + 0 + 1 + + + 1 + 1 + 31 + 0 + 0 + 1 + 1 + 31 + 0 + 0 + 1 + + + 1 + 1 + 31 + 0 + 0 + 1 + 1 + 31 + 0 + 0 + 1 + + + 1 + 1 + 31 + 0 + 0 + 1 + 1 + 31 + 0 + 0 + 1 + + + 1 + 1 + 31 + 0 + 0 + 1 + 1 + 31 + 0 + 0 + 1 + + + 1 + 1 + 31 + 0 + 0 + 1 + 1 + 31 + 0 + 0 + 1 + + \ No newline at end of file diff --git a/old/calib_data/Conf_calibrated_MPA5_config1.xml b/old/calib_data/Conf_calibrated_MPA5_config1.xml new file mode 100644 index 0000000..535e10d --- /dev/null +++ b/old/calib_data/Conf_calibrated_MPA5_config1.xml @@ -0,0 +1,323 @@ + + + 3 + 0 + 0 + 0 + 0 + 70 + 100 + + + 1 + 1 + 16 + 0 + 0 + 1 + 1 + 0 + 0 + 0 + 1 + + + 1 + 1 + 17 + 0 + 0 + 1 + 1 + 11 + 0 + 0 + 1 + + + 1 + 1 + 9 + 0 + 0 + 1 + 1 + 25 + 0 + 0 + 1 + + + 1 + 1 + 11 + 0 + 0 + 1 + 1 + 15 + 0 + 0 + 1 + + + 1 + 1 + 11 + 0 + 0 + 1 + 1 + 16 + 0 + 0 + 1 + + + 1 + 1 + 27 + 0 + 0 + 1 + 1 + 11 + 0 + 0 + 1 + + + 1 + 1 + 11 + 0 + 0 + 1 + 1 + 11 + 0 + 0 + 1 + + + 1 + 1 + 27 + 0 + 0 + 1 + 1 + 16 + 0 + 0 + 1 + + + 1 + 1 + 16 + 0 + 0 + 1 + 1 + 17 + 0 + 0 + 1 + + + 1 + 1 + 25 + 0 + 0 + 1 + 1 + 16 + 0 + 0 + 1 + + + 1 + 1 + 3 + 0 + 0 + 1 + 1 + 0 + 0 + 0 + 1 + + + 1 + 1 + 11 + 0 + 0 + 1 + 1 + 13 + 0 + 0 + 1 + + + 1 + 1 + 8 + 0 + 0 + 1 + 1 + 4 + 0 + 0 + 1 + + + 1 + 1 + 11 + 0 + 0 + 1 + 1 + 3 + 0 + 0 + 1 + + + 1 + 1 + 27 + 0 + 0 + 1 + 1 + 11 + 0 + 0 + 1 + + + 1 + 1 + 27 + 0 + 0 + 1 + 1 + 27 + 0 + 0 + 1 + + + 1 + 1 + 16 + 0 + 0 + 1 + 1 + 17 + 0 + 0 + 1 + + + 1 + 1 + 8 + 0 + 0 + 1 + 1 + 11 + 0 + 0 + 1 + + + 1 + 1 + 3 + 0 + 0 + 1 + 1 + 11 + 0 + 0 + 1 + + + 1 + 1 + 11 + 0 + 0 + 1 + 1 + 11 + 0 + 0 + 1 + + + 1 + 1 + 11 + 0 + 0 + 1 + 1 + 11 + 0 + 0 + 1 + + + 1 + 1 + 11 + 0 + 0 + 1 + 1 + 11 + 0 + 0 + 1 + + + 1 + 1 + 12 + 0 + 0 + 1 + 1 + 11 + 0 + 0 + 1 + + + 1 + 1 + 16 + 0 + 0 + 1 + 1 + 8 + 0 + 0 + 1 + + \ No newline at end of file diff --git a/old/calib_data/Conf_calibrated_MPA6_config1.xml b/old/calib_data/Conf_calibrated_MPA6_config1.xml new file mode 100644 index 0000000..157bc09 --- /dev/null +++ b/old/calib_data/Conf_calibrated_MPA6_config1.xml @@ -0,0 +1,323 @@ + + + 3 + 0 + 0 + 0 + 0 + 70 + 100 + + + 1 + 1 + 18 + 0 + 0 + 1 + 1 + 18 + 0 + 0 + 1 + + + 1 + 1 + 12 + 0 + 0 + 1 + 1 + 18 + 0 + 0 + 1 + + + 1 + 1 + 16 + 0 + 0 + 1 + 1 + 3 + 0 + 0 + 1 + + + 1 + 1 + 18 + 0 + 0 + 1 + 1 + 12 + 0 + 0 + 1 + + + 1 + 1 + 3 + 0 + 0 + 1 + 1 + 17 + 0 + 0 + 1 + + + 1 + 1 + 16 + 0 + 0 + 1 + 1 + 12 + 0 + 0 + 1 + + + 1 + 1 + 12 + 0 + 0 + 1 + 1 + 17 + 0 + 0 + 1 + + + 1 + 1 + 26 + 0 + 0 + 1 + 1 + 17 + 0 + 0 + 1 + + + 1 + 1 + 16 + 0 + 0 + 1 + 1 + 18 + 0 + 0 + 1 + + + 1 + 1 + 26 + 0 + 0 + 1 + 1 + 18 + 0 + 0 + 1 + + + 1 + 1 + 18 + 0 + 0 + 1 + 1 + 18 + 0 + 0 + 1 + + + 1 + 1 + 21 + 0 + 0 + 1 + 1 + 14 + 0 + 0 + 1 + + + 1 + 1 + 18 + 0 + 0 + 1 + 1 + 18 + 0 + 0 + 1 + + + 1 + 1 + 28 + 0 + 0 + 1 + 1 + 31 + 0 + 0 + 1 + + + 1 + 1 + 15 + 0 + 0 + 1 + 1 + 26 + 0 + 0 + 1 + + + 1 + 1 + 26 + 0 + 0 + 1 + 1 + 17 + 0 + 0 + 1 + + + 1 + 1 + 18 + 0 + 0 + 1 + 1 + 15 + 0 + 0 + 1 + + + 1 + 1 + 18 + 0 + 0 + 1 + 1 + 12 + 0 + 0 + 1 + + + 1 + 1 + 9 + 0 + 0 + 1 + 1 + 12 + 0 + 0 + 1 + + + 1 + 1 + 7 + 0 + 0 + 1 + 1 + 28 + 0 + 0 + 1 + + + 1 + 1 + 25 + 0 + 0 + 1 + 1 + 28 + 0 + 0 + 1 + + + 1 + 1 + 17 + 0 + 0 + 1 + 1 + 28 + 0 + 0 + 1 + + + 1 + 1 + 18 + 0 + 0 + 1 + 1 + 17 + 0 + 0 + 1 + + + 1 + 1 + 18 + 0 + 0 + 1 + 1 + 16 + 0 + 0 + 1 + + \ No newline at end of file diff --git a/old/calib_data/Conf_default_MPA1_config1.xml b/old/calib_data/Conf_default_MPA1_config1.xml new file mode 100644 index 0000000..af5ac25 --- /dev/null +++ b/old/calib_data/Conf_default_MPA1_config1.xml @@ -0,0 +1,324 @@ + + + + 3 + 0 + 0 + 0 + 0 + 15 + 33 + + + 1 + 1 + 15 + 1 + 0 + 1 + 1 + 15 + 1 + 0 + 0 + + + 1 + 1 + 15 + 1 + 0 + 1 + 1 + 15 + 1 + 0 + 0 + + + 1 + 1 + 15 + 1 + 0 + 1 + 1 + 15 + 1 + 0 + 0 + + + 1 + 1 + 15 + 1 + 0 + 1 + 1 + 15 + 1 + 0 + 0 + + + 1 + 1 + 15 + 1 + 0 + 1 + 1 + 15 + 1 + 0 + 0 + + + 1 + 1 + 15 + 1 + 0 + 1 + 1 + 15 + 1 + 0 + 0 + + + 1 + 1 + 15 + 1 + 0 + 1 + 1 + 15 + 1 + 0 + 0 + + + 1 + 1 + 15 + 1 + 0 + 1 + 1 + 15 + 1 + 0 + 0 + + + 1 + 1 + 15 + 1 + 0 + 1 + 1 + 15 + 1 + 0 + 0 + + + 1 + 1 + 15 + 1 + 0 + 1 + 1 + 15 + 1 + 0 + 0 + + + 1 + 1 + 15 + 1 + 0 + 1 + 1 + 15 + 1 + 0 + 0 + + + 1 + 1 + 15 + 1 + 0 + 1 + 1 + 15 + 1 + 0 + 0 + + + 1 + 1 + 15 + 1 + 0 + 1 + 1 + 15 + 1 + 0 + 0 + + + 1 + 1 + 15 + 1 + 0 + 1 + 1 + 15 + 1 + 0 + 0 + + + 1 + 1 + 15 + 1 + 0 + 1 + 1 + 15 + 1 + 0 + 0 + + + 1 + 1 + 15 + 1 + 0 + 1 + 1 + 15 + 1 + 0 + 0 + + + 1 + 1 + 15 + 1 + 0 + 1 + 1 + 15 + 1 + 0 + 0 + + + 1 + 1 + 15 + 1 + 0 + 1 + 1 + 15 + 1 + 0 + 0 + + + 1 + 1 + 15 + 1 + 0 + 1 + 1 + 15 + 1 + 0 + 0 + + + 1 + 1 + 15 + 1 + 0 + 1 + 1 + 15 + 1 + 0 + 0 + + + 1 + 1 + 15 + 1 + 0 + 1 + 1 + 15 + 1 + 0 + 0 + + + 1 + 1 + 15 + 1 + 0 + 1 + 1 + 15 + 1 + 0 + 0 + + + 1 + 1 + 15 + 1 + 0 + 1 + 1 + 15 + 1 + 0 + 0 + + + 1 + 1 + 15 + 1 + 0 + 1 + 1 + 15 + 1 + 0 + 0 + + diff --git a/old/calib_data/Conf_default_MPA2_config1.xml b/old/calib_data/Conf_default_MPA2_config1.xml new file mode 100644 index 0000000..af5ac25 --- /dev/null +++ b/old/calib_data/Conf_default_MPA2_config1.xml @@ -0,0 +1,324 @@ + + + + 3 + 0 + 0 + 0 + 0 + 15 + 33 + + + 1 + 1 + 15 + 1 + 0 + 1 + 1 + 15 + 1 + 0 + 0 + + + 1 + 1 + 15 + 1 + 0 + 1 + 1 + 15 + 1 + 0 + 0 + + + 1 + 1 + 15 + 1 + 0 + 1 + 1 + 15 + 1 + 0 + 0 + + + 1 + 1 + 15 + 1 + 0 + 1 + 1 + 15 + 1 + 0 + 0 + + + 1 + 1 + 15 + 1 + 0 + 1 + 1 + 15 + 1 + 0 + 0 + + + 1 + 1 + 15 + 1 + 0 + 1 + 1 + 15 + 1 + 0 + 0 + + + 1 + 1 + 15 + 1 + 0 + 1 + 1 + 15 + 1 + 0 + 0 + + + 1 + 1 + 15 + 1 + 0 + 1 + 1 + 15 + 1 + 0 + 0 + + + 1 + 1 + 15 + 1 + 0 + 1 + 1 + 15 + 1 + 0 + 0 + + + 1 + 1 + 15 + 1 + 0 + 1 + 1 + 15 + 1 + 0 + 0 + + + 1 + 1 + 15 + 1 + 0 + 1 + 1 + 15 + 1 + 0 + 0 + + + 1 + 1 + 15 + 1 + 0 + 1 + 1 + 15 + 1 + 0 + 0 + + + 1 + 1 + 15 + 1 + 0 + 1 + 1 + 15 + 1 + 0 + 0 + + + 1 + 1 + 15 + 1 + 0 + 1 + 1 + 15 + 1 + 0 + 0 + + + 1 + 1 + 15 + 1 + 0 + 1 + 1 + 15 + 1 + 0 + 0 + + + 1 + 1 + 15 + 1 + 0 + 1 + 1 + 15 + 1 + 0 + 0 + + + 1 + 1 + 15 + 1 + 0 + 1 + 1 + 15 + 1 + 0 + 0 + + + 1 + 1 + 15 + 1 + 0 + 1 + 1 + 15 + 1 + 0 + 0 + + + 1 + 1 + 15 + 1 + 0 + 1 + 1 + 15 + 1 + 0 + 0 + + + 1 + 1 + 15 + 1 + 0 + 1 + 1 + 15 + 1 + 0 + 0 + + + 1 + 1 + 15 + 1 + 0 + 1 + 1 + 15 + 1 + 0 + 0 + + + 1 + 1 + 15 + 1 + 0 + 1 + 1 + 15 + 1 + 0 + 0 + + + 1 + 1 + 15 + 1 + 0 + 1 + 1 + 15 + 1 + 0 + 0 + + + 1 + 1 + 15 + 1 + 0 + 1 + 1 + 15 + 1 + 0 + 0 + + diff --git a/old/calib_data/Conf_default_MPA3_config1.xml b/old/calib_data/Conf_default_MPA3_config1.xml new file mode 100644 index 0000000..af5ac25 --- /dev/null +++ b/old/calib_data/Conf_default_MPA3_config1.xml @@ -0,0 +1,324 @@ + + + + 3 + 0 + 0 + 0 + 0 + 15 + 33 + + + 1 + 1 + 15 + 1 + 0 + 1 + 1 + 15 + 1 + 0 + 0 + + + 1 + 1 + 15 + 1 + 0 + 1 + 1 + 15 + 1 + 0 + 0 + + + 1 + 1 + 15 + 1 + 0 + 1 + 1 + 15 + 1 + 0 + 0 + + + 1 + 1 + 15 + 1 + 0 + 1 + 1 + 15 + 1 + 0 + 0 + + + 1 + 1 + 15 + 1 + 0 + 1 + 1 + 15 + 1 + 0 + 0 + + + 1 + 1 + 15 + 1 + 0 + 1 + 1 + 15 + 1 + 0 + 0 + + + 1 + 1 + 15 + 1 + 0 + 1 + 1 + 15 + 1 + 0 + 0 + + + 1 + 1 + 15 + 1 + 0 + 1 + 1 + 15 + 1 + 0 + 0 + + + 1 + 1 + 15 + 1 + 0 + 1 + 1 + 15 + 1 + 0 + 0 + + + 1 + 1 + 15 + 1 + 0 + 1 + 1 + 15 + 1 + 0 + 0 + + + 1 + 1 + 15 + 1 + 0 + 1 + 1 + 15 + 1 + 0 + 0 + + + 1 + 1 + 15 + 1 + 0 + 1 + 1 + 15 + 1 + 0 + 0 + + + 1 + 1 + 15 + 1 + 0 + 1 + 1 + 15 + 1 + 0 + 0 + + + 1 + 1 + 15 + 1 + 0 + 1 + 1 + 15 + 1 + 0 + 0 + + + 1 + 1 + 15 + 1 + 0 + 1 + 1 + 15 + 1 + 0 + 0 + + + 1 + 1 + 15 + 1 + 0 + 1 + 1 + 15 + 1 + 0 + 0 + + + 1 + 1 + 15 + 1 + 0 + 1 + 1 + 15 + 1 + 0 + 0 + + + 1 + 1 + 15 + 1 + 0 + 1 + 1 + 15 + 1 + 0 + 0 + + + 1 + 1 + 15 + 1 + 0 + 1 + 1 + 15 + 1 + 0 + 0 + + + 1 + 1 + 15 + 1 + 0 + 1 + 1 + 15 + 1 + 0 + 0 + + + 1 + 1 + 15 + 1 + 0 + 1 + 1 + 15 + 1 + 0 + 0 + + + 1 + 1 + 15 + 1 + 0 + 1 + 1 + 15 + 1 + 0 + 0 + + + 1 + 1 + 15 + 1 + 0 + 1 + 1 + 15 + 1 + 0 + 0 + + + 1 + 1 + 15 + 1 + 0 + 1 + 1 + 15 + 1 + 0 + 0 + + diff --git a/old/calib_data/Conf_default_MPA4_config1.xml b/old/calib_data/Conf_default_MPA4_config1.xml new file mode 100644 index 0000000..af5ac25 --- /dev/null +++ b/old/calib_data/Conf_default_MPA4_config1.xml @@ -0,0 +1,324 @@ + + + + 3 + 0 + 0 + 0 + 0 + 15 + 33 + + + 1 + 1 + 15 + 1 + 0 + 1 + 1 + 15 + 1 + 0 + 0 + + + 1 + 1 + 15 + 1 + 0 + 1 + 1 + 15 + 1 + 0 + 0 + + + 1 + 1 + 15 + 1 + 0 + 1 + 1 + 15 + 1 + 0 + 0 + + + 1 + 1 + 15 + 1 + 0 + 1 + 1 + 15 + 1 + 0 + 0 + + + 1 + 1 + 15 + 1 + 0 + 1 + 1 + 15 + 1 + 0 + 0 + + + 1 + 1 + 15 + 1 + 0 + 1 + 1 + 15 + 1 + 0 + 0 + + + 1 + 1 + 15 + 1 + 0 + 1 + 1 + 15 + 1 + 0 + 0 + + + 1 + 1 + 15 + 1 + 0 + 1 + 1 + 15 + 1 + 0 + 0 + + + 1 + 1 + 15 + 1 + 0 + 1 + 1 + 15 + 1 + 0 + 0 + + + 1 + 1 + 15 + 1 + 0 + 1 + 1 + 15 + 1 + 0 + 0 + + + 1 + 1 + 15 + 1 + 0 + 1 + 1 + 15 + 1 + 0 + 0 + + + 1 + 1 + 15 + 1 + 0 + 1 + 1 + 15 + 1 + 0 + 0 + + + 1 + 1 + 15 + 1 + 0 + 1 + 1 + 15 + 1 + 0 + 0 + + + 1 + 1 + 15 + 1 + 0 + 1 + 1 + 15 + 1 + 0 + 0 + + + 1 + 1 + 15 + 1 + 0 + 1 + 1 + 15 + 1 + 0 + 0 + + + 1 + 1 + 15 + 1 + 0 + 1 + 1 + 15 + 1 + 0 + 0 + + + 1 + 1 + 15 + 1 + 0 + 1 + 1 + 15 + 1 + 0 + 0 + + + 1 + 1 + 15 + 1 + 0 + 1 + 1 + 15 + 1 + 0 + 0 + + + 1 + 1 + 15 + 1 + 0 + 1 + 1 + 15 + 1 + 0 + 0 + + + 1 + 1 + 15 + 1 + 0 + 1 + 1 + 15 + 1 + 0 + 0 + + + 1 + 1 + 15 + 1 + 0 + 1 + 1 + 15 + 1 + 0 + 0 + + + 1 + 1 + 15 + 1 + 0 + 1 + 1 + 15 + 1 + 0 + 0 + + + 1 + 1 + 15 + 1 + 0 + 1 + 1 + 15 + 1 + 0 + 0 + + + 1 + 1 + 15 + 1 + 0 + 1 + 1 + 15 + 1 + 0 + 0 + + diff --git a/old/calib_data/Conf_default_MPA5_config1.xml b/old/calib_data/Conf_default_MPA5_config1.xml new file mode 100644 index 0000000..af5ac25 --- /dev/null +++ b/old/calib_data/Conf_default_MPA5_config1.xml @@ -0,0 +1,324 @@ + + + + 3 + 0 + 0 + 0 + 0 + 15 + 33 + + + 1 + 1 + 15 + 1 + 0 + 1 + 1 + 15 + 1 + 0 + 0 + + + 1 + 1 + 15 + 1 + 0 + 1 + 1 + 15 + 1 + 0 + 0 + + + 1 + 1 + 15 + 1 + 0 + 1 + 1 + 15 + 1 + 0 + 0 + + + 1 + 1 + 15 + 1 + 0 + 1 + 1 + 15 + 1 + 0 + 0 + + + 1 + 1 + 15 + 1 + 0 + 1 + 1 + 15 + 1 + 0 + 0 + + + 1 + 1 + 15 + 1 + 0 + 1 + 1 + 15 + 1 + 0 + 0 + + + 1 + 1 + 15 + 1 + 0 + 1 + 1 + 15 + 1 + 0 + 0 + + + 1 + 1 + 15 + 1 + 0 + 1 + 1 + 15 + 1 + 0 + 0 + + + 1 + 1 + 15 + 1 + 0 + 1 + 1 + 15 + 1 + 0 + 0 + + + 1 + 1 + 15 + 1 + 0 + 1 + 1 + 15 + 1 + 0 + 0 + + + 1 + 1 + 15 + 1 + 0 + 1 + 1 + 15 + 1 + 0 + 0 + + + 1 + 1 + 15 + 1 + 0 + 1 + 1 + 15 + 1 + 0 + 0 + + + 1 + 1 + 15 + 1 + 0 + 1 + 1 + 15 + 1 + 0 + 0 + + + 1 + 1 + 15 + 1 + 0 + 1 + 1 + 15 + 1 + 0 + 0 + + + 1 + 1 + 15 + 1 + 0 + 1 + 1 + 15 + 1 + 0 + 0 + + + 1 + 1 + 15 + 1 + 0 + 1 + 1 + 15 + 1 + 0 + 0 + + + 1 + 1 + 15 + 1 + 0 + 1 + 1 + 15 + 1 + 0 + 0 + + + 1 + 1 + 15 + 1 + 0 + 1 + 1 + 15 + 1 + 0 + 0 + + + 1 + 1 + 15 + 1 + 0 + 1 + 1 + 15 + 1 + 0 + 0 + + + 1 + 1 + 15 + 1 + 0 + 1 + 1 + 15 + 1 + 0 + 0 + + + 1 + 1 + 15 + 1 + 0 + 1 + 1 + 15 + 1 + 0 + 0 + + + 1 + 1 + 15 + 1 + 0 + 1 + 1 + 15 + 1 + 0 + 0 + + + 1 + 1 + 15 + 1 + 0 + 1 + 1 + 15 + 1 + 0 + 0 + + + 1 + 1 + 15 + 1 + 0 + 1 + 1 + 15 + 1 + 0 + 0 + + diff --git a/old/calib_data/Conf_default_MPA6_config1.xml b/old/calib_data/Conf_default_MPA6_config1.xml new file mode 100644 index 0000000..af5ac25 --- /dev/null +++ b/old/calib_data/Conf_default_MPA6_config1.xml @@ -0,0 +1,324 @@ + + + + 3 + 0 + 0 + 0 + 0 + 15 + 33 + + + 1 + 1 + 15 + 1 + 0 + 1 + 1 + 15 + 1 + 0 + 0 + + + 1 + 1 + 15 + 1 + 0 + 1 + 1 + 15 + 1 + 0 + 0 + + + 1 + 1 + 15 + 1 + 0 + 1 + 1 + 15 + 1 + 0 + 0 + + + 1 + 1 + 15 + 1 + 0 + 1 + 1 + 15 + 1 + 0 + 0 + + + 1 + 1 + 15 + 1 + 0 + 1 + 1 + 15 + 1 + 0 + 0 + + + 1 + 1 + 15 + 1 + 0 + 1 + 1 + 15 + 1 + 0 + 0 + + + 1 + 1 + 15 + 1 + 0 + 1 + 1 + 15 + 1 + 0 + 0 + + + 1 + 1 + 15 + 1 + 0 + 1 + 1 + 15 + 1 + 0 + 0 + + + 1 + 1 + 15 + 1 + 0 + 1 + 1 + 15 + 1 + 0 + 0 + + + 1 + 1 + 15 + 1 + 0 + 1 + 1 + 15 + 1 + 0 + 0 + + + 1 + 1 + 15 + 1 + 0 + 1 + 1 + 15 + 1 + 0 + 0 + + + 1 + 1 + 15 + 1 + 0 + 1 + 1 + 15 + 1 + 0 + 0 + + + 1 + 1 + 15 + 1 + 0 + 1 + 1 + 15 + 1 + 0 + 0 + + + 1 + 1 + 15 + 1 + 0 + 1 + 1 + 15 + 1 + 0 + 0 + + + 1 + 1 + 15 + 1 + 0 + 1 + 1 + 15 + 1 + 0 + 0 + + + 1 + 1 + 15 + 1 + 0 + 1 + 1 + 15 + 1 + 0 + 0 + + + 1 + 1 + 15 + 1 + 0 + 1 + 1 + 15 + 1 + 0 + 0 + + + 1 + 1 + 15 + 1 + 0 + 1 + 1 + 15 + 1 + 0 + 0 + + + 1 + 1 + 15 + 1 + 0 + 1 + 1 + 15 + 1 + 0 + 0 + + + 1 + 1 + 15 + 1 + 0 + 1 + 1 + 15 + 1 + 0 + 0 + + + 1 + 1 + 15 + 1 + 0 + 1 + 1 + 15 + 1 + 0 + 0 + + + 1 + 1 + 15 + 1 + 0 + 1 + 1 + 15 + 1 + 0 + 0 + + + 1 + 1 + 15 + 1 + 0 + 1 + 1 + 15 + 1 + 0 + 0 + + + 1 + 1 + 15 + 1 + 0 + 1 + 1 + 15 + 1 + 0 + 0 + + diff --git a/old/calibration_2MPA_new.py b/old/calibration_2MPA_new.py new file mode 100644 index 0000000..becb673 --- /dev/null +++ b/old/calibration_2MPA_new.py @@ -0,0 +1,523 @@ +import sys +from ROOT import TGraph, TCanvas, TLine +from classes import * +from array import array +from optparse import OptionParser + +parser = OptionParser() + +# General options + +parser.add_option('-m', '--MPA', metavar='N', type='int', +default = '1', +dest = 'mpanum', +help = 'Calibrate MPA N') + +parser.add_option('-r', '--resolution',metavar='N', type='int', +default = '1', +dest = 'resolution', +help = 'Only scan every N thresholds to speed up scan. Results in lower precision of TrimDACs') + +# CALDAC options (setting charge also enables calDAC) + +parser.add_option('-e', '--enable', action='store_true', +dest = 'calEnbl', +default = False, +help = 'Enable calibration') + +parser.add_option('-c', '--charge',metavar='C', type='int', +dest = 'calCharge', +help = 'Enable calibration with charge C (0 - 0xFF). If not set CalDAC is disabled.') + +parser.add_option('-n', '--number',metavar='N', type='int', +dest = 'calNum', +help = 'Number of calibration pulses') + +parser.add_option('-l', '--strobelength',metavar='N', type='int', +dest = 'calLen', +help = 'Length of calibration pulses') + +# Shutter length + +parser.add_option('-s', '--shutterdur',metavar='N', type='int', +default = '0xFFFF', +dest = 'shutterDur', +help = 'Shutter open time (0 - 0xFFFF).') + +(options, args) = parser.parse_args() + +if options.calEnbl == None and (options.calCharge != None or options.calNum != None or options.calLen !=None): # Check if user has forgotten to enable calibration + print "Calibration isn't enabled, setting charge, number or length will have no effect." + quit() +else: # Defaults for calibration but no explicit charge, number or strobe length + options.calCharge = 80 + options.calNum = 1000 + options.calLen = 40 + + +# Connection and GLIB +a = uasic(connection="file://connections_test.xml",device="board0") +glib = a._hw + +# Source all classes +mapsa = MAPSA(a) + +# Get all 6 MPAs and corresponding configs +mpa=[] +conf=[] + +for i in range(0,6): + mpa.append(MPA(glib,i+1)) + conf.append(mpa[i].config("data/Default_MPA.xml")) + +# Define MPA (1-6) (iMPA 2 or 5 for double assembly) + +mpaDict = {0:2,1:5} +iMPA = options.mpanum - 1 # Zero-indexed (from 0 to 5 on full assembly) + +# Set voltage steps of threshold DAC and trimming DAC (in mV/Step) +thrVoltStep = 1.456 +trimVoltStep = 3.75 + + +# File to which trimming values are written +trimFile = open('trimDac_MPA'+str(iMPA+1), 'w') + +# File to which THDAC values of falling edges after trimming are written +fallingEdgeFile = open('data/fallingEdgeTrimmed_MPA'+str(iMPA+1), 'w') + + +# Modify config + +glib.getNode("Control").getNode("MPA_clock_enable").write(0x1) +glib.dispatch() + +glib.getNode("Configuration").getNode("num_MPA").write(0x2) + +# Define default config + +defaultPixelCfg = {'PML':1,'ARL':1,'CEL':int(options.calEnbl),'CW':0,'PMR':1,'ARR':1,'CER':int(options.calEnbl),'SP':0,'SR':1,'TRIMDACL':30,'TRIMDACR':30} +defaultPeripheryCfg = {'OM':3,'RT':0,'SCW':0,'SH2':0,'SH1':0,'THDAC':0,'CALDAC':options.calCharge} +if options.calEnbl: + mapsa.daq().Strobe_settings(options.calNum,0x8F,options.calLen,40,cal=1) # Push number of pulses, delay between shutter open and first pulse, length of pulses, time between pulses, enable calibration (on GLIB) to GLIB + +# Upload +for key in defaultPeripheryCfg: + conf[iMPA].modifyperiphery(key,defaultPeripheryCfg[key]) +for pix in range(0,24): + for key in defaultPixelCfg: + conf[iMPA].modifypixel(pix + 1,key,defaultPixelCfg[key]) + +conf[iMPA].upload() +glib.getNode("Configuration").getNode("mode").write(0x1) +glib.dispatch() + + + +# Arrays to be filled by threshold scan +eventArray = [] +hitArray = [] +thrArray = [] +bxArray = [] +hitArrayCounter = [] + +# Start threshold scan +for thr in range(0,255, options.resolution): # Only every 'options.resolution'-steps, reflected in precision of falling edges after trimming + + #print thr + # Apply threshold + + conf[iMPA].modifyperiphery('THDAC',thr) + conf[iMPA].upload() + + glib.getNode("Configuration").getNode("mode").write(0x1) + conf[iMPA].spi_wait() # includes dispatch + + + ########################## + ####### Sequencer ######## + ########################## + # Opens shutter (mode = 0x0 single shutter, 0x1 four (buffers) consequitive shutter) + # Set shutter duration + # Write in first buffer (default and therefore not necessary to be defined) + # Readout has to be enabled in order to get the data. Default. + mapsa.daq().Sequencer_init(0, options.shutterDur ) + + counter = glib.getNode("Readout").getNode("Counter").getNode("MPA"+str(iMPA + 1)).getNode("buffer_1").readBlock(25) + glib.dispatch() + + + # Readout ripple counter + counterArray = [] + for x in range(1,len(counter)): # Skip header at [0] + counterArray.append(counter[x] & 0x7FFF) # Mask to select left pixel. First bit is not considered as this seems sometimes to be set erronously. (Lots of entries with 0b1000000000000000) + counterArray.append((counter[x] >> 16) & 0x7FFF) # Mask to select right pixel. Same as above. + + # Readout buffer (TRUE / FALSE : Wait for sequencer) + mem = mpa[mpaDict[iMPA]-1].daq().read_raw(1,1,True)[0] + + # Mem integer array to binary string in readable order (header,bx,pix) + binMemStr= "" + for i in range(0,216): + binMemStr = binMemStr + '{0:032b}'.format(mem[215-i]) + + # String to binary array + binMem = [binMemStr[x:x+72] for x in range(0,len(binMemStr),72)] + + # Get elements of binary string + hd = [] + bx = [] + pix = [] + for entry in binMem: + hd.append(entry[0:8]) + bx.append(entry[8:24]) + pix.append(entry[24:72]) + + # Count number of Events + nEvents = 0 + for event in hd: + if event == "11111111": + nEvents+=1 + + # Sum hits per pixel + sumPixHits = [0]*48 + for event in pix: + for i, ipix in enumerate(event): + sumPixHits[i]+=int(ipix) + + # bunch crossing from binary to int + bx=[int(ibx,2) for ibx in bx] + + eventArray.append(nEvents) + hitArray.append(sumPixHits) + thrArray.append(thr) + bxArray.append(bx) + hitArrayCounter.append(counterArray) + + +print "---END OF SCAN---" + +numOfEvents = [] +for ithr in bxArray: +# print 'Total clock cycles per threshold: %s' %max(ithr) # Events without a hit aren't saved but number of clock cycles until memory is full can be constructed from BX-Id + numOfEvents.append(max(ithr)) + + +print "Average number of clock cycles until memory is full: %s" %(sum(numOfEvents)/len(numOfEvents)) + + + +# Generate new list [[pix1_ThScan],[pix2_ThScan],..] from memory +pxlVsThrMem = [] +for ipix in range(0,len(hitArray[0])): + pxlVsThrMem.append([item[ipix] for item in hitArray]) + +# Generate new list [[pix1_ThScan],[pix2_ThScan],..] from ripple counter +pxlVsThrCounter = [] +for ipix in range(0,len(hitArrayCounter[0])): + pxlVsThrCounter.append([item[ipix] for item in hitArrayCounter]) + +# Generate graphs for each pixel +graphsMem = [] +for ipixScan in pxlVsThrMem: + graphsMem.append(TGraph(len(thrArray),array('d',thrArray),array('d',ipixScan))) + +graphsCounter = [] +maxHitsPerPix = [] # For scaling of graph +for ipixScan in pxlVsThrCounter: + graphsCounter.append(TGraph(len(thrArray),array('d',thrArray),array('d',ipixScan))) + maxHitsPerPix.append(max(ipixScan)) + + +# Draw graphs on canvas +c1 = TCanvas("graph","graph",1024,768) +c1.cd() + +for i,graph in enumerate(graphsMem): + graph.SetLineColor(3) + if i==0: + graph.SetTitle('Threshold Scan;Threshold (DAC);Number of Hits') + graph.GetYaxis().SetRangeUser(0,max(maxHitsPerPix)*1.1) + graph.Draw("APL") + else: + graph.Draw("PL") + +for graph in graphsCounter: + graph.Draw("PL") + +# Add line for nMax +line = TLine(0,max(eventArray),graphsMem[0].GetXaxis().GetXmax(),max(eventArray)) +line.SetLineColor(2) +line.Draw() + +print "Max number of events during scan: %s" %max(eventArray) + + +########################################### +########### Begin calibration ############# +########################################### + +# Find noisy pixels +noisyPixels = [] +for i,pxl in enumerate(pxlVsThrCounter): + if max(pxl) > 10000: + print "Pixel %s is very noisy at %s hits" %(i,max(pxl)) + noisyPixels.append(0) + else: + noisyPixels.append(1) + +# Find falling edges on which is calibrated +thrArrayFallingEdge = [] +for pxl in pxlVsThrCounter: + + pxlMax = max(pxl) + thresholdValueAndPxl = zip(thrArray,pxl) # Match thresholds to amount of hits and create list of tuples + + maxBin = pxl.index(pxlMax) # Find lowest threshold with maximum amount of hits + pxlRightOfPeak = thresholdValueAndPxl[maxBin:] # Get rid of rising edge (less hits than maxbin) + + halfMax = pxlMax/2 # Middle of falling edge + for threshold in pxlRightOfPeak: # Find first threshold with less hits than middle of falling edge, then break + if threshold[1] < halfMax: + thrArrayFallingEdge.append(threshold[0]) + break # Only one threshold is needed, leave loop + +print "Falling edges at %s" %list(enumerate(thrArrayFallingEdge, start=1)) + +pxlLowestThreshold = min(thrArrayFallingEdge) +trimDacToTheLeft = [(pxl - pxlLowestThreshold) * (thrVoltStep/trimVoltStep) for pxl in thrArrayFallingEdge] + +# Normalize trimDac and take into account that we started with trimDac set to 30 +trimDac = [max(0, (30 - int(round(pxlTrimDac)))) for pxlTrimDac in trimDacToTheLeft] + +print "Lower all trimDACs by %s" %min(trimDac) +# Set all trimDac as low as possible +trimDac = [pix - min(trimDac) for pix in trimDac] + +# Write trimDac values to MPA +for pix in range(0,24): + conf[iMPA].modifypixel(pix + 1,'TRIMDACL',trimDac[2*pix]) + conf[iMPA].modifypixel(pix + 1,'TRIMDACR',trimDac[2*pix + 1]) + +conf[iMPA].upload() +glib.getNode("Configuration").getNode("mode").write(0x1) +conf[iMPA].spi_wait() # includes dispatch + + +# Write twice to push config to Memory_OutConf to check what has been written +glib.getNode("Configuration").getNode("mode").write(0x1) +conf[iMPA].spi_wait() + +outConf = glib.getNode("Configuration").getNode("Memory_OutConf").getNode("MPA"+str(iMPA + 1)).getNode("config_1").readBlock(0x19) # Get written config +glib.dispatch() +readconf = [] +for pix in outConf: # Format this config to extract trimDac values +# print '{0:020b}'.format(pix) + readconf.append((pix >> 2) & 0b11111) + readconf.append((pix >> 12) & 0b11111) + +eventArray = [] +hitArray = [] +thrArray = [] +bxArray = [] +hitArrayCounter = [] + + +# Start threshold scan for calibrated pixels +for thr in range(0,255, options.resolution): + + #print thr + + # Apply threshold + + conf[iMPA].modifyperiphery('THDAC',thr) + conf[iMPA].upload() + + glib.getNode("Configuration").getNode("mode").write(0x1) + conf[iMPA].spi_wait() # includes dispatch + + # Start acquisition (sequencer) (Enable single (0) or four (4) consequitive buffers for shutter. Set Shutter duration and do final 'write' to push config to MPA) + mapsa.daq().Sequencer_init(0,options.shutterDur) + + counter = glib.getNode("Readout").getNode("Counter").getNode("MPA"+str(iMPA + 1)).getNode("buffer_1").readBlock(25) + glib.dispatch() + + counterArray = [] + for x in range(1,len(counter)): # Skip header at [0] + counterArray.append(counter[x] & 0x7FFF) # Mask to select left pixel. First bit is not considered as this seems sometimes to be set erronously. (Lots of entries with 0b1000000000000000) + counterArray.append((counter[x] >> 16) & 0x7FFF) # Mask to select right pixel. Same as above + + # Readout buffer (TRUE / FALSE : Wait for sequencer) + mem = mpa[mpaDict[iMPA]-1].daq().read_raw(1,1,True)[0] + + # Mem integer array to binary string in readable order (header,bx,pix) + binMemStr= "" + for i in range(0,216): + binMemStr = binMemStr + '{0:032b}'.format(mem[215-i]) + + # String to binary array + binMem = [binMemStr[x:x+72] for x in range(0,len(binMemStr),72)] + + # Get elements of binary string + hd = [] + bx = [] + pix = [] + for entry in binMem: + hd.append(entry[0:8]) + bx.append(entry[8:24]) + pix.append(entry[24:72]) + + # Count number of Events + nEvents = 0 + for event in hd: + if event == "11111111": + nEvents+=1 + + # Sum hits per pixel + sumPixHits = [0]*48 + for event in pix: + for i, ipix in enumerate(event): + sumPixHits[i]+=int(ipix) + + # bunch crossing from binary to int + bx=[int(ibx,2) for ibx in bx] + + eventArray.append(nEvents) + hitArray.append(sumPixHits) + thrArray.append(thr) + bxArray.append(bx) + hitArrayCounter.append(counterArray) + + +print "---END OF SCAN---" +numOfEvents = [] +for ithr in bxArray: +# print 'Cycles per threshold: %s' %max(ithr) + numOfEvents.append(max(ithr)) + + +print "Average number of clock cycles until memory is full: %s" %(sum(numOfEvents)/len(numOfEvents)) + +# Generate new list [[pix1_ThScan],[pix2_ThScan],..] from memory +pxlVsThrMem = [] +for ipix in range(0,len(hitArray[0])): + pxlVsThrMem.append([item[ipix] for item in hitArray]) + +# Generate new list [[pix1_ThScan],[pix2_ThScan],..] from ripple counter +pxlVsThrCounter = [] +for ipix in range(0,len(hitArrayCounter[0])): # Loop over pixels + pxlVsThrCounter.append([item[ipix] for item in hitArrayCounter]) + +# Generate graphs for each pixel +graphsMem = [] + +for ipixScan in pxlVsThrMem: + graphsMem.append(TGraph(len(thrArray),array('d',thrArray),array('d',ipixScan))) + +graphsCounter = [] +maxHitsPerPix = [] +for ipixScan in pxlVsThrCounter: + graphsCounter.append(TGraph(len(thrArray),array('d',thrArray),array('d',ipixScan))) + maxHitsPerPix.append(max(ipixScan)) + + +# Draw graphs on canvas +c2 = TCanvas("graph2","graph",1024,768) +c2.cd() + +for i,graph in enumerate(graphsMem): + graph.SetLineColor(3) + if i==0: + graph.SetTitle('Threshold Scan;Threshold (DAC);Number of Hits') + graph.GetYaxis().SetRangeUser(0,max(maxHitsPerPix)*1.1) + graph.Draw("APL") + else: + graph.Draw("PL") + +for graph in graphsCounter: + graph.Draw("PL") + +# Add line for nMax +line = TLine(0,max(eventArray),graphsMem[0].GetXaxis().GetXmax(),max(eventArray)) +line.SetLineColor(2) +line.Draw() + +print "Max number of events during scan: %s" %max(eventArray) + + +#################################################################### +########### Check if calibration was successful #################### +#################################################################### + +# Find pixel with lowest threshold +thrArrayFallingEdge = [] +thrArrayPeak = [] + +for pxl in pxlVsThrCounter: + + thresholdValueAndPxl = zip(thrArray,pxl) # Match thresholds to amount of hits and create list of tuples + pxlMax = max(pxl) + + maxBin = pxl.index(pxlMax) # Find lowest threshold with maximum amount of hits + pxlRightOfPeak = thresholdValueAndPxl[maxBin:] # Get rid of rising edge (less hits than maxbin) + + halfMax = pxlMax/2 # Middle of falling edge + for threshold in pxlRightOfPeak: # Find first threshold with less hits than middle of falling edge, then break + if threshold[1] < halfMax: + thrArrayFallingEdge.append(threshold[0]) + break + + ## Find peak + thrArrayPeak.append(maxBin) + +meanThrArrayPeak = sorted(thrArrayPeak)[len(thrArrayPeak)/2] # Mean threshold of noise + +print "Falling edges at %s" %list(enumerate(thrArrayFallingEdge, start=1)) # Enumerate to make matching value to pixel number easier + +untrimmableMask = [] # Mask of untrimmable pixels (e.g. trimDac is too small), 1 is ok and 0 is untrimmable +for i, pix in enumerate(thrArrayFallingEdge): + if abs(pix - pxlLowestThreshold) > 5: + print "Untrimmable pixel %s with falling edge at %s" %(i + 1,pix) + untrimmableMask.append(0) # Mask this pixel as it can't be trimmed far enough + else: + untrimmableMask.append(1) + +# Write twice to push config to Memory_OutConf to check what has been written +glib.getNode("Configuration").getNode("mode").write(0x1) +conf[iMPA].spi_wait() + +outConf = glib.getNode("Configuration").getNode("Memory_OutConf").getNode("MPA"+str(iMPA + 1)).getNode("config_1").readBlock(0x19) # Get written config +glib.dispatch() +readconf = [] +for pix in outConf: # Format this config to extract trimDac values +# print '{0:020b}'.format(pix) + readconf.append((pix >> 2) & 0b11111) + readconf.append((pix >> 12) & 0b11111) + +#print "Written Trim DAC: %s" %list(enumerate(readconf[2:], start=1)) # Skip periphery config (first two entries) + + +# Write trimDac files to file 'trimDac' for later use +for pxl in trimDac: + trimFile.write(str(pxl)) + trimFile.write('\n') +trimFile.close() + +# Write falling edges of trimmed peaks to file to do detection of untrimmable pixels +for pxl in thrArrayFallingEdge: + fallingEdgeFile.write(str(pxl)) + fallingEdgeFile.write('\n') +fallingEdgeFile.close() + +# Write graph with calibrated pixels to file + +c2.Print('plots/MPA_'+str(iMPA+1)+'_Calibration_post.pdf', 'pdf') + + +print "Trimming on threshold %s" %pxlLowestThreshold +print "Untrimmable pixel mask: %s" %untrimmableMask +print "Noisy pixel mask: %s" %noisyPixels +print "Trimming bits: %s" %list(enumerate(trimDac, start=1)) +print "Average peak at %s" %(meanThrArrayPeak) + +raw_input("Press any key to exit") diff --git a/old/calibration_rewrite_moritz.py b/old/calibration_rewrite_moritz.py new file mode 100644 index 0000000..63781ff --- /dev/null +++ b/old/calibration_rewrite_moritz.py @@ -0,0 +1,405 @@ +from classes import * +from xml.dom import minidom +import xml.etree.ElementTree +from xml.etree.ElementTree import Element, SubElement, Comment +import sys, select, os, array +from array import array +import ROOT +from ROOT import TGraph, TCanvas, gPad, TFile + +import numpy as np + +import matplotlib.pyplot as plt +from matplotlib.pyplot import show, plot + +from optparse import OptionParser + + +######## Configuration start ####### + +parser = OptionParser() +parser.add_option('-s', '--setting', metavar='F', type='string', action='store', +default = 'none', +dest = 'setting', +help = 'settings ie default, calibration, testbeam etc') + +parser.add_option('-c', '--charge', metavar='F', type='int', action='store', +default = 70, +dest = 'calCharge', +help = 'Charge for caldac') + +parser.add_option('-w', '--shutterdur', metavar='F', type='int', action='store', +default = 0xFFFFF, +dest = 'shutterDur', +help = 'shutter duration') + + +parser.add_option('-n', '--number', metavar='F', type='int', action='store', +default = 0x5, +dest = 'calNumber', +help = 'number of calstrobe pulses to send') + +parser.add_option('-l', '--strobelength', metavar='F', type='int', action='store', +default = 50, +dest = 'strobeLen', +help = 'length of strobe') + +parser.add_option('-i', '--strobedist', metavar='F', type='int', action='store', +default = 50, +dest = 'strobeDist', +help = 'time between strobes') + +parser.add_option('-d', '--strobedelay', metavar='F', type='int', action='store', +default = 0xFF, +dest = 'strobeDel', +help = 'time before first strobe') + +parser.add_option('-r', '--resolution ', metavar='F', type='int', action='store', +default = '1', +dest = 'res', +help = 'resolution, skip each r-th threshold step to speed up threshold scan') + +parser.add_option('-y', '--string ', metavar='F', type='string', action='store', +default = '', +dest = 'string', +help = 'extra string') + + +(options, args) = parser.parse_args() + + +shutterMode = 0x0 # shutter options + + +buffnum = 1 + +if options.setting=='calibration': + calEnbl = 1 # Set Calibration Enable bit +else: + calEnbl = 0 +signlPlt = 0 # Signal polarity + + + +######## Configuration end #### + +a = uasic(connection="file://connections_test.xml",device="board0") +mapsa = MAPSA(a) +read = a._hw.getNode("Control").getNode('firm_ver').read() +a._hw.dispatch() +print "Running firmware version " + str(read) + +a._hw.getNode("Control").getNode("MPA_clock_enable").write(0x1) +a._hw.dispatch() + +config = mapsa.config(Config=1,string='default') # load default cfg +config.upload() + + + + + +confdict = {'OM':[3]*6,'RT':[0]*6,'SCW':[0]*6,'SH2':[0]*6,'SH1':[0]*6,'THDAC':[0]*6,'CALDAC':[options.calCharge]*6,'PML':[1]*6,'ARL':[1]*6,'CEL':[calEnbl]*6,'CW':[0]*6,'PMR':[1]*6,'ARR':[1]*6,'CER':[calEnbl]*6,'SP':[signlPlt]*6,'SR':[1]*6,'TRIMDACL':[30]*6,'TRIMDACR':[30]*6} +config.modifyfull(confdict) + +mapsa.daq().Strobe_settings(options.calNumber,options.strobeDel,options.strobeLen,options.strobeDist,cal=calEnbl) + +x1 = array('d') +y1 = [] +for x in range(0,256): # start threshold scan + if x%options.res!=0: + continue # skip some threshold values due to resolution option + if x%10==0: + print "THDAC " + str(x) + + config.modifyperiphery('THDAC',[x]*6) # change threshold for all 6 MPAs + config.upload() + config.write() + + mapsa.daq().Sequencer_init(shutterMode,options.shutterDur) + + pix,mem = mapsa.daq().read_data(buffnum) # pix = [[MPA1_header,MPA1_header,MPA1_pix1,..,MPA1_pix48],..,[MPA6]] + +# pixMatrixNoHeaders = np.delete(np.array(pix), [:2] , 1) # Create numpy array and delete headers + + + + ipix = 0 + + for mpa in pix: # Loop over MPAs + + del mpa[0:2] # Drop double header + y1.append([]) # Append an empty array + y1[ipix].append(array('d',mpa)) # Append array of 48 pixels for each MPA and THDAC [MPA1[THDAC1[Pix1,..,Pix48] , .. , THDAC256[Pix1,..,Pix48]],..,MPA6[],[][]..] + + ipix += 1 + + x1.append(x) # Array of THDAC 0-255 + + +print "Generating nominal per pixel trimDacPix values" + +calibconfs = config._confs +calibconfsxmlroot = config._confsxmlroot + + +c1 = TCanvas('c1', '', 700, 900) +c1.Divide(2,3) +thldSteps = np.array(x1) +trimDacMAPSA = [] +yarrv = [] +grarr = [] +xdvals = [] + +for i in range(0,6): # loop over MPA + backup=TFile("plots/backup_preCalibration_"+options.string+"_MPA"+str(i)+".root","recreate") + calibconfxmlroot = calibconfsxmlroot[i] + xdvals.append(0.) + c1.cd(i+1) + trimDacMPA = [] # Trimming values for each pixel for one MPA + yarr = np.array(y1[i]) # [ THDAC1[Pix1,..,Pix48] , .. , THDAC256[Pix1,..,Pix48] ] + grarr.append([]) + gr1 = [] + yarrv.append(yarr) # Equivalent to y1 without empty brackets at the end + + + for pxl in range(0,len(yarr[0,:])): # loop over 48 pixels + onePixAllThlds = yarr[:,pxl] # loop over 256 THDAC for one pixel + + + if max(onePixAllThlds)==0: + print "zero" + gr1.append(TGraph(len(x1)-1,array('d',thldSteps),array('d',onePixAllThlds))) + if pxl==0: # draw curve for first pixel + + gr1[pxl].SetTitle(';DAC Value (1.456 mV);Counts (1/1.456)') + grarr[i].append(gr1[pxl]) + grarr[i][pxl].Draw() + gr1[pxl].Write(str(pxl)) + else: # draw other pixels + grarr[i].append(gr1[pxl]) + grarr[i][pxl].Draw('same') + gr1[pxl].Write(str(pxl)) + gPad.Update() + + halfmax = max(onePixAllThlds)/2.0 + maxbin = np.where(onePixAllThlds==max(onePixAllThlds)) # array with threshold with most hits for single pixel, given as nested 2d array with usually 1 entry + + for thldValue in range(0,len(thldSteps)-1): # Loop over all THDAC + + if (onePixAllThlds[thldValue + 1] - halfmax)<0.0 and thldValue > maxbin[0][0]: # Falling edge right before half maximum (first condition selects only thresholds with less hits than half maximum, second condition selects right side of peak. Runs only once due to break.) + if pxl%2==0: # get trimming value of left pixel (config always for two pixels (32bit)) (initially set to 30) + prev_trim = int(calibconfxmlroot[(pxl)/2+1].find('TRIMDACL').text) + else: # same for right pixel + prev_trim = int(calibconfxmlroot[(pxl+1)/2].find('TRIMDACR').text) + + diffToHalfMaxFromLeft = abs(onePixAllThlds[thldValue] - halfmax) + diffToHalfMaxFromRight = abs(onePixAllThlds[thldValue +1] - halfmax) + xdacval = thldValue + diffToHalfMaxFromRight/(diffToHalfMaxFromLeft + diffToHalfMaxFromRight) + + trimDacPix = 31 + prev_trim - int(round(xdacval*1.456/3.75)) # x*th_step/trim_step . Result can be bigger than 31 which hardware can't do, this will be checked later. + xdvals[i] += xdacval*1.456/3.75 + trimDacMPA.append(trimDacPix) + break # go to next pixel (pixel trimmed) + + if thldValue==len(thldSteps)-2: # No curve, save old value + if pxl%2==0: # Left pixel + prev_trim = int(calibconfxmlroot[(pxl)/2+1].find('TRIMDACL').text) + else: # Right pixel + prev_trim = int(calibconfxmlroot[(pxl+1)/2].find('TRIMDACR').text) + + trimDacPix = int(prev_trim) + trimDacMPA.append(trimDacPix) + print "UNTRIMMED" # no trimmable threshold / no falling edge found + break # go to next pixel (pixel not trimmed in relation to previous pixel) + trimDacMAPSA.append(trimDacMPA) # All MPAs (MAPSA) +print trimDacMAPSA +ave = 0 +for x in xdvals: + ave+=x/48. # average per MPA +ave/=6. # average of all MPAs ### MUST BE CHANGED TO ACCOUNT FOR DIFFERENT NUMBER OF MPAs! + +# Calculate an offset for each MPA to account for differences +offset = [] +for i in range(0,6): + ave15 = 0 + for j in trimDacMAPSA[i]: + ave15+=j + ave15/=len(trimDacMAPSA[i]) + mpacorr = xdvals[i]/48. - ave + offset.append( 15 - int(round(ave15 + mpacorr))) + +colors = [[],[],[],[],[],[]] +for iy1 in range(0,len(yarrv[0][0,:])): # Loop over pixels twice + upldac = [] + for i in range(0,6): + trimDacMPA = trimDacMAPSA[i] + upldac.append(trimDacMPA[iy1]+offset[i]) + + ## Normalize trimming values uploaded to MPA to fit in 5-bit TRIMDAC + for u in range(0,len(upldac)): + upldac[u] = max(0,upldac[u]) + upldac[u] = min(31,upldac[u]) + if upldac[u]==31: + colors[u].append(2) # red curve (can't trim enough because TRIMDAC has only 5 bit) + elif upldac[u]==0: + colors[u].append(4) # blue curve (can't trim enough, wrong direction) + else: + colors[u].append(1) # black curve + + if iy1%2==0: + config.modifypixel((iy1)/2+1,'TRIMDACL',upldac) + else: + config.modifypixel((iy1+1)/2,'TRIMDACR',upldac) + + +c1.Print('plots/Scurve_Calibration'+options.string+'_pre.root', 'root') +c1.Print('plots/Scurve_Calibration'+options.string+'_pre.pdf', 'pdf') +c1.Print('plots/Scurve_Calibration'+options.string+'_pre.png', 'png') +config.modifyperiphery('THDAC',[100]*6) +config.upload() +config.write() +for i in range(0,6): + xmlrootfile = config._confsxmltree[i] + print xmlrootfile + a = config._confsxmlroot[i] + print "writing data/Conf_calibrated_MPA"+str(i+1)+"_config1.xml" + xmlrootfile.write("data/Conf_calibrated_MPA"+str(i+1)+"_config1.xml") + + +### Same threshold scan with calibrated pixel +print "Testing Calibration" + +config1 = mapsa.config(Config=1,string='calibrated') +config1.upload() + +config1.modifyperiphery('OM',[3]*6) +config1.modifyperiphery('RT',[0]*6) +config1.modifyperiphery('SCW',[0]*6) +config1.modifyperiphery('SH2',[0]*6) +config1.modifyperiphery('SH1',[0]*6) +config1.modifyperiphery('THDAC',[0]*6) +config1.modifyperiphery('CALDAC', [options.calCharge]*6) +for x in range(1,25): + config1.modifypixel(x,'PML', [1]*6) + config1.modifypixel(x,'ARL', [1]*6) + config1.modifypixel(x,'CEL', [calEnbl]*6) + config1.modifypixel(x,'CW', [0]*6) + config1.modifypixel(x,'PMR', [1]*6) + config1.modifypixel(x,'ARR', [1]*6) + config1.modifypixel(x,'CER', [calEnbl]*6) + config1.modifypixel(x,'SP', [signlPlt]*6) + config1.modifypixel(x,'SR', [1]*6) + + +config1.write() + + + + +x1 = array('d') +y1 = [] + +for x in range(0,256): + if x%options.res!=0: + continue + if x%10==0: +# print trimDacMPA + print "THDAC " + str(x) + + config1.modifyperiphery('THDAC',[x]*6) + config1.upload() + config1.write() + + mapsa.daq().Sequencer_init(shutterMode,options.shutterDur) + pix,mem = mapsa.daq().read_data(buffnum) + ipix=0 + + for p in pix: + + p.pop(0) + p.pop(0) + y1.append([]) + y1[ipix].append(array('d',p)) + + ipix+=1 + x1.append(x) + + +c2 = TCanvas('c2', '', 700, 900) +c2.Divide(2,3) + +thldSteps = np.array(x1) +yarrv = [] +gr2arr = [] +means = [] +########## Plot calibrated thresholds + +allMPAsFallingEdges = [] +for i in range(0,6): + backup=TFile("plots/backup_postCalibration_"+options.string+"_MPA"+str(i)+".root","recreate") + + c2.cd(i+1) + yarr = np.array(y1[i]) + gr2arr.append([]) + gr2 = [] + means.append(0.) + yarrv.append(yarr) + for iy1 in range(0,len(yarr[0,:])): + onePixAllThlds = yarr[:,iy1] + + gr2.append(TGraph(len(x1)-1,array('d',thldSteps),array('d',onePixAllThlds))) + + if iy1==0: + + gr2[iy1].SetTitle(';DAC Value (1.456 mV);Counts (1/1.456)') + gr2arr[i].append(gr2[iy1]) + gr2arr[i][iy1].SetLineColor(colors[i][iy1]) + gr2arr[i][iy1].Draw() + gr2[iy1].Write(str(iy1)) + + else: + gr2arr[i].append(gr2[iy1]) + gr2arr[i][iy1].SetLineColor(colors[i][iy1]) + gr2arr[i][iy1].Draw('same') + gr2[iy1].Write(str(iy1)) + gPad.Update() + means[i]+=gr2[iy1].GetMean(1) + + + +###################################################### +########## Get falling edges after calibration ####### +###################################################### + + # Find pixel with lowest threshold + thrArrayFallingEdge = [] + pxlVsThrCounter = [] + for i in range(0,len(yarr[0,:])): # loop over pixels + pxlVsThrCounter.append(yarr[:,i].tolist()) + for pxl in pxlVsThrCounter: + ## Find falling edge + halfMax = max(pxl)/2 + pxlDiff = [abs(x - halfMax) for x in pxl] # Difference of hits for each threshold to half maximum of hits + thrRightOfHalfMaxFalling = max([ # Highest threshold to get threshold right after halfmax of falling edge + pxlDiff.index(pxlDiffI) # Match differences of hits to threshold values + for pxlDiffI in sorted(pxlDiff)[:4] # Four threshold values with smallest distance to halfmax (left/right of rising edge and left/right of falling edge) + ]) + thrArrayFallingEdge.append(thrRightOfHalfMaxFalling) + allMPAsFallingEdges.append(thrArrayFallingEdge) + +print "Falling edges at %s" %allMPAsFallingEdges + +print 'Means' +for m in means: + print m/48. + +c2.Print('plots/Scurve_Calibration'+options.string+'_post.root', 'root') +c2.Print('plots/Scurve_Calibration'+options.string+'_post.pdf', 'pdf') +c2.Print('plots/Scurve_Calibration'+options.string+'_post.png', 'png') + +print "" +print "Done" + + + diff --git a/old/calibration_rewrite_moritz_second_scan.py b/old/calibration_rewrite_moritz_second_scan.py new file mode 100644 index 0000000..af2559f --- /dev/null +++ b/old/calibration_rewrite_moritz_second_scan.py @@ -0,0 +1,476 @@ +from classes import * +from xml.dom import minidom +import xml.etree.ElementTree +from xml.etree.ElementTree import Element, SubElement, Comment +import sys, select, os, array +from array import array +import ROOT +from ROOT import TLine, TGraph, TCanvas, gPad, TFile + +import numpy as np + +import matplotlib.pyplot as plt +from matplotlib.pyplot import show, plot + +from optparse import OptionParser + + +######## Configuration start ####### + +parser = OptionParser() +parser.add_option('-s', '--setting', metavar='F', type='string', action='store', +default = 'none', +dest = 'setting', +help = 'settings ie default, calibration, testbeam etc') + +parser.add_option('-c', '--charge', metavar='F', type='int', action='store', +default = 70, +dest = 'calCharge', +help = 'Charge for caldac') + +parser.add_option('-w', '--shutterdur', metavar='F', type='int', action='store', +default = 0xFFFFF, +dest = 'shutterDur', +help = 'shutter duration') + + +parser.add_option('-n', '--number', metavar='F', type='int', action='store', +default = 0x5, +dest = 'calNumber', +help = 'number of calstrobe pulses to send') + +parser.add_option('-l', '--strobelength', metavar='F', type='int', action='store', +default = 50, +dest = 'strobeLen', +help = 'length of strobe') + +parser.add_option('-i', '--strobedist', metavar='F', type='int', action='store', +default = 50, +dest = 'strobeDist', +help = 'time between strobes') + +parser.add_option('-d', '--strobedelay', metavar='F', type='int', action='store', +default = 0xFF, +dest = 'strobeDel', +help = 'time before first strobe') + +parser.add_option('-r', '--resolution ', metavar='F', type='int', action='store', +default = '1', +dest = 'res', +help = 'resolution, skip each r-th threshold step to speed up threshold scan') + +parser.add_option('-y', '--string ', metavar='F', type='string', action='store', +default = '', +dest = 'string', +help = 'extra string') + + +(options, args) = parser.parse_args() + + +shutterMode = 0x0 # shutter options + + +buffnum = 1 + +if options.setting=='calibration': + calEnbl = 1 # Set Calibration Enable bit +else: + calEnbl = 0 +signlPlt = 0 # Signal polarity + + + +######## Configuration end #### + +a = uasic(connection="file://connections_test.xml",device="board0") +mapsa = MAPSA(a) +read = a._hw.getNode("Control").getNode('firm_ver').read() +a._hw.dispatch() +print "Running firmware version " + str(read) + +a._hw.getNode("Control").getNode("MPA_clock_enable").write(0x1) +a._hw.dispatch() + +config = mapsa.config(Config=1,string='default') # load default cfg +config.upload() + + + + + +confdict = {'OM':[3]*6,'RT':[0]*6,'SCW':[0]*6,'SH2':[0]*6,'SH1':[0]*6,'THDAC':[0]*6,'CALDAC':[options.calCharge]*6,'PML':[1]*6,'ARL':[1]*6,'CEL':[calEnbl]*6,'CW':[0]*6,'PMR':[1]*6,'ARR':[1]*6,'CER':[calEnbl]*6,'SP':[signlPlt]*6,'SR':[1]*6,'TRIMDACL':[30]*6,'TRIMDACR':[30]*6} +config.modifyfull(confdict) + +mapsa.daq().Strobe_settings(options.calNumber,options.strobeDel,options.strobeLen,options.strobeDist,cal=calEnbl) + +x1 = array('d') +y1 = [] +for x in range(0,256): # start threshold scan + if x%options.res!=0: + continue # skip some threshold values due to resolution option + if x%10==0: + print "THDAC " + str(x) + + config.modifyperiphery('THDAC',[x]*6) # change threshold for all 6 MPAs + config.upload() + config.write() + + mapsa.daq().Sequencer_init(shutterMode,options.shutterDur) + + pix,mem = mapsa.daq().read_data(buffnum) # pix = [[MPA1_header,MPA1_header,MPA1_pix1,..,MPA1_pix48],..,[MPA6]] + +# pixMatrixNoHeaders = np.delete(np.array(pix), [:2] , 1) # Create numpy array and delete headers + + + + ipix = 0 + + for mpa in pix: # Loop over MPAs + + del mpa[0:2] # Drop double header + y1.append([]) # Append an empty array + y1[ipix].append(array('d',mpa)) # Append array of 48 pixels for each MPA and THDAC [MPA1[THDAC1[Pix1,..,Pix48] , .. , THDAC256[Pix1,..,Pix48]],..,MPA6[],[][]..] + + ipix += 1 + + x1.append(x) # Array of THDAC 0-255 + + +print "Generating nominal per pixel trimDacPix values" + +calibconfs = config._confs +calibconfsxmlroot = config._confsxmlroot + + +c1 = TCanvas('c1', '', 700, 900) +c1.Divide(2,3) +thldSteps = np.array(x1) +trimDacMAPSA = [] +yarrv = [] +grarr = [] +xdvals = [] + +for i in range(0,6): # loop over MPA + backup=TFile("plots/backup_preCalibration_"+options.string+"_MPA"+str(i)+".root","recreate") + calibconfxmlroot = calibconfsxmlroot[i] + xdvals.append(0.) + c1.cd(i+1) + trimDacMPA = [] # Trimming values for each pixel for one MPA + yarr = np.array(y1[i]) # [ THDAC1[Pix1,..,Pix48] , .. , THDAC256[Pix1,..,Pix48] ] + grarr.append([]) + gr1 = [] + yarrv.append(yarr) # Equivalent to y1 without empty brackets at the end + + + for pxl in range(0,len(yarr[0,:])): # loop over 48 pixels + onePixAllThlds = yarr[:,pxl] # loop over 256 THDAC for one pixel + + + if max(onePixAllThlds)==0: + print "zero" + gr1.append(TGraph(len(x1)-1,array('d',thldSteps),array('d',onePixAllThlds))) + if pxl==0: # draw curve for first pixel + + gr1[pxl].SetTitle(';DAC Value (1.456 mV);Counts (1/1.456)') + grarr[i].append(gr1[pxl]) + grarr[i][pxl].Draw() + gr1[pxl].Write(str(pxl)) + else: # draw other pixels + grarr[i].append(gr1[pxl]) + grarr[i][pxl].Draw('same') + gr1[pxl].Write(str(pxl)) + gPad.Update() + + halfmax = max(onePixAllThlds)/2.0 + maxbin = np.where(onePixAllThlds==max(onePixAllThlds)) # array with threshold with most hits for single pixel, given as nested 2d array with usually 1 entry + + for thldValue in range(0,len(thldSteps)-1): # Loop over all THDAC + + if (onePixAllThlds[thldValue + 1] - halfmax)<0.0 and thldValue > maxbin[0][0]: # Falling edge right before half maximum (first condition selects only thresholds with less hits than half maximum, second condition selects right side of peak. Runs only once due to break.) + if pxl%2==0: # get trimming value of left pixel (config always for two pixels (32bit)) (initially set to 30) + prev_trim = int(calibconfxmlroot[(pxl)/2+1].find('TRIMDACL').text) + else: # same for right pixel + prev_trim = int(calibconfxmlroot[(pxl+1)/2].find('TRIMDACR').text) + + diffToHalfMaxFromLeft = abs(onePixAllThlds[thldValue] - halfmax) + diffToHalfMaxFromRight = abs(onePixAllThlds[thldValue +1] - halfmax) + xdacval = thldValue #+ diffToHalfMaxFromRight/(diffToHalfMaxFromLeft + diffToHalfMaxFromRight) + + trimDacPix = 31 + prev_trim - int(round(xdacval*1.456/3.75)) # x*th_step/trim_step . Result can be bigger than 31 which hardware can't do, this will be checked later. + xdvals[i] += xdacval*1.456/3.75 + trimDacMPA.append(trimDacPix) + break # go to next pixel (pixel trimmed) + + if thldValue==len(thldSteps)-2: # No curve, save old value + if pxl%2==0: # Left pixel + prev_trim = int(calibconfxmlroot[(pxl)/2+1].find('TRIMDACL').text) + else: # Right pixel + prev_trim = int(calibconfxmlroot[(pxl+1)/2].find('TRIMDACR').text) + + trimDacPix = int(prev_trim) + trimDacMPA.append(trimDacPix) + print "UNTRIMMED" # no trimmable threshold / no falling edge found + break # go to next pixel (pixel not trimmed in relation to previous pixel) + trimDacMAPSA.append(trimDacMPA) # All MPAs (MAPSA) +print trimDacMAPSA +ave = 0 +for x in xdvals: + ave+=x/48. # average per MPA +ave/=6. # average of all MPAs ### MUST BE CHANGED TO ACCOUNT FOR DIFFERENT NUMBER OF MPAs! + +# Calculate an offset for each MPA to account for differences +offset = [] +for i in range(0,6): + ave15 = 0 + for j in trimDacMAPSA[i]: + ave15+=j + ave15/=len(trimDacMAPSA[i]) + mpacorr = xdvals[i]/48. - ave + offset.append( 15 - int(round(ave15 + mpacorr))) + +colors = [[],[],[],[],[],[]] +for iy1 in range(0,len(yarrv[0][0,:])): # Loop over pixels twice + upldac = [] + for i in range(0,6): + trimDacMPA = trimDacMAPSA[i] + upldac.append(trimDacMPA[iy1]+offset[i]) + + ## Normalize trimming values uploaded to MPA to fit in 5-bit TRIMDAC + for u in range(0,len(upldac)): + upldac[u] = max(0,upldac[u]) + upldac[u] = min(31,upldac[u]) + if upldac[u]==31: + colors[u].append(2) # red curve (can't trim enough because TRIMDAC has only 5 bit) + elif upldac[u]==0: + colors[u].append(4) # blue curve (can't trim enough, wrong direction) + else: + colors[u].append(1) # black curve + + if iy1%2==0: + config.modifypixel((iy1)/2+1,'TRIMDACL',upldac) + else: + config.modifypixel((iy1+1)/2,'TRIMDACR',upldac) + + +config1 = mapsa.config(Config=1,string='calibrated') +config1.upload() + +config1.modifyperiphery('OM',[3]*6) +config1.modifyperiphery('RT',[0]*6) +config1.modifyperiphery('SCW',[0]*6) +config1.modifyperiphery('SH2',[0]*6) +config1.modifyperiphery('SH1',[0]*6) +config1.modifyperiphery('THDAC',[0]*6) +config1.modifyperiphery('CALDAC', [options.calCharge]*6) +for x in range(1,25): + config1.modifypixel(x,'PML', [1]*6) + config1.modifypixel(x,'ARL', [1]*6) + config1.modifypixel(x,'CEL', [calEnbl]*6) + config1.modifypixel(x,'CW', [0]*6) + config1.modifypixel(x,'PMR', [1]*6) + config1.modifypixel(x,'ARR', [1]*6) + config1.modifypixel(x,'CER', [calEnbl]*6) + config1.modifypixel(x,'SP', [signlPlt]*6) + config1.modifypixel(x,'SR', [1]*6) + + +config1.write() + +##################################################################################################################### +################### Start threshold scan for calibrated pixels (Moritz' falling edge detection) ##################### +##################################################################################################################### +glib = a._hw +mpa = [] +conf = [] +for i in range(0,6): + mpa.append(MPA(glib,i+1)) + conf.append(mpa[i].config("data/Default_MPA.xml")) +glib.getNode("Configuration").getNode("num_MPA").write(0x6) + +hitArrayCounter = [] +thrArray = [] +iMPA = 0 +for thr in range(0,255): + + if thr%1 == 0: + #print thr + thrArray.append(thr) + # Apply threshold + config1.modifyperiphery('THDAC',[thr]*6) + config1.upload() + config1.write() + # Start acquisition (sequencer) (Enable single (0) or four (4) consequitive buffers for shutter. Set Shutter duration and do final 'write' to push config to MPA) + mapsa.daq().Sequencer_init(0,options.shutterDur) + + counter = glib.getNode("Readout").getNode("Counter").getNode("MPA"+str(iMPA + 1)).getNode("buffer_1").readBlock(25) + glib.dispatch() + counterArray = [] + for x in range(1,len(counter)): # Skip header at [0] + counterArray.append(counter[x] & 0xFFFF) # Mask to select left pixel + counterArray.append((counter[x] >> 16) & 0xFFFF) # Mask to select right pixel + hitArrayCounter.append(counterArray) + print counterArray + + +print "---END OF SCAN---" + + +# Generate new list [[pix1_ThScan],[pix2_ThScan],..] from ripple counter +pxlVsThrCounter = [] +for ipix in range(0,len(hitArrayCounter[0])): + pxlVsThrCounter.append([item[ipix] for item in hitArrayCounter]) + +# Generate graphs for each pixel +graphsCounter = [] +maxHitsPerPix = [] # For scaling of graph +for ipixScan in pxlVsThrCounter: + graphsCounter.append(TGraph(len(thrArray),array('d',thrArray),array('d',ipixScan))) + maxHitsPerPix.append(max(ipixScan)) + +# Draw graphs on canvas +c2 = TCanvas("graph2","graph2",700,900) +c2.cd() + +for i,graph in enumerate(graphsCounter): + if i == 0: + graph.Draw("APL") + graph.GetYaxis().SetRangeUser(0,max(maxHitsPerPix)*1.1) + else: + graph.Draw("PL") + + +## Check if calibration was successful ## + +# Find pixel with lowest threshold +thrArrayFallingEdge = [] +thrArrayPeak = [] +for pxl in pxlVsThrCounter: + + pxl = [hits if hits < 20000 else 0 for hits in pxl] # Exclude extremely high noise as that is not plausible. Glib error? + + ## Find falling edge + halfMax = max(pxl)/2 + pxlDiff = [abs(x - halfMax) for x in pxl] # Difference of hits for each threshold to half maximum of hits + thrRightOfHalfMaxFalling = max([ # Highest threshold to get threshold right after halfmax of falling edge + thrArray[pxlDiff.index(pxlDiffI)] # Match differences of hits to threshold values + for pxlDiffI in sorted(pxlDiff)[:4] # Four threshold values with smallest distance to halfmax (left/right of rising edge and left/right of falling edge) + ]) + thrArrayFallingEdge.append(thrRightOfHalfMaxFalling) + + ## Find peak + pxlDiff = [thr - max(pxl) for thr in pxl] + thrArrayPeak.append(thrArray[pxlDiff.index(0)]) + +print "Falling edges at %s" %thrArrayFallingEdge + +########################################################################################## +#################### Plot calibrated pixels (Nash's edge detection) ###################### +########################################################################################## + +print "Testing Calibration (NASH)" + +x1 = array('d') +y1 = [] + +for x in range(0,256): + if x%options.res!=0: + continue +# if x%10==0: +# print trimDacMPA +# print "THDAC " + str(x) + + config1.modifyperiphery('THDAC',[x]*6) + config1.upload() + config1.write() + + mapsa.daq().Sequencer_init(shutterMode,options.shutterDur) + pix,mem = mapsa.daq().read_data(buffnum) + ipix=0 + + for p in pix: + + p.pop(0) + p.pop(0) + y1.append([]) + y1[ipix].append(array('d',p)) + + ipix+=1 + x1.append(x) + + +c3 = TCanvas('c3', '', 700, 900) +c3.Divide(2,3) + +thldSteps = np.array(x1) +yarrv = [] +gr2arr = [] +means = [] +########## Plot calibrated thresholds + +allMPAsFallingEdges = [] +for i in range(0,6): + backup=TFile("plots/backup_postCalibration_"+options.string+"_MPA"+str(i)+".root","recreate") + + c3.cd(i+1) + yarr = np.array(y1[i]) + gr2arr.append([]) + gr2 = [] + means.append(0.) + yarrv.append(yarr) + for iy1 in range(0,len(yarr[0,:])): + onePixAllThlds = yarr[:,iy1] + + gr2.append(TGraph(len(x1)-1,array('d',thldSteps),array('d',onePixAllThlds))) + + if iy1==0: + + gr2[iy1].SetTitle(';DAC Value (1.456 mV);Counts (1/1.456)') + gr2arr[i].append(gr2[iy1]) + gr2arr[i][iy1].Draw() + gr2[iy1].Write(str(iy1)) + + else: + gr2arr[i].append(gr2[iy1]) + gr2arr[i][iy1].Draw('same') + gr2[iy1].Write(str(iy1)) + gPad.Update() + means[i]+=gr2[iy1].GetMean(1) + + + +###################################################### +########## Get falling edges after calibration ####### +###################################################### + + # Find pixel with lowest threshold + thrArrayFallingEdge = [] + pxlVsThrCounter = [] + for i in range(0,len(yarr[0,:])): # loop over pixels + pxlVsThrCounter.append(yarr[:,i].tolist()) + for pxl in pxlVsThrCounter: + ## Find falling edge + halfMax = max(pxl)/2 + pxlDiff = [abs(x - halfMax) for x in pxl] # Difference of hits for each threshold to half maximum of hits + thrRightOfHalfMaxFalling = max([ # Highest threshold to get threshold right after halfmax of falling edge + pxlDiff.index(pxlDiffI) # Match differences of hits to threshold values + for pxlDiffI in sorted(pxlDiff)[:4] # Four threshold values with smallest distance to halfmax (left/right of rising edge and left/right of falling edge) + ]) + thrArrayFallingEdge.append(thrRightOfHalfMaxFalling) + allMPAsFallingEdges.append(thrArrayFallingEdge) + +print "Falling edges at %s" %allMPAsFallingEdges + +print 'Means' +for m in means: + print m/48. + +c3.Print('plots/Scurve_Calibration'+options.string+'_post.root', 'root') +c3.Print('plots/Scurve_Calibration'+options.string+'_post.pdf', 'pdf') +c3.Print('plots/Scurve_Calibration'+options.string+'_post.png', 'png') + +print "" +print "Done" + + +raw_input("Press any key to exit") diff --git a/old/mem_calibration.py b/old/mem_calibration.py new file mode 100644 index 0000000..d618ab4 --- /dev/null +++ b/old/mem_calibration.py @@ -0,0 +1,184 @@ +import sys +from classes import * +from array import array +from optparse import OptionParser + +#import root after optparse to get help page from optparse +from ROOT import TGraph, TCanvas, TLine, TColor + + +# Add options +parser = OptionParser() + +parser.add_option('-w', '--shutterdur', metavar='F', type='int', action='store', +default = 0xFFFF, +dest = 'shutterdur', +help = 'shutter duration') + +parser.add_option('-t', '--trim', metavar='F', type='int', action='store', +default = 30, +dest = 'trimDAC', +help = 'Global trim DAC (0-31)') + +parser.add_option('-b', '--buffer', metavar='F', type='int', action='store', +default = 1, +dest = 'buffer', +help = 'Select buffer (1-4)') + +parser.add_option('-m', '--mpa', metavar='F', type='int', action='store', +default = 0, +dest = 'mpa', +help = 'Select mpa (0-5)') + +parser.add_option('-c', '--continuous', metavar='F', type='int', action='store', +default = 0, +dest = 'continuous', +help = 'Enable continuous datataking') + +(options,args) = parser.parse_args() + +# Establish connection +a = uasic(connection="file://connections_test.xml",device="board0") +mapsa=MAPSA(a) +read = a._hw.getNode("Control").getNode('firm_ver').read() +a._hw.dispatch() +print "Running firmware version " + str(read) + +# Get all MPAs +mpa = [] +for i in range(1,7): + mpa.append(mapsa.getMPA(i)) + +# Enable clock +a._hw.getNode("Control").getNode("MPA_clock_enable").write(0x1) +a._hw.dispatch() + +# Calibration disable +CE = 0 + +# Load default config +config = mapsa.config(Config=1,string='default') +config.upload() + +# Modify config +confdict = {'OM':[3]*6,'RT':[0]*6,'SCW':[0]*6,'SH2':[0]*6,'SH1':[0]*6,'THDAC':[0]*6,'CALDAC':[30]*6,'PML':[1]*6,'ARL':[1]*6,'CEL':[CE]*6,'CW':[0]*6,'PMR':[1]*6,'ARR':[1]*6,'CER':[CE]*6,'SP':[0]*6,'SR':[1]*6,'TRIMDACL':[options.trimDAC]*6,'TRIMDACR':[options.trimDAC]*6} +config.modifyfull(confdict) + +eventArray = [] +hitArray = [] +thrArray = [] +bxArray = [] + +# Start threshold scan +for thr in range(0,255): + + if thr%2 == 0: + print thr + + # Apply threshold + config.modifyperiphery('THDAC',[thr]*6) + config.upload() + config.write() + + # Start acquisition (sequencer) + #mapsa.daq().Sequencer_init(options.continuous,options.shutterdur) + + ########################## + ### Begin of sequencer ### + ########################## + + # Set shutter duration + a._hw.getNode("Shutter").getNode("time").write(options.shutterdur) + + # Opens shutter (mode = 0x0 single shutter, 0x1 four (buffers) consequitive shutter) + a._hw.getNode("Control").getNode("Sequencer").getNode('datataking_continuous').write(options.continuous) + + # Write in first buffer (default and therefore not necessary to be defined) + #a._hw.getNode("Control").getNode("Sequencer").getNode('buffers_index').write(0) + + # Readout has to be enabled in order to get the data + a._hw.getNode("Control").getNode("readout").write(1) + a._hw.dispatch() + + ######################## + ### End of sequencer ### + ######################## + + # Readout buffer (TRUE / FALSE : Wait for sequencer) + mem = mpa[options.mpa].daq().read_raw(options.buffer,1,True)[0] + + # Mem integer array to binary string in readable order (header,bx,pix) + binMemStr= "" + for i in range(0,216): + binMemStr = binMemStr + '{0:032b}'.format(mem[215-i]) + + # String to binary array + binMem = [binMemStr[x:x+72] for x in range(0,len(binMemStr),72)] + + # Get elements of binary string + hd = [] + bx = [] + pix = [] + for entry in binMem: + hd.append(entry[0:8]) + bx.append(entry[8:24]) + pix.append(entry[24:72]) + + # Count number of Events + nEvents = 0 + for event in hd: + if event == "11111111": + nEvents+=1 + + # Sum hits per pixel + sumPixHits = [0]*48 + for event in pix: + for i, ipix in enumerate(event): + sumPixHits[i]+=int(ipix) + + # bunch crossing from binary to int + bx=[int(ibx,2) for ibx in bx] + + eventArray.append(nEvents) + hitArray.append(sumPixHits) + thrArray.append(thr) + bxArray.append(bx) + + + +print "---END OF SCAN---" + +for ithr in bxArray: + print max(ithr) + +# Generate new list [[pix1_ThScan],[pix2_ThScan],..] +pxlVsThr = [] +for ipix in range(0,len(hitArray[0])): + pxlVsThr.append([item[ipix] for item in hitArray]) + +# Generate graphs for each pixel +graphs = [] + +for ipixScan in pxlVsThr: + graphs.append(TGraph(len(thrArray),array('d',thrArray),array('d',ipixScan))) + +# Draw graphs on canvas +c1 = TCanvas("graph","graph",1024,768) +c1.cd() + +for i,graph in enumerate(graphs): + if i==0: + graph.SetTitle('Threshold Scan;Threshold (DAC);Number of Hits') + graph.GetYaxis().SetRangeUser(0,max(eventArray)*1.1) + graph.Draw("APL") + else: + graph.Draw("PL") + +# Add line for nMax +line = TLine(0,max(eventArray),graphs[0].GetXaxis().GetXmax(),max(eventArray)) +line.SetLineColor(2) +line.Draw() + +print "Max number of events during scan: %s" %max(eventArray) + +raw_input("Press any key to exit") diff --git a/old/noise_calibration_mpa2_mpa5.py b/old/noise_calibration_mpa2_mpa5.py new file mode 100644 index 0000000..7a5dfc2 --- /dev/null +++ b/old/noise_calibration_mpa2_mpa5.py @@ -0,0 +1,237 @@ +import sys +from classes import * +from array import array +from optparse import OptionParser +from thresholdscan import thresholdScan + +# Add options +parser = OptionParser() + +parser.add_option('-w', '--shutterdur', metavar='F', type='int', action='store', +default = 0xFFFF, +dest = 'shutterdur', +help = 'shutter duration') + +parser.add_option('-b', '--buffer', metavar='F', type='int', action='store', +default = 1, +dest = 'buffer', +help = 'Select buffer (1-4)') + +parser.add_option('-m', '--mpa', metavar='F', type='int', action='store', +default = 1, +dest = 'mpa', +help = 'Select mpa (1-6)') + +parser.add_option('-c', '--continuous', metavar='F', type='int', action='store', +default = 0, +dest = 'continuous', +help = 'Enable continuous datataking') + +(options,args) = parser.parse_args() + +#import root after optparse to get help page from optparse +from ROOT import TGraph, TCanvas, TLine, TColor + +# Establish connection +a = uasic(connection="file://connections_test.xml",device="board0") +mapsa=MAPSA(a) +read = a._hw.getNode("Control").getNode('firm_ver').read() +a._hw.dispatch() +print "Running firmware version " + str(read) + + +mpa = [] +conf = [] +for i in range(1,7): + mpa.append(mapsa.getMPA(i)) + conf.append(mpa[i-1].config("data/Conf_default_MPA"+str(i)+"_config1.xml")) + +# Reset control logic +a._hw.getNode("Control").getNode("logic_reset").write(0x1) +a._hw.dispatch() + +# Enable clock +a._hw.getNode("Control").getNode("MPA_clock_enable").write(0x1) +a._hw.dispatch() + +# Calibration disable +CE = 0 + +# Resolution of threshold scan (only scan every 'res' steps) +res = 1 + +# Load default config +config = mapsa.config(Config=1,string='default') +config.upload() + +# Set voltage steps of threshold DAC and trimming DAC (in mV/Step) +thrVoltStep = 1.456 +trimVoltStep = 3.75 + +# Modify config +confdict = {'OM':[3]*6,'RT':[0]*6,'SCW':[0]*6,'SH2':[0]*6,'SH1':[0]*6,'THDAC':[0]*6,'CALDAC':[30]*6,'PML':[1]*6,'ARL':[1]*6,'CEL':[CE]*6,'CW':[0]*6,'PMR':[1]*6,'ARR':[1]*6,'CER':[CE]*6,'SP':[0]*6,'SR':[1]*6,'TRIMDACL':[30]*6,'TRIMDACR':[30]*6} +config.modifyfull(confdict) + + +############################ +### Start Threshold Scan ### +############################ + +thrArray, pxlVsThrCounterAllMPAs = thresholdScan(res, options.shutterdur) # Array with threshold values and array [MPA1[[[pix1_ThScan], [pix2_ThScan],....], MPA2[[..],[..],...]]] + +print pxlVsThrCounterAllMPAs + +pxlVsThrCounter2 = pxlVsThrCounterAllMPAs[0] # Split into one array for each MPA +pxlVsThrCounter5 = pxlVsThrCounterAllMPAs[1] + + +########################################################## +### Begin plotting uncalibrated pixels over thresholds ### +########################################################## + +# Generate graphs for each pixel in asynchronous memory (ripple counter) +graphsCounter2 = [] + +for ipixScan in pxlVsThrCounter2: + graphsCounter2.append(TGraph(len(thrArray),array('d',thrArray),array('d',ipixScan))) + +graphsCounter5 = [] + +for ipixScan in pxlVsThrCounter5: + graphsCounter5.append(TGraph(len(thrArray),array('d',thrArray),array('d',ipixScan))) + + +# Draw graphs on canvas +c1 = TCanvas("graph","graph",1024,768) +c1.Divide(2) + +c1.cd(1) + +for i,graph2 in enumerate(graphsCounter2): + if i==0: + graph2.SetTitle('Threshold Scan;Threshold (DAC);Number of Hits') + graph2.Draw("APL") + else: + graph2.Draw("PL") + +c1.cd(2) + +for i,graph5 in enumerate(graphsCounter5): + if i==0: + graph5.SetTitle('Threshold Scan;Threshold (DAC);Number of Hits') + graph5.Draw("APL") + else: + graph5.Draw("PL") + + + +################################## +### Begin calibration on noise ### +################################## + +# Find pixel with lowest threshold +thrArrayFallingEdge = [] +for pxl in pxlVsThrCounter2: + + pxl = [hits if hits < 10000 else 0 for hits in pxl] + halfMax = max(pxl)/2 + + pxlDiff = [abs(x - halfMax) for x in pxl] # Difference of hits for each threshold to half maximum of hits + thrRightOfHalfMaxFalling = max([ # Highest threshold to get threshold right after halfmax of falling edge + thrArray[pxlDiff.index(pxlDiffI)] # Match differences of hits to threshold values + for pxlDiffI in sorted(pxlDiff)[:4] # Four threshold values with smallest distance to halfmax (left/right of rising edge and left/right of falling edge) + ]) + thrArrayFallingEdge.append(thrRightOfHalfMaxFalling) + +pxlLowestThreshold = thrArrayFallingEdge.index(min(thrArrayFallingEdge)) + +trimDacToTheLeft = [(pxl - pxlLowestThreshold) * (thrVoltStep/trimVoltStep) + for pxl in thrArrayFallingEdge] + +# Normalize trimDac and take into account that we started with trimDac set to 30 +trimDac = [max(0, (30 - int(pxlTrimDac))) for pxlTrimDac in trimDacToTheLeft] + +# Split into left and right pixels +trimDacLeftPxl = [trimDac [x] for x in range(0,len(trimDac),2)] +trimDacRightPxl = [trimDac [x] for x in range(1,len(trimDac),2)] + +# Modify pixels with new trimDac values (Using the trimming values from MPA 2 for all MPAs, just for now) + +a._hw.getNode("Configuration").getNode("num_MPA").write(0x2) + +for i in range(0,24): + conf[0].modifypixel(i+1,'TRIMDACL',[trimDacLeftPxl[i]]*6) + conf[0].modifypixel(i+1,'TRIMDACR',[trimDacRightPxl[i]]*6) +#config.modifyperiphery('OM',[3]*6) +#config.modifyperiphery('RT',[0]*6) +#config.modifyperiphery('SCW',[0]*6) +#config.modifyperiphery('SH2',[0]*6) +#config.modifyperiphery('SH1',[0]*6) +#config.modifyperiphery('THDAC',[0]*6) +#config.modifyperiphery('CALDAC', [30]*6) +#for x in range(1,25): +# config.modifypixel(x,'PML', [1]*6) +# config.modifypixel(x,'ARL', [1]*6) +# config.modifypixel(x,'CEL', [CE]*6) +# config.modifypixel(x,'CW', [0]*6) +# config.modifypixel(x,'PMR', [1]*6) +# config.modifypixel(x,'ARR', [1]*6) +# config.modifypixel(x,'CER', [CE]*6) +# config.modifypixel(x,'SP', [0]*6) +# config.modifypixel(x,'SR', [1]*6) +#config.upload() +#config.write() + +a._hw.getNode("Configuration").getNode("mode").write(0x1) +a._hw.dispatch() + + + +#for i in range(0,24): + + +### Start new threshold scan, this time with calibrated pixels +thrArray, pxlVsThrCounterAllMPAs = thresholdScan(res, options.shutterdur) # Array with threshold values and array [MPA1[[[pix1_ThScan], [pix2_ThScan],....], MPA2[[..],[..],...]]] + +pxlVsThrCounter2 = pxlVsThrCounterAllMPAs[0] # Split into one array for each MPA +pxlVsThrCounter5 = pxlVsThrCounterAllMPAs[1] + +########################################################## +### Begin plotting calibrated pixels over thresholds ### +########################################################## + +# Generate graphs for each pixel in asynchronous memory (ripple counter) +graphsCounter2 = [] +for ipixScan in pxlVsThrCounter2: + graphsCounter2.append(TGraph(len(thrArray),array('d',thrArray),array('d',ipixScan))) + +graphsCounter5 = [] +for ipixScan in pxlVsThrCounter5: + graphsCounter5.append(TGraph(len(thrArray),array('d',thrArray),array('d',ipixScan))) + + +# Draw graphs on canvas +c2 = TCanvas("graph2","Calibrated graph",1024,768) +c2.Divide(2) + +c2.cd(1) + +for i,graph2 in enumerate(graphsCounter2): + if i==0: + graph2.SetTitle('Threshold Scan;Threshold (DAC);Number of Hits') + graph2.Draw("APL") + else: + graph2.Draw("PL") + +c2.cd(2) + +for i,graph5 in enumerate(graphsCounter5): + if i==0: + graph5.SetTitle('Threshold Scan;Threshold (DAC);Number of Hits') + graph5.Draw("APL") + else: + graph5.Draw("PL") + + + +raw_input("Press any key to exit") diff --git a/old/pix_mem_calibration.py b/old/pix_mem_calibration.py new file mode 100644 index 0000000..13a9583 --- /dev/null +++ b/old/pix_mem_calibration.py @@ -0,0 +1,451 @@ +import sys +from classes import * +from array import array +from optparse import OptionParser + + + +# Add options +parser = OptionParser() + +parser.add_option('-w', '--shutterdur', metavar='F', type='int', action='store', +default = 0xFF, +dest = 'shutterdur', +help = 'shutter duration') + +parser.add_option('-t', '--trim', metavar='F', type='int', action='store', +default = 30, +dest = 'trimDAC', +help = 'Global trim DAC (0-31)') + +parser.add_option('-b', '--buffer', metavar='F', type='int', action='store', +default = 1, +dest = 'buffer', +help = 'Select buffer (1-4)') + +parser.add_option('-m', '--mpa', metavar='F', type='int', action='store', +default = 1, +dest = 'mpa', +help = 'Select mpa (1-6)') + +parser.add_option('-c', '--continuous', metavar='F', type='int', action='store', +default = 0, +dest = 'continuous', +help = 'Enable continuous datataking') + +(options,args) = parser.parse_args() + +#import root after optparse to get help page from optparse +from ROOT import TGraph, TCanvas, TLine, TColor + +# Establish connection +a = uasic(connection="file://connections_test.xml",device="board0") +mapsa=MAPSA(a) +read = a._hw.getNode("Control").getNode('firm_ver').read() +a._hw.dispatch() +print "Running firmware version " + str(read) + +# Reset control logic +a._hw.getNode("Control").getNode("logic_reset").write(0x1) +a._hw.dispatch() + +#Write number of MPAs present (Doesn't work because mapsa.config expects 6 mpas) +#mpaAmount = 2 +#a._hw.getNode("Configuration").getNode("num_MPA").write(mpaAmount) +#a._hw.getNode("Configuration").getNode("mode").write(0x5) +#a._hw.dispatch() +#config._spi_wait() + +# Enable clock +a._hw.getNode("Control").getNode("MPA_clock_enable").write(0x1) +a._hw.dispatch() + +# Calibration disable +CE = 0 + +# Resolution of threshold scan (only scan every 'res' steps) +res = 2 + + +### Hacky workaround, should be solved using num_MPA +# Amount of MPAs on board +mpasPresent = [0, 1, 0, 0, 1, 0] # MAPSA with 2 MPAs at middle positions +#mpasPresent = [1, 1, 1, 1, 1, 1] # fully equiped MAPSA with 6 MPAs + +# MPA-register in which the ripple counter data can be found (ripple counter fills MPA registers from the back, if there are less than 6 MPAs options.mpa doesn't match where ripple counter stores data +rippleRegister = 6 - sum(mpasPresent) + sum(mpasPresent[:options.mpa]) + +# Load default config +config = mapsa.config(Config=1,string='default') +config.upload() + +# Set voltage steps of threshold DAC and trimming DAC (in mV/Step) +thrVoltStep = 1.456 +trimVoltStep = 3.75 + +# Modify config +confdict = {'OM':[3]*6,'RT':[0]*6,'SCW':[0]*6,'SH2':[0]*6,'SH1':[0]*6,'THDAC':[0]*6,'CALDAC':[30]*6,'PML':[1]*6,'ARL':[1]*6,'CEL':[CE]*6,'CW':[0]*6,'PMR':[1]*6,'ARR':[1]*6,'CER':[CE]*6,'SP':[0]*6,'SR':[1]*6,'TRIMDACL':[options.trimDAC]*6,'TRIMDACR':[options.trimDAC]*6} +config.modifyfull(confdict) + +# Synchronous Acquisition +eventArray = [] +hitArrayMem = [] +thrArray = [] +bxArray = [] + +# Asynchronous Acquisition +hitArrayCounter = [] + +# Start threshold scan (only every 'res' threshold) +for thr in range(0,255,res): + + print thr + + # Apply threshold + config.modifyperiphery('THDAC',[thr]*6) + config.upload() + config.write() + + # Start acquisition (sequencer) + + ########################## + ### Begin of sequencer ### + ########################## + + # Set shutter duration + a._hw.getNode("Shutter").getNode("time").write(options.shutterdur) + + # Opens shutter (mode = 0x0 single shutter, 0x1 four (buffers) consequitive shutter) + a._hw.getNode("Control").getNode("Sequencer").getNode('datataking_continuous').write(options.continuous) + + # Write in first buffer (default and therefore not necessary to be defined) + #a._hw.getNode("Control").getNode("Sequencer").getNode('buffers_index').write(0) + + # Readout has to be enabled in order to get the data + a._hw.getNode("Control").getNode("readout").write(1) + a._hw.dispatch() + + ######################## + ### End of sequencer ### + ######################## + + # Readout buffer (TRUE / FALSE : Wait for sequencer) and ripple counter + # mem, counter = mpa[options.mpa].daq().read_raw(options.buffer,1,True) # Doesn't work for less than 6 MPAs due to ripple counter data in wrong registers + + counter = a._hw.getNode("Readout").getNode("Counter").getNode("MPA"+str(rippleRegister)).getNode("buffer_"+str(options.buffer)).readBlock(25) # Ignore '-m' option, ripple counter is always here for single MPA, no matter which one + mem = a._hw.getNode("Readout").getNode("Memory").getNode("MPA"+str(options.mpa)).getNode("buffer_"+str(options.buffer)).readBlock(216) + a._hw.dispatch() + + ### Synchronous Acquisition ### + + # Mem integer array to binary string in readable order (header,bx,pix) + binMemStr= "" + for i in range(0,216): + binMemStr = binMemStr + '{0:032b}'.format(mem[215-i]) + + # String to binary array + binMem = [binMemStr[x:x+72] for x in range(0,len(binMemStr),72)] + + # Get elements of binary string + hd = [] + bx = [] + pix = [] + for entry in binMem: + hd.append(entry[0:8]) + bx.append(entry[8:24]) + pix.append(entry[24:72]) + + + # Count number of Events + nEvents = 0 + for event in hd: + if event == "11111111": + nEvents+=1 + + # Sum hits per pixel + sumPixHits = [0]*48 + for event in pix: + for i, ipix in enumerate(event): + sumPixHits[i]+=int(ipix) + + # bunch crossing from binary to int + bx=[int(ibx,2) for ibx in bx] + + eventArray.append(nEvents) + hitArrayMem.append(sumPixHits) + thrArray.append(thr) + bxArray.append(bx) + + ### Asynchronous ripple counter ### + + counterArray = [] + for x in range(1,len(counter)): # Skip header at [0] + counterArray.append(counter[x] & 0xFFFF) # Mask to select left pixel + counterArray.append((counter[x] >> 16) & 0xFFFF) # Mask to select right pixel + hitArrayCounter.append(counterArray) + +print "---END OF SCAN---" + +for ithr in bxArray: + print max(ithr) + +# Generate new list [[pix1_ThScan],[pix2_ThScan],..] from synchronous acquisition +pxlVsThrMem = [] +for ipix in range(0,len(hitArrayMem[0])): + pxlVsThrMem.append([item[ipix] for item in hitArrayMem]) + +# Generate new list [[pix1_ThScan],[pix2_ThScan],..] from asynchronous acquisition (ripple counter) +pxlVsThrCounter = [] +for ipix in range(0,len(hitArrayCounter[0])): + pxlVsThrCounter.append([item[ipix] for item in hitArrayCounter]) + + +########################################################## +### Begin plotting uncalibrated pixels over thresholds ### +########################################################## + +# Generate graphs for each pixel in synchronous memory +graphsMem = [] + +for ipixScan in pxlVsThrMem: + graphsMem.append(TGraph(len(thrArray),array('d',thrArray),array('d',ipixScan))) + +# Generate graphs for each pixel in asynchronous memory (ripple counter) +graphsCounter = [] + +for ipixScan in pxlVsThrCounter: + graphsCounter.append(TGraph(len(thrArray),array('d',thrArray),array('d',ipixScan))) + + +# Draw graphs on canvas +c1 = TCanvas("graph","graph",1024,768) +c1.cd() + +for i,graph in enumerate(graphsMem): + if i==0: + graph.SetTitle('Threshold Scan;Threshold (DAC);Number of Hits') + graph.GetYaxis().SetRangeUser(0,max(eventArray)*1.1) + graph.Draw("APL") + else: + graph.Draw("PL") + +for graph in graphsCounter: + graph.SetLineColor(3) + graph.Draw("PL") + +# Add line for nMax +line = TLine(0,max(eventArray),graphsMem[0].GetXaxis().GetXmax(),max(eventArray)) +line.SetLineColor(2) +line.Draw() + +print "Max number of events during scan: %s" %max(eventArray) + + +######################### +### Begin calibration ### +######################### + +calibconf = config._confs[options.mpa - 1] +calibconfxmlroot = config._confsxmlroot[options.mpa - 1] + +### Calculate trim values +trimOffsetArray = [] +for i,pxl in enumerate(pxlVsThrCounter): # configure each pixel separately, iterator needed to distinguish between left and right pixel + if i%2==0: # get default trimming value of left pixel (config always for two pixels (32bit)) + configTrim = int(calibconfxmlroot[i/2+1].find('TRIMDACL').text) + else: # same for right pixel + configTrim = int(calibconfxmlroot[(i+1)/2].find('TRIMDACR').text) + + halfMax = max(pxl)/2.0 # half of maximum amount of hits seen for all thresholds + + thrValueMaxHits = pxl.index(max(pxl)) * res # threshold value at which maximum number of hits was found (res is used because index of array doesn't necessarily match threshold value, only when res=1) + for thrStep in range(len(pxl) - 1): # highest threshold can't be trimmed + thrValue = thrStep * res # actual threshold value of this threshold step + if (pxl[thrStep + 1] - halfMax) < 0 and thrValueMaxHits < thrValue : # Falling edge right before half maximum (first condition selects only thresholds with less hits than half maximum, second condition selects right side of peak. + diffToHalfMaxLeft = abs(pxl[thrStep] - halfMax) + diffToHalfMaxRight = abs(pxl[thrStep + 1] - halfMax) + + thrOffset = thrValue + diffToHalfMaxRight / (diffToHalfMaxLeft + diffToHalfMaxRight) # offset of thresholds but in threshold steps + trimOffset = 31 + configTrim - int(round(thrOffset*thrVoltStep/trimVoltStep)) # convert from thrSteps to trimSteps and subtract from trim in configuration file + break #go to next pixel + else: # no break, pixel can't be trimmed because there is no right edge + trimOffset = configTrim # just apply trim from config file + print "UNTRIMMED" + trimOffsetArray.append(trimOffset) + +# Limit to 5 bit for trimDAC and split into left and right trimDAC +trimDacLeft = [max(0, min(31, trimOffsetArray[x])) for x in range(0,len(trimOffsetArray),2)] +trimDacRight = [max(0, min(31, trimOffsetArray[x])) for x in range(1,len(trimOffsetArray),2)] + +print 'TRIMDACL' +print trimDacLeft + +print 'TRIMDACR' +print trimDacRight + +################################################## +##### New threshold scan, this time calibrated ### +################################################## + +# Modify config +confdict = {'OM':[3]*6,'RT':[0]*6,'SCW':[0]*6,'SH2':[0]*6,'SH1':[0]*6,'THDAC':[0]*6,'CALDAC':[30]*6,'PML':[1]*6,'ARL':[1]*6,'CEL':[CE]*6,'CW':[0]*6,'PMR':[1]*6,'ARR':[1]*6,'CER':[CE]*6,'SP':[0]*6,'SR':[1]*6,'TRIMDACL':trimDacLeft*6,'TRIMDACR':trimDacRight*6} +config.modifyfull(confdict) +# Synchronous Acquisition +eventArrayCalib = [] +hitArrayMemCalib = [] +thrArray = [] +bxArrayCalib = [] + +# Asynchronous Acquisition +hitArrayCounterCalib = [] + +# Start threshold scan (only every second threshold) +for thr in range(0,255,res): + + print thr + + # Apply threshold + config.modifyperiphery('THDAC',[thr]*6) + config.upload() + config.write() + + # Start acquisition (sequencer) + + ########################## + ### Begin of sequencer ### + ########################## + + # Set shutter duration + a._hw.getNode("Shutter").getNode("time").write(options.shutterdur) + + # Opens shutter (mode = 0x0 single shutter, 0x1 four (buffers) consequitive shutter) + a._hw.getNode("Control").getNode("Sequencer").getNode('datataking_continuous').write(options.continuous) + + # Write in first buffer (default and therefore not necessary to be defined) + #a._hw.getNode("Control").getNode("Sequencer").getNode('buffers_index').write(0) + + # Readout has to be enabled in order to get the data + a._hw.getNode("Control").getNode("readout").write(1) + a._hw.dispatch() + + ######################## + ### End of sequencer ### + ######################## + + # Readout buffer (TRUE / FALSE : Wait for sequencer) and ripple counter + # mem, counter = mpa[options.mpa].daq().read_raw(options.buffer,1,True) # Doesn't work for less than 6 MPAs due to ripple counter data in wrong registers + + + counter = a._hw.getNode("Readout").getNode("Counter").getNode("MPA"+str(rippleRegister)).getNode("buffer_"+str(options.buffer)).readBlock(25) # Ignore '-m' option, ripple counter is always here for single MPA, no matter which one + mem = a._hw.getNode("Readout").getNode("Memory").getNode("MPA"+str(options.mpa)).getNode("buffer_"+str(options.buffer)).readBlock(216) + a._hw.dispatch() + + ### Synchronous Acquisition ### + + # Mem integer array to binary string in readable order (header,bx,pix) + binMemStr= "" + for i in range(0,216): + binMemStr = binMemStr + '{0:032b}'.format(mem[215-i]) + + # String to binary array + binMem = [binMemStr[x:x+72] for x in range(0,len(binMemStr),72)] + + # Get elements of binary string + hd = [] + bx = [] + pix = [] + for entry in binMem: + hd.append(entry[0:8]) + bx.append(entry[8:24]) + pix.append(entry[24:72]) + + + # Count number of Events + nEvents = 0 + for event in hd: + if event == "11111111": + nEvents+=1 + + # Sum hits per pixel + sumPixHits = [0]*48 + for event in pix: + for i, ipix in enumerate(event): + sumPixHits[i]+=int(ipix) + + # bunch crossing from binary to int + bx=[int(ibx,2) for ibx in bx] + + eventArrayCalib.append(nEvents) + hitArrayMemCalib.append(sumPixHits) + thrArray.append(thr) + bxArrayCalib.append(bx) + + ### Asynchronous ripple counter ### + + counterArrayCalib = [] + for x in range(1,len(counter)): # Skip header at [0] + counterArrayCalib.append(counter[x] & 0xFFFF) # Mask to select left pixel + counterArrayCalib.append((counter[x] >> 16) & 0xFFFF) # Mask to select right pixel + hitArrayCounterCalib.append(counterArrayCalib) + +print "---END OF SCAN---" + +for ithr in bxArray: + print max(ithr) + +# Generate new list [[pix1_ThScan],[pix2_ThScan],..] from synchronous acquisition +pxlVsThrMem = [] +for ipix in range(0,len(hitArrayMem[0])): + pxlVsThrMem.append([item[ipix] for item in hitArrayMemCalib]) + +# Generate new list [[pix1_ThScan],[pix2_ThScan],..] from asynchronous acquisition (ripple counter) +pxlVsThrCounter = [] +for ipix in range(0,len(hitArrayCounter[0])): + pxlVsThrCounter.append([item[ipix] for item in hitArrayCounterCalib]) + + +######################################################## +### Begin plotting calibrated pixels over thresholds ### +######################################################## + +# Generate graphs for each pixel in synchronous memory +graphsMemCalib = [] + +for ipixScan in pxlVsThrMem: + graphsMemCalib.append(TGraph(len(thrArray),array('d',thrArray),array('d',ipixScan))) + +# Generate graphs for each pixel in asynchronous memory (ripple counter) +graphsCounterCalib = [] + +for ipixScan in pxlVsThrCounter: + graphsCounterCalib.append(TGraph(len(thrArray),array('d',thrArray),array('d',ipixScan))) + + +# Draw graphs on canvas +c2 = TCanvas("calibgraph","calibgraph",1024,768) +c2.cd() + +for i,graphCalib in enumerate(graphsMemCalib): + if i==0: + graphCalib.SetTitle('Threshold Scan;Threshold (DAC);Number of Hits') + graphCalib.GetYaxis().SetRangeUser(0,max(eventArrayCalib)*1.1) + graphCalib.Draw("APL") + else: + graphCalib.Draw("PL") + +for graphCalib in graphsCounterCalib: + graphCalib.SetLineColor(3) + graphCalib.Draw("PL") + +# Add line for nMax +line = TLine(0,max(eventArrayCalib),graphsMemCalib[0].GetXaxis().GetXmax(),max(eventArrayCalib)) +line.SetLineColor(2) +line.Draw() + + + + + + +raw_input("Press any key to exit") + diff --git a/old/pixtest.py b/old/pixtest.py new file mode 100644 index 0000000..69125ac --- /dev/null +++ b/old/pixtest.py @@ -0,0 +1,144 @@ +import sys +from classes import * +from array import array +from optparse import OptionParser + +#import root after optparse to get help page from optparse +from ROOT import TGraph, TCanvas, TLine, TColor + + +# Add options +parser = OptionParser() + +parser.add_option('-w', '--shutterdur', metavar='F', type='int', action='store', +default = 0xFFFF, +dest = 'shutterdur', +help = 'shutter duration') + +parser.add_option('-t', '--trim', metavar='F', type='int', action='store', +default = 30, +dest = 'trimDAC', +help = 'Global trim DAC (0-31)') + +parser.add_option('-b', '--buffer', metavar='F', type='int', action='store', +default = 1, +dest = 'buffer', +help = 'Select buffer (1-4)') + +parser.add_option('-m', '--mpa', metavar='F', type='int', action='store', +default = 1, +dest = 'mpa', +help = 'Select mpa (1-mpaAmount)') + +parser.add_option('-c', '--continuous', metavar='F', type='int', action='store', +default = 0, +dest = 'continuous', +help = 'Enable continuous datataking') + +parser.add_option('-d', '--threshold', metavar='F', type='int', action='store', +default = 50, +dest = 'threshold', +help = 'Set threshold for DAC') +(options,args) = parser.parse_args() + +# Establish connection +a = uasic(connection="file://connections_test.xml",device="board0") +mapsa=MAPSA(a) +read = a._hw.getNode("Control").getNode('firm_ver').read() +a._hw.dispatch() +print "Running firmware version " + str(read) + +# Enable clock +a._hw.getNode("Control").getNode("MPA_clock_enable").write(0x1) +a._hw.dispatch() + +# Calibration disable +CE = 0 + + +# MPA Amount + +mpaAmount = 6 + +# Load default config +config = mapsa.config(Config=1,string='default') +config.upload() + +# Modify config +confdict = {'OM':[3]*mpaAmount,'RT':[0]*mpaAmount,'SCW':[0]*mpaAmount,'SH2':[0]*mpaAmount,'SH1':[0]*mpaAmount,'THDAC':[0]*mpaAmount,'CALDAC':[30]*mpaAmount,'PML':[1]*mpaAmount,'ARL':[1]*mpaAmount,'CEL':[CE]*mpaAmount,'CW':[0]*mpaAmount,'PMR':[1]*mpaAmount,'ARR':[1]*mpaAmount,'CER':[CE]*mpaAmount,'SP':[0]*mpaAmount,'SR':[1]*mpaAmount,'TRIMDACL':[options.trimDAC]*mpaAmount,'TRIMDACR':[options.trimDAC]*mpaAmount} +config.modifyfull(confdict) +# Synchronous Acquisition +eventArray = [] +hitArrayMem = [] +thrArray = [] +bxArray = [] + +# Asynchronous Acquisition +hitArrayCounter = [] + +thr = options.threshold +# Apply threshold +config.modifyperiphery('THDAC',[thr]*mpaAmount) +config.upload() +# config.write() + +a._hw.getNode("Configuration").getNode("num_MPA").write(0x2) +a._hw.getNode("Configuration").getNode("mode").write(0x5) +a._hw.dispatch() +config.spi_wait() + + +# Start acquisition (sequencer) + +########################## +### Begin of sequencer ### +########################## + +# Set shutter duration +a._hw.getNode("Shutter").getNode("time").write(options.shutterdur) + +# Opens shutter (mode = 0x0 single shutter, 0x1 four (buffers) consequitive shutter) +a._hw.getNode("Control").getNode("Sequencer").getNode('datataking_continuous').write(options.continuous) + +# Write in first buffer (default and therefore not necessary to be defined) +a._hw.getNode("Control").getNode("Sequencer").getNode('buffers_index').write(0) + +# Readout has to be enabled in order to get the data +a._hw.getNode("Control").getNode("readout").write(1) +a._hw.dispatch() + +######################## +### End of sequencer ### +######################## + +# Readout buffer (TRUE / FALSE : Wait for sequencer) and ripple counter +#mem, counter = mpa[options.mpa].daq().read_raw(options.buffer,options.mpa+1,False) +#counter_data = a._hw.getNode("Readout").getNode("Counter").getNode("MPA"+str(options.mpa)).getNode("buffer_"+str(options.buffer)).readBlock(25) +#memory_data = a._hw.getNode("Readout").getNode("Memory").getNode("MPA"+str(options.mpa)).getNode("buffer_"+str(options.buffer)).readBlock(216) + +counter_data = a._hw.getNode("Readout").getNode("Counter").getNode("MPA" + str(options.mpa)).getNode("buffer_"+str(options.buffer)).readBlock(25) +memory_data = a._hw.getNode("Readout").getNode("Memory").getNode("MPA"+str(options.mpa)).getNode("buffer_"+str(options.buffer)).readBlock(216) +a._hw.dispatch() + + +# Mem integer array to binary string in readable order (header,bx,pix) +binMemStr= "" +for i in range(0,216): + binMemStr = binMemStr + '{0:032b}'.format(memory_data[215-i]) + +# String to binary array +binMem = [binMemStr[x:x+72] for x in range(0,len(binMemStr),72)] + +counterArray = [] +for x in range(0,len(counter_data)): + counterArray.append(counter_data[x] & 0xFFFF) # Mask to select left pixel + counterArray.append((counter_data[x] >> 16) & 0xFFFF) # Mask to select right pixel + +print counterArray +for x in range(0,len(binMem)): + print binMem[x] + + +print 'Binary representation of ripple counter:' +for x in range(0, len(counterArray)): + print bin(counterArray[x]) diff --git a/old/thresholdscan.py b/old/thresholdscan.py new file mode 100644 index 0000000..3fa281a --- /dev/null +++ b/old/thresholdscan.py @@ -0,0 +1,70 @@ +# Start threshold scan (only every 'res' thresholds) +from classes import * + +a = uasic(connection="file://connections_test.xml",device="board0") +mapsa=MAPSA(a) +config = mapsa.config(Config=1,string='default') + +def thresholdScan(res, shutterdur): + mpaAmount = 2 + thrArray = [] + hitArrayCounter = [] + for thr in range(0,255,res): + + print thr + + # Apply threshold + config.modifyperiphery('THDAC',[thr]*6) + config.upload() + config.write() + + thrArray.append(thr) + # Start acquisition (sequencer) + + ########################## + ### Begin of sequencer ### + ########################## + + # Set shutter duration + a._hw.getNode("Shutter").getNode("time").write(shutterdur) + + # Opens shutter (mode = 0x0 single shutter, 0x1 four (buffers) consequitive shutter) + a._hw.getNode("Control").getNode("Sequencer").getNode('datataking_continuous').write(0x0) + + # Write in first buffer (default and therefore not necessary to be defined) + #a._hw.getNode("Control").getNode("Sequencer").getNode('buffers_index').write(0) + + # Readout has to be enabled in order to get the data + a._hw.getNode("Control").getNode("readout").write(1) + a._hw.dispatch() + + ######################## + ### End of sequencer ### + ######################## + + # Readout buffer (TRUE / FALSE : Wait for sequencer) and ripple counter (Names don't match because ripples are in wrong registers) + mpaArrayCounter = [] + for i in range(0,mpaAmount): + counter = a._hw.getNode("Readout").getNode("Counter").getNode("MPA" + str(5 + i)).getNode("buffer_1").readBlock(25) + a._hw.dispatch() + + counterArray = [] + for x in range(1,len(counter)): # Skip header at [0] + counterArray.append(counter[x] & 0xFFFF) # Mask to select left pixel + counterArray.append((counter[x] >> 16) & 0xFFFF) # Mask to select right pixel + + mpaArrayCounter.append(counterArray) + + hitArrayCounter.append(mpaArrayCounter) + + print "--- END OF SCAN ---" + + # Generate new list [MPA1[[[pix1_ThScan],[pix2_ThScan]],MPA2[...], ..] from asynchronous acquisition (ripple counter) + mpaPxlVsThrCounter = [] + for i in range(0,mpaAmount): + pxlVsThrCounter = [] + for ipix in range(0,len(hitArrayCounter[i][0])): + pxlVsThrCounter.append([item[i][ipix] for item in hitArrayCounter]) + mpaPxlVsThrCounter.append(pxlVsThrCounter) + + return thrArray, mpaPxlVsThrCounter diff --git a/pixPlot.py b/pixPlot.py new file mode 100644 index 0000000..39fcae4 --- /dev/null +++ b/pixPlot.py @@ -0,0 +1,57 @@ +import sys +from ROOT import TH2F, TCanvas, gStyle, TAxis + +class MPAPlot: + + def __init__(self): + + self.plot = None + + def pixelHits(self, hitArray): + + gStyle.SetOptStat(0) + gStyle.SetPalette(55) + + x = [ix for ix in range(0,16)] + y = [0,1,2] + + hits = [] + + if len(hitArray) is 48: + hits.append(hitArray[:16]) + hits.append(list(reversed(hitArray[16:32]))) + hits.append(hitArray[32:]) + else: + sys.exit("Hit array must contain 48 entries") + + histo = TH2F("h1","HitMap",16,0.5,16.5,3,0.5,3.5) + + for iy in y: + for ix in x: + for iHit in range(0,hits[iy][ix]): + histo.Fill(ix+0.5,iy+0.5) + + histo.GetYaxis().SetNdivisions(3) + + self.plot = histo + return self.plot + + def draw(self): + + c1 = TCanvas("c1", "Canvas", 768, 1280) + c1.SetRightMargin(0.15) + c1.cd() + self.plot.Draw("colz") + + raw_input() + +if __name__ == "__main__": + + plot = MPAPlot() + if len(sys.argv)>1: + hits = sys.argv[1] + else: + #hits = [80, 40, 44, 43, 30, 34, 0, 46, 0, 64, 0, 75, 0, 0, 59, 108, 88, 27, 25, 38, 34, 30, 39, 28, 23, 30, 28, 30, 35, 35, 31, 54, 61, 28, 31, 30, 35, 41, 41, 0, 43, 0, 48, 38, 40, 36, 35, 83] + hits = [89, 32, 33, 49, 35, 34, 28, 38, 55, 37, 38, 35, 25, 22, 43, 92, 70, 35, 35, 31, 22, 23, 21, 24, 23, 32, 26, 31, 34, 39, 45, 103, 107, 42, 41, 29, 21, 30, 27, 33, 30, 34, 34, 24, 28, 44, 41, 63] + plot.pixelHits(hits) + plot.draw() diff --git a/plot_generators/hits_over_vbias.py b/plot_generators/hits_over_vbias.py new file mode 100644 index 0000000..e3789cb --- /dev/null +++ b/plot_generators/hits_over_vbias.py @@ -0,0 +1,100 @@ +from MPACalibration import MPACalibration +import xml.etree.ElementTree as ET +from MPAPlot import MPAPlot +from KeithleyControl.keithleyControl import keithley +import time + +shutterDur = 0x1FFFFF +resolution = 10 +assembly = [2,5] +calibration = MPACalibration(assembly) +voltSource = keithley() +voltSource.init() +voltSource.setVoltage(110) + +mpaConfig = [] +conf = calibration._conf +mapsaClasses = calibration._mapsaClasses +glib = calibration._glib + +for MPA in assembly: + mpaConfig.append(ET.parse("data/Conf_trimcalib_MPA"+str(MPA)+"_config1.xml")) # Construct list of roots of XML files, one for each MPA + +trimDACMAPSA = [] +for MPAtree in mpaConfig: + MPA = MPAtree.getroot() + trimDAC = [] + for pixel in MPA.findall('pixel'): + trimDAC.append(int(pixel.find('TRIMDACL').text)) + trimDAC.append(int(pixel.find('TRIMDACR').text)) + trimDACMAPSA.append(trimDAC) +calibration.writeCalibrationToMPA(trimDAC = trimDACMAPSA) + +#calibration.thresholdScan() +#counterThrScan, _ = calibration.getThrScanPerPix() +#_,_,thresholds = calibration.getThrScanMetadata() +#counterRaw, _ = calibration.getThrScanRawHits() + +#globalThreshold = [] +#for iMPA, MPA in enumerate(counterThrScan): +# maxPix = [] +# plot = MPAPlot() +# for pix in MPA: +# plot.createGraph(thresholds[iMPA], pix) +# maxPix.append(pix.index(max(pix))) +# plot.setRange(yRange = [0, max([max(pix) for pix in MPA])]) +# plot.draw() +# print sum(maxPix)/len(maxPix) +# globalThreshold.append(int(raw_input("Which global threshold should be set? \n"))) + +globalThreshold = [150,150] +for iMPA, MPA in enumerate(assembly): + conf[iMPA].modifyperiphery('THDAC',globalThreshold[iMPA]) # Write threshold to MPA 'iMPA' + conf[iMPA].upload() + glib.getNode("Configuration").getNode("mode").write(len(assembly) - 1) + conf[iMPA].spi_wait() # includes dispatch + +#for iMPA, MPA in enumerate(counterRaw): +# print MPA[globalThreshold[iMPA]] + + +calibration.writeCalibrationToMPA(trimDAC = trimDACMAPSA) + +hitArrayVolt = [] +voltArray = [] + +for voltStep in range(0, 111, resolution): + + voltSource.setVoltage(voltStep) + voltArray.append(voltStep) + + mapsaClasses.daq().Sequencer_init(0, shutterDur) + mpaArrayCounter = [] + for iMPA, _ in enumerate(assembly): + + counter = glib.getNode("Readout").getNode("Counter").getNode("MPA"+str(iMPA + 1)).getNode("buffer_1").readBlock(25) + glib.dispatch() + + counterArray = [] + for x in range(1,len(counter)): # Skip header at [0] + counterArray.append(counter[x] & 0x7FFF) # Mask to select left pixel + counterArray.append((counter[x] >> 16) & 0x7FFF) # Mask to select right pixel + mpaArrayCounter.append(counterArray) + + hitArrayVolt.append(mpaArrayCounter) + time.sleep(2) + print voltSource.readVoltage() + print voltSource.readCurrent() + +voltSource.close() +hitArrayMAPSA = [list(MPA) for MPA in zip(*hitArrayVolt)] # Swap highest and second-higest order of nesting +print hitArrayMAPSA[0] +print hitArrayMAPSA[1] + + +for MPA in hitArrayMAPSA: + plot = MPAPlot() + for pix in MPA: + plot.createGraph(voltArray, pix) + plot.setRange(yRange = [0,50]) + plot.draw() diff --git a/plot_generators/hits_vs_thresholds.py b/plot_generators/hits_vs_thresholds.py new file mode 100644 index 0000000..eaa4a27 --- /dev/null +++ b/plot_generators/hits_vs_thresholds.py @@ -0,0 +1,97 @@ +from MPACalibration import MPACalibration +from MPAPlot import MPAPlot +from ROOT import TCanvas,TFile, TLine, gStyle, TDirectory + +assembly = [2,5] +gStyle.SetOptFit() +rootFile = TFile("plots_kit/Threshold_scan_before_and_after_calibration.root", "recreate") + +calibration = MPACalibration(assembly) +calibration.thresholdScan(calEnbl = 1, calNum = 5000) + +counter, mem = calibration.getThrScanPerPix() +_,_,threshold = calibration.getThrScanMetadata() +for nMPA, MPA in enumerate(assembly): + mpaDir = rootFile.mkdir("Threshold scans before calibration with MPA "+str(MPA), "Threshold scans before calibration with MPA "+str(MPA)) + plot = MPAPlot() + for pix in counter[nMPA]: + plot.createGraph(threshold[nMPA], pix) + plot.setTitle('MPA ' + str(MPA) + ' threshold scan before calibration; Threshold (DAC);Number of Hits') + plot.draw() + graphList = plot.getPlot() + for graph in graphList: + mpaDir.Add(graph) + mpaDir.Write() + +edgesBeforeCal = calibration.findFallingEdges() +trimDac = calibration.getTrimBits(minimize = False) +calibration.writeCalibrationToMPA(trimDAC = trimDac) + +for nMPA, MPA in enumerate(assembly): + plot = MPAPlot() + plot.fillHisto(edgesBeforeCal[nMPA] ) + plot.fitHisto() + plot.setTitle('Falling edges of MPA '+str(MPA)+' before calibration; Threshold (DAC); Number of Pixels') + plot.draw() + histo = plot.getPlot(0) + histo.Write() + + +calibration.thresholdScan(calEnbl = 1, calNum = 5000) +counter, mem = calibration.getThrScanPerPix() +_,_,threshold = calibration.getThrScanMetadata() + +for nMPA, MPA in enumerate(assembly): + mpaDir = rootFile.mkdir("Threshold scans after calibration with MPA "+str(MPA), "Threshold scans after calibration with MPA "+str(MPA)) + + plot = MPAPlot() + for pix in counter[nMPA]: + plot.createGraph(threshold[nMPA], pix) + plot.setTitle('MPA ' + str(MPA) + ' threshold scan after calibration on thld ' + str(min(edgesBeforeCal[nMPA])) + '; Threshold (DAC);Number of Hits') + + graphList = plot.getPlot() + for graph in graphList: + mpaDir.Add(graph) + + c1 = TCanvas("hist", "hist", 1024, 768) + c1.cd() + for i,graph in enumerate(graphList): + if i == 0: + graph.Draw("APL") + else: + graph.Draw("PL") + + + # Add line for edge on which was trimmed + line = TLine(min(edgesBeforeCal[nMPA]), 0, min(edgesBeforeCal[nMPA]), 5000) + line.SetLineColor(2) + line.Draw() + mpaDir.Add(line) + + mpaDir.Write() + + raw_input() + +edgesAfterCal = calibration.findFallingEdges() + +for nMPA, MPA in enumerate(assembly): + plot = MPAPlot() + plot.fillHisto(edgesAfterCal[nMPA] ) + plot.fitHisto() + plot.setTitle('Falling edges of MPA '+str(MPA)+' after calibration; Threshold (DAC); Number of Pixels') + histo = plot.getPlot(0) + histo.Write() + plot.draw() + + + +for nMPA, MPA in enumerate(assembly): + plot = MPAPlot() + plot.fillHisto(trimDac[nMPA], 0, 30) + plot.fitHisto() + plot.setTitle('TrimDACs of MPA '+str(MPA)+' after calibration; Trim (DAC); Number of Pixels') + histo = plot.getPlot(0) + histo.Write() + plot.draw() + +rootFile.Close() diff --git a/startDaq.sh b/startDaq.sh new file mode 100755 index 0000000..58747a8 --- /dev/null +++ b/startDaq.sh @@ -0,0 +1,7 @@ +#!/bin/bash + +while true +do + python daq/daq_continuous_2MPA.py + sleep 5 +done diff --git a/testBeam.py b/testBeam.py new file mode 100644 index 0000000..0839309 --- /dev/null +++ b/testBeam.py @@ -0,0 +1,56 @@ +import sys +from classes import * + +# Connection and GLIB +a = uasic(connection="file://connections_test.xml",device="board0") +glib = a._hw + +# Define MPA (1-6) (nMPA 2 or 5 for double assembly) +mpaDict = {0:2,1:5} +iMPA = 1 + +# Get all 6 MPAs and corresponding configs +# TODO: break down to two MPAs +mapsa = MAPSA(a) + +mpa=[] +conf=[] + +for i in range(0,6): + mpa.append(MPA(a._hw,i+1)) + conf.append(mpa[i].config("data/Default_MPA.xml")) + +# Set number of MPAs and start clock +glib.getNode("Control").getNode("MPA_clock_enable").write(0x1) +glib.getNode("Configuration").getNode("num_MPA").write(0x2) +glib.getNode("Configuration").getNode("mode").write(0x1) +glib.dispatch() + +# Configure both MPAs +# TODO: break down to two MPAs + +CE = 0 + +config = mapsa.config(Config=1,string='default') +config.upload() +confdict = {'OM':[3]*6,'RT':[0]*6,'SCW':[0]*6,'SH2':[0]*6,'SH1':[0]*6,'THDAC':[0]*6,'CALDAC':[30]*6,'PML':[1]*6,'ARL':[1]*6,'CEL':[CE]*6,'CW':[0]*6,'PMR':[1]*6,'ARR':[1]*6,'CER':[CE]*6,'SP':[0]*6,'SR':[1]*6,'TRIMDACL':[30]*6,'TRIMDACR':[30]*6} +config.modifyfull(confdict) + + +################# +### START DAQ ### +################# + +i=1 + +while True: + i+=1 + + glib.getNode("Shutter").getNode("time").write(0xFFFF) + glib.getNode("Control").getNode("Sequencer").getNode("datataking_continuous").write(0x0) +# glib.getNode("Control").getNode("readout").write(1) + glib.dispatch() + + + + print i diff --git a/testBeamAnalysis.py b/testBeamAnalysis.py new file mode 100644 index 0000000..45ee264 --- /dev/null +++ b/testBeamAnalysis.py @@ -0,0 +1,196 @@ +import os +import sys +import ast +import numpy as np + +class TBAnalysis(object): + + def __init__(self): + pass + + + def counterDecode(self, counterArray): + + counterData = [] + + for pix in counterArray[1:]: # Skip header at [0] + counterData.append(pix & 0x7FFF) # Mask to select left pixel. First bit is not considered as this seems sometimes to be set erronously. (Lots of entries with 0b1000000000000000) + counterData.append((pix >> 16) & 0x7FFF) # Mask to select right pixel. Same as above. + + return counterData + + + def memoryDecode(self, memoryArray, zeroSup = True): + + binMemStr= "" + for j in range(0,216): + binMemStr = binMemStr + '{0:032b}'.format(memoryArray[215-j]) + + # String to binary array + binMem = [binMemStr[x:x+72] for x in range(0,len(binMemStr),72)] + + if zeroSup: + binMem = self.memoryZeroSuppress(binMem) + + return binMem + + def memoryZeroSuppress(self, event): + + noZeroEvent = [entry for entry in event if int(entry) > 0] + + return noZeroEvent + + def memoryContent(self, memoryData): + + + hd = [] + bx = [] + pix = [] + + for entry in memoryData[:-1]: # Discard last entry in memory as here the 48th - pixel is always showing a hit, even if pixel is disabled. This is intended as a workaround, the maximum number of hits per pixel and memory is now 95. + hd.append(entry[:8]) + bx.append(entry[8:24]) + pix.append(entry[24:]) + + return {'header':hd, 'bx':bx, 'hits':pix} + + + def parseFile(self, fileName): + + data = [] + + with open(fileName, 'r') as iFile: + for line in iFile: + data.append(ast.literal_eval(line)) + + return data + + + def getData(self, dataArray, nMPA = 2): + + data = [[] for i in range(0,nMPA)] + + if len(dataArray[0]) == 25: # unprocessed counter array + for i, entry in enumerate(dataArray): + data[i%nMPA].append(self.counterDecode(entry)) + if i%1000 == 0: + print "Decoding event %s" %(i/2) + elif len(dataArray[0]) == 216: # unprocessed memory array + for i, entry in enumerate(dataArray): + data[i%nMPA].append(self.memoryDecode(entry)) + if i%1000 == 0: + print "Decoding event %s" %(i/2) + else: + sys.exit("Wrong data format") + + return data + + + def loadFile(self, fileName): + + rawData = self.parseFile(fileName) + data = self.getData(rawData) + + return data + + + def saveDecoded(self, fileName, outPath="decoded"): + + data = self.loadFile(fileName) + + if not os.path.exists(os.path.dirname(fileName)+"/"+outPath): + os.makedirs(os.path.dirname(fileName)+"/"+outPath) + + for i,mpa in enumerate(data): + with open("%s/%s/%s_%s" %(os.path.dirname(fileName), outPath, os.path.basename(fileName), i),'w+') as outFile: + for line in mpa: + outFile.write(str(line)+'\n') + + return True + + + def convertFormat(self, dutRaw, axis = "X"): + + dutArray = [] + + for eventNum in range(len(dutRaw)): + + dutEvent = [] + + for pixNum,pix in enumerate(dutRaw[eventNum]): + if pix > 0: + if axis == "X": + if pixNum > 15 and pixNum < 32: + for i in range(pix): + dutEvent.append(31 - pixNum) + else: + for i in range(pix): + dutEvent.append(pixNum%16) + + elif axis == "Y": + for i in range(pix): + dutEvent.append(pixNum/16) + + else: + sys.exit("This axis doesn't exist") + + dutArray.append(dutEvent) + + return dutArray + + + +if __name__ == "__main__": + + from MPAPlot import MPAPlot + + tb = TBAnalysis() + + #if len(sys.argv) == 2: + # data = tb.loadFile(sys.argv[1]) + #else: + # sys.exit("No input file specified") + + #if sys.argv[1].split("/")[0] == "decoded": + # pass + #else: + # tb.saveDecoded(sys.argv[1]) + + try: + if not sys.stdin.isatty(): + for line in sys.stdin: + tb.saveDecoded(line) + elif len(sys.argv) > 1: + for line in sys.argv[1:]: + tb.saveDecoded(line) + print "Decoded file %s" %line + else: + print "Need a file to decode" + except: + sys.exit("Raw file not found") + + #if len(sys.argv) == 2: + # data = tb.loadFile(sys.argv[1]) + # + # runHits = [] + # + # for mpa in data: + # runHits.append(np.sum(mpa,0)) + + # for mpa in runHits: + # plt = MPAPlot() + # plt.createHitMap(mpa) + # plt.draw() + + #refArray = tb.parseFile(sys.argv[2]) + # + #dutRaw = tb.parseFile(sys.argv[1]) + + #dutArray = tb.convertFormat(dutRaw) + + #plot = MPAPlot() + + #plot.createCorrelationPlot(dutArray, refArray, "X" , -1) + + #plot.draw() + diff --git a/testBeamCorrelate.py b/testBeamCorrelate.py new file mode 100644 index 0000000..f9e2c66 --- /dev/null +++ b/testBeamCorrelate.py @@ -0,0 +1,34 @@ +from MPAPlot import MPAPlot +import sys +from testBeamAnalysis import TBAnalysis + +tb = TBAnalysis() + + +axis = sys.argv[3] + +# Input + +if len(sys.argv) == 5: + offset = int(sys.argv[4]) +elif len(sys.argv) == 6: + offset = range(int(sys.argv[4]),int(sys.argv[5])+1) +else: + offset = 0 + +dutRaw = tb.parseFile(sys.argv[1]) +refArray = tb.parseFile(sys.argv[2]) + +dutArray = tb.convertFormat(dutRaw, axis) + +plot = MPAPlot() + +# Plot +if isinstance(offset,int): + plot.createCorrelationPlot(dutArray, refArray, axis , offset) + plot.draw() +else: + for iOff in offset: + plot.createCorrelationPlot(dutArray, refArray, axis , iOff) + plot.save("output/correlations") + diff --git a/test_address_table_v1.xml b/test_address_table_v1.xml index 42e9f3d..8831a8c 100644 --- a/test_address_table_v1.xml +++ b/test_address_table_v1.xml @@ -2,7 +2,12 @@ +<<<<<<< HEAD +======= + + / +>>>>>>> 8bd6ffb... Current state of the analysis. A horrible, horrible state… @@ -299,4 +304,8 @@ + + + + diff --git a/threshscan.py b/threshscan.py index 65627d0..95986ea 100644 --- a/threshscan.py +++ b/threshscan.py @@ -10,13 +10,9 @@ #from ROOT import TGraph import sys, select, os, array,subprocess from array import array -#import ROOT -#from ROOT import TGraph import datetime saveout = sys.stdout - - commands = [] i=0 thresh = 80 diff --git a/trimDACtest/plot_trim.py b/trimDACtest/plot_trim.py new file mode 100644 index 0000000..2ecb056 --- /dev/null +++ b/trimDACtest/plot_trim.py @@ -0,0 +1,38 @@ +import pickle +import sys +from ROOT import TGraph, TCanvas, TLine, TF1 +from array import array + +pxlTrimFallingEdge = pickle.load(open(str(sys.path[0])+"/trimDacFallingEdge.pickle","r")) +# Draw graphs on canvas +c1 = TCanvas("graph","graph",1024,768) +c1.SetGrid() + +graphs = [] +for pxl in pxlTrimFallingEdge: + graphs.append(TGraph(32,array('d',range(32)),array('d',pxl))) # Generate graph with trimDACs on x-axis and falling edge position (in threshold-steps) on y-axis + +fitFunc = TF1("fa1","[0]+x*[1]",0,32) +fitvals = [] +for i,graph in enumerate(graphs): + graph.SetLineColor(i+1) + graph.SetMarkerStyle(8) + if i==0: + fitFunc.SetName("Fit for pixel "+str(i+1)) + result = graph.Fit(fitFunc.GetName(), "S") + graph.SetTitle('Trim Scan;Trim (DAC);Falling Edge (Threshold)') + graph.GetYaxis().SetRangeUser(0,255) + graph.Draw("APL") + else: + fitFunc.SetName("Fit for pixel "+str(i+1)) + result = graph.Fit(fitFunc.GetName(), "S") + graph.SetTitle('Pixel ' +str(i+1)) + graph.GetYaxis().SetRangeUser(0,255) + graph.Draw("PL") + fitvals.append(result.Parameter(1)) + +fitvals = sorted(enumerate(fitvals, start=1), key=lambda x: x[1]) +for i, fit in fitvals: + print "Pixel %s with %s" %(i,'{0:.3f}'.format(fit)) + +raw_input("Press any key to exit") diff --git a/trimDACtest/ratios b/trimDACtest/ratios new file mode 100644 index 0000000..899437a --- /dev/null +++ b/trimDACtest/ratios @@ -0,0 +1,98 @@ +0.382513661202 +0.378378378378 +0.385674931129 +0.365535248042 +0.393258426966 +0.366492146597 +0.388888888889 +0.371352785146 +0.37037037037 +0.365535248042 +0.393258426966 +0.354430379747 +0.4 +0.368421052632 +0.383561643836 +0.340632603406 +0.358056265985 +0.37037037037 +0.355329949239 +0.377358490566 +0.356234096692 +0.387811634349 +0.362694300518 +0.392156862745 +0.374331550802 +0.364583333333 +0.363636363636 +0.395480225989 +0.340632603406 +0.367454068241 +0.356234096692 +0.373333333333 +0.375335120643 +0.362694300518 +0.387811634349 +0.373333333333 +0.394366197183 +0.357142857143 +0.376344086022 +0.379403794038 +0.4 +0.382513661202 +0.378378378378 +0.361757105943 +0.384615384615 +0.364583333333 +0.363636363636 +0.373333333333 + +0.404624277457 +0.356234096692 +0.388888888889 +0.364583333333 +0.380434782609 +0.365535248042 +0.387811634349 +0.39886039886 +0.405797101449 +0.389972144847 +0.385674931129 +0.358974358974 +0.384615384615 +0.374331550802 +0.375335120643 +0.374331550802 +0.361757105943 +0.386740331492 +0.368421052632 +0.403458213256 +0.367454068241 +0.380434782609 +0.368421052632 +0.379403794038 +0.356234096692 +0.371352785146 +0.369393139842 +0.377358490566 +0.353535353535 +0.382513661202 +0.381471389646 +0.374331550802 +0.369393139842 +0.380434782609 +0.37037037037 +0.378378378378 +0.373333333333 +0.358974358974 +0.382513661202 +0.385674931129 +0.360824742268 +0.359897172236 +0.376344086022 +0.383561643836 +0.394366197183 +0.367454068241 +0.380434782609 +0.375335120643 + diff --git a/trimDACtest/trimDacFallingEdge.pickle b/trimDACtest/trimDacFallingEdge.pickle new file mode 100644 index 0000000..7b716ee --- /dev/null +++ b/trimDACtest/trimDacFallingEdge.pickle @@ -0,0 +1,1256 @@ +(lp0 +(lp1 +I3 +aI5 +aI8 +aI10 +aI13 +aI16 +aI19 +aI22 +aI24 +aI27 +aI30 +aI33 +aI36 +aI39 +aI41 +aI44 +aI46 +aI50 +aI52 +aI55 +aI56 +aI60 +aI63 +aI66 +aI69 +aI71 +aI75 +aI77 +aI79 +aI82 +aI85 +aI88 +aa(lp2 +I16 +aI19 +aI21 +aI24 +aI28 +aI30 +aI34 +aI37 +aI39 +aI43 +aI45 +aI48 +aI52 +aI54 +aI58 +aI60 +aI62 +aI65 +aI66 +aI71 +aI74 +aI77 +aI80 +aI81 +aI84 +aI87 +aI91 +aI94 +aI97 +aI100 +aI103 +aI106 +aa(lp3 +I47 +aI49 +aI52 +aI54 +aI57 +aI59 +aI62 +aI64 +aI68 +aI70 +aI73 +aI75 +aI78 +aI81 +aI83 +aI86 +aI88 +aI90 +aI93 +aI95 +aI99 +aI101 +aI104 +aI107 +aI110 +aI112 +aI115 +aI117 +aI120 +aI123 +aI125 +aI128 +aa(lp4 +I3 +aI5 +aI8 +aI11 +aI14 +aI17 +aI20 +aI23 +aI26 +aI29 +aI33 +aI36 +aI39 +aI42 +aI45 +aI48 +aI51 +aI54 +aI57 +aI60 +aI63 +aI66 +aI68 +aI72 +aI75 +aI78 +aI81 +aI84 +aI87 +aI90 +aI92 +aI96 +aa(lp5 +I29 +aI32 +aI33 +aI38 +aI40 +aI43 +aI46 +aI49 +aI53 +aI56 +aI59 +aI62 +aI64 +aI67 +aI69 +aI71 +aI74 +aI79 +aI81 +aI83 +aI86 +aI90 +aI92 +aI95 +aI99 +aI102 +aI105 +aI108 +aI110 +aI113 +aI116 +aI119 +aa(lp6 +I10 +aI13 +aI15 +aI18 +aI2 +aI3 +aI4 +aI6 +aI9 +aI12 +aI15 +aI18 +aI20 +aI24 +aI27 +aI29 +aI32 +aI36 +aI39 +aI42 +aI45 +aI47 +aI51 +aI53 +aI55 +aI58 +aI60 +aI65 +aI67 +aI70 +aI73 +aI76 +aa(lp7 +I28 +aI30 +aI33 +aI2 +aI21 +aI24 +aI26 +aI29 +aI33 +aI36 +aI39 +aI42 +aI44 +aI47 +aI50 +aI53 +aI56 +aI59 +aI60 +aI63 +aI67 +aI70 +aI73 +aI75 +aI79 +aI82 +aI85 +aI88 +aI89 +aI93 +aI96 +aI99 +aa(lp8 +I4 +aI6 +aI9 +aI36 +aI3 +aI6 +aI10 +aI12 +aI15 +aI18 +aI21 +aI23 +aI27 +aI29 +aI34 +aI36 +aI40 +aI43 +aI46 +aI49 +aI53 +aI55 +aI59 +aI61 +aI64 +aI67 +aI70 +aI73 +aI76 +aI79 +aI82 +aI85 +aa(lp9 +I26 +aI26 +aI31 +aI12 +aI39 +aI42 +aI46 +aI48 +aI51 +aI54 +aI56 +aI60 +aI63 +aI65 +aI69 +aI71 +aI73 +aI75 +aI79 +aI81 +aI85 +aI88 +aI90 +aI94 +aI95 +aI99 +aI102 +aI105 +aI108 +aI110 +aI114 +aI117 +aa(lp10 +I16 +aI19 +aI21 +aI34 +aI15 +aI18 +aI21 +aI24 +aI26 +aI29 +aI31 +aI35 +aI38 +aI41 +aI44 +aI47 +aI49 +aI50 +aI54 +aI57 +aI59 +aI63 +aI66 +aI68 +aI71 +aI73 +aI77 +aI79 +aI82 +aI85 +aI88 +aI91 +aa(lp11 +I18 +aI20 +aI23 +aI25 +aI38 +aI39 +aI42 +aI45 +aI48 +aI51 +aI53 +aI56 +aI60 +aI63 +aI65 +aI68 +aI69 +aI72 +aI74 +aI77 +aI79 +aI83 +aI86 +aI89 +aI91 +aI94 +aI97 +aI100 +aI103 +aI106 +aI109 +aI111 +aa(lp12 +I2 +aI3 +aI6 +aI26 +aI28 +aI31 +aI34 +aI38 +aI41 +aI44 +aI46 +aI48 +aI53 +aI56 +aI58 +aI62 +aI63 +aI67 +aI69 +aI72 +aI76 +aI79 +aI81 +aI84 +aI88 +aI91 +aI93 +aI96 +aI100 +aI103 +aI105 +aI109 +aa(lp13 +I15 +aI19 +aI21 +aI9 +aI28 +aI31 +aI35 +aI37 +aI40 +aI43 +aI46 +aI48 +aI50 +aI54 +aI57 +aI59 +aI63 +aI66 +aI66 +aI71 +aI74 +aI77 +aI79 +aI81 +aI84 +aI87 +aI91 +aI94 +aI96 +aI99 +aI102 +aI105 +aa(lp14 +I2 +aI2 +aI2 +aI25 +aI11 +aI13 +aI16 +aI19 +aI2 +aI3 +aI3 +aI6 +aI8 +aI11 +aI14 +aI16 +aI20 +aI23 +aI26 +aI29 +aI31 +aI35 +aI37 +aI40 +aI43 +aI46 +aI49 +aI52 +aI54 +aI58 +aI60 +aI63 +aa(lp15 +I5 +aI2 +aI4 +aI5 +aI28 +aI30 +aI34 +aI37 +aI22 +aI23 +aI27 +aI29 +aI32 +aI35 +aI38 +aI41 +aI43 +aI47 +aI49 +aI52 +aI54 +aI57 +aI60 +aI63 +aI64 +aI68 +aI70 +aI73 +aI76 +aI78 +aI81 +aI84 +aa(lp16 +I50 +aI8 +aI10 +aI7 +aI8 +aI10 +aI14 +aI16 +aI38 +aI40 +aI45 +aI47 +aI50 +aI53 +aI56 +aI59 +aI60 +aI63 +aI66 +aI69 +aI70 +aI72 +aI78 +aI81 +aI83 +aI85 +aI88 +aI91 +aI94 +aI97 +aI101 +aI103 +aa(lp17 +I7 +aI52 +aI55 +aI13 +aI9 +aI13 +aI14 +aI18 +aI20 +aI23 +aI26 +aI29 +aI31 +aI35 +aI38 +aI41 +aI45 +aI48 +aI51 +aI54 +aI56 +aI59 +aI63 +aI66 +aI68 +aI72 +aI75 +aI78 +aI80 +aI84 +aI86 +aI90 +aa(lp18 +I27 +aI9 +aI12 +aI58 +aI16 +aI18 +aI21 +aI24 +aI21 +aI23 +aI26 +aI29 +aI32 +aI35 +aI38 +aI41 +aI45 +aI47 +aI50 +aI53 +aI56 +aI59 +aI61 +aI64 +aI65 +aI70 +aI73 +aI76 +aI79 +aI81 +aI84 +aI87 +aa(lp19 +I22 +aI29 +aI32 +aI14 +aI61 +aI63 +aI67 +aI70 +aI27 +aI30 +aI33 +aI36 +aI38 +aI42 +aI44 +aI47 +aI50 +aI53 +aI55 +aI59 +aI62 +aI64 +aI66 +aI70 +aI73 +aI76 +aI78 +aI81 +aI84 +aI87 +aI88 +aI93 +aa(lp20 +I4 +aI25 +aI26 +aI35 +aI17 +aI20 +aI23 +aI26 +aI72 +aI75 +aI78 +aI80 +aI83 +aI86 +aI89 +aI92 +aI94 +aI98 +aI100 +aI103 +aI107 +aI109 +aI112 +aI114 +aI117 +aI120 +aI122 +aI125 +aI128 +aI132 +aI135 +aI137 +aa(lp21 +I27 +aI8 +aI2 +aI30 +aI37 +aI39 +aI42 +aI46 +aI28 +aI30 +aI34 +aI36 +aI39 +aI42 +aI44 +aI47 +aI50 +aI53 +aI55 +aI58 +aI61 +aI64 +aI66 +aI69 +aI71 +aI75 +aI77 +aI80 +aI83 +aI85 +aI88 +aI90 +aa(lp22 +I22 +aI30 +aI10 +aI3 +aI34 +aI36 +aI39 +aI42 +aI49 +aI51 +aI54 +aI57 +aI59 +aI62 +aI65 +aI67 +aI70 +aI74 +aI76 +aI79 +aI82 +aI85 +aI87 +aI90 +aI93 +aI96 +aI98 +aI101 +aI104 +aI106 +aI109 +aI112 +aa(lp23 +I17 +aI24 +aI33 +aI13 +aI5 +aI8 +aI11 +aI13 +aI46 +aI47 +aI50 +aI54 +aI57 +aI60 +aI62 +aI65 +aI66 +aI71 +aI73 +aI76 +aI79 +aI82 +aI84 +aI87 +aI91 +aI92 +aI97 +aI100 +aI102 +aI105 +aI108 +aI111 +aa(lp24 +I26 +aI20 +aI26 +aI36 +aI16 +aI18 +aI21 +aI24 +aI15 +aI18 +aI21 +aI24 +aI27 +aI29 +aI33 +aI36 +aI38 +aI41 +aI43 +aI46 +aI49 +aI52 +aI55 +aI58 +aI59 +aI63 +aI66 +aI67 +aI70 +aI74 +aI77 +aI79 +aa(lp25 +I23 +aI29 +aI23 +aI30 +aI39 +aI42 +aI2 +aI3 +aI27 +aI31 +aI34 +aI37 +aI39 +aI43 +aI45 +aI48 +aI51 +aI54 +aI57 +aI60 +aI63 +aI66 +aI68 +aI71 +aI75 +aI77 +aI80 +aI83 +aI85 +aI89 +aI91 +aI94 +aa(lp26 +I14 +aI26 +aI31 +aI25 +aI32 +aI36 +aI45 +aI48 +aI6 +aI9 +aI11 +aI14 +aI15 +aI19 +aI21 +aI25 +aI28 +aI31 +aI34 +aI37 +aI39 +aI42 +aI45 +aI48 +aI51 +aI54 +aI57 +aI59 +aI61 +aI64 +aI67 +aI70 +aa(lp27 +I12 +aI16 +aI29 +aI34 +aI28 +aI31 +aI38 +aI41 +aI50 +aI53 +aI56 +aI59 +aI62 +aI65 +aI69 +aI71 +aI73 +aI75 +aI79 +aI81 +aI85 +aI89 +aI91 +aI94 +aI96 +aI100 +aI103 +aI106 +aI109 +aI112 +aI114 +aI117 +aa(lp28 +I2 +aI14 +aI19 +aI32 +aI37 +aI39 +aI34 +aI37 +aI45 +aI47 +aI50 +aI53 +aI55 +aI59 +aI61 +aI64 +aI66 +aI70 +aI72 +aI75 +aI78 +aI80 +aI81 +aI86 +aI90 +aI92 +aI95 +aI98 +aI101 +aI104 +aI107 +aI108 +aa(lp29 +I28 +aI2 +aI15 +aI22 +aI36 +aI39 +aI42 +aI44 +aI40 +aI43 +aI45 +aI48 +aI50 +aI55 +aI57 +aI61 +aI63 +aI65 +aI69 +aI71 +aI74 +aI77 +aI80 +aI83 +aI86 +aI89 +aI91 +aI94 +aI97 +aI100 +aI103 +aI106 +aa(lp30 +I16 +aI31 +aI3 +aI19 +aI24 +aI27 +aI41 +aI44 +aI47 +aI50 +aI53 +aI56 +aI59 +aI62 +aI64 +aI67 +aI69 +aI73 +aI75 +aI77 +aI79 +aI83 +aI86 +aI89 +aI91 +aI95 +aI98 +aI100 +aI103 +aI106 +aI109 +aI112 +aa(lp31 +I28 +aI3 +aI33 +aI5 +aI22 +aI25 +aI29 +aI31 +aI48 +aI51 +aI54 +aI57 +aI59 +aI62 +aI65 +aI68 +aI70 +aI73 +aI75 +aI77 +aI79 +aI84 +aI87 +aI89 +aI93 +aI96 +aI99 +aI102 +aI105 +aI106 +aI110 +aI113 +aa(lp32 +I15 +aI19 +aI2 +aI37 +aI7 +aI10 +aI27 +aI30 +aI35 +aI38 +aI40 +aI43 +aI45 +aI48 +aI51 +aI53 +aI54 +aI58 +aI60 +aI63 +aI66 +aI69 +aI71 +aI74 +aI76 +aI79 +aI82 +aI85 +aI86 +aI90 +aI92 +aI95 +aa(lp33 +I5 +aI31 +aI21 +aI3 +aI40 +aI43 +aI13 +aI16 +aI33 +aI36 +aI38 +aI41 +aI44 +aI46 +aI49 +aI51 +aI54 +aI57 +aI60 +aI63 +aI65 +aI68 +aI71 +aI73 +aI76 +aI79 +aI82 +aI84 +aI86 +aI89 +aI92 +aI95 +aa(lp34 +I6 +aI18 +aI33 +aI25 +aI6 +aI9 +aI45 +aI48 +aI19 +aI21 +aI24 +aI26 +aI29 +aI32 +aI35 +aI37 +aI41 +aI44 +aI46 +aI49 +aI52 +aI55 +aI57 +aI60 +aI62 +aI66 +aI69 +aI71 +aI75 +aI77 +aI80 +aI82 +aa(lp35 +I6 +aI8 +aI21 +aI36 +aI27 +aI30 +aI12 +aI15 +aI51 +aI53 +aI57 +aI60 +aI62 +aI65 +aI68 +aI71 +aI73 +aI75 +aI79 +aI81 +aI84 +aI87 +aI90 +aI93 +aI95 +aI99 +aI102 +aI104 +aI107 +aI110 +aI113 +aI116 +aa(lp36 +I11 +aI9 +aI10 +aI24 +aI40 +aI43 +aI33 +aI36 +aI18 +aI20 +aI23 +aI26 +aI30 +aI32 +aI35 +aI38 +aI41 +aI44 +aI47 +aI50 +aI53 +aI56 +aI58 +aI61 +aI64 +aI67 +aI69 +aI73 +aI76 +aI79 +aI82 +aI84 +aa(lp37 +I3 +aI2 +aI12 +aI13 +aI27 +aI30 +aI45 +aI48 +aI39 +aI42 +aI45 +aI48 +aI50 +aI53 +aI56 +aI59 +aI63 +aI66 +aI69 +aI71 +aI74 +aI77 +aI79 +aI81 +aI86 +aI87 +aI91 +aI94 +aI96 +aI100 +aI103 +aI105 +aa(lp38 +I17 +aI9 +aI3 +aI16 +aI14 +aI3 +aI33 +aI36 +aI51 +aI55 +aI57 +aI60 +aI63 +aI66 +aI69 +aI71 +aI73 +aI77 +aI79 +aI81 +aI86 +aI89 +aI91 +aI94 +aI96 +aI101 +aI103 +aI106 +aI110 +aI112 +aI115 +aI118 +aa. \ No newline at end of file diff --git a/trimDACtest/trim_scan.py b/trimDACtest/trim_scan.py new file mode 100644 index 0000000..a765749 --- /dev/null +++ b/trimDACtest/trim_scan.py @@ -0,0 +1,276 @@ +# Change trimDAC, then do threshold scan. Repeat for all trimDACs to identify nonlinear behaviour etc + +import sys +from ROOT import TGraph, TCanvas, TLine +from classes import * +from array import array +from optparse import OptionParser +import pickle + +parser = OptionParser() + +# General options + +parser.add_option('-m', '--MPA', metavar='N', type='int', +default = '1', +dest = 'mpanum', +help = 'Calibrate MPA N') + +parser.add_option('-r', '--resolution',metavar='N', type='int', +default = '1', +dest = 'resolution', +help = 'Only scan every N thresholds to speed up scan. Results in lower precision of TrimDACs') + +# CALDAC options (setting charge also enables calDAC) + +parser.add_option('-e', '--enable', action='store_true', +dest = 'calEnbl', +default = False, +help = 'Enable calibration') + +parser.add_option('-c', '--charge',metavar='C', type='int', +dest = 'calCharge', +help = 'Enable calibration with charge C (0 - 0xFF). If not set CalDAC is disabled.') + +parser.add_option('-n', '--number',metavar='N', type='int', +dest = 'calNum', +help = 'Number of calibration pulses') + +parser.add_option('-l', '--strobelength',metavar='N', type='int', +dest = 'calLen', +help = 'Length of calibration pulses') + +# Shutter length + +parser.add_option('-s', '--shutterdur',metavar='N', type='int', +default = '0xFFFF', +dest = 'shutterDur', +help = 'Shutter open time (0 - 0xFFFF).') + +(options, args) = parser.parse_args() + +if options.calEnbl == None and (options.calCharge != None or options.calNum != None or options.calLen !=None): # Check if user has forgotten to enable calibration + print "Calibration isn't enabled, setting charge, number or length will have no effect." + quit() +else: # Defaults for calibration but no explicit charge, number or strobe length + options.calCharge = 80 + options.calNum = 1000 + options.calLen = 40 + + +# Connection and GLIB +a = uasic(connection="file://connections_test.xml",device="board0") +glib = a._hw + +# Source all classes +mapsa = MAPSA(a) + +# Get all 6 MPAs and corresponding configs +mpa=[] +conf=[] + +for i in range(0,6): + mpa.append(MPA(glib,i+1)) + conf.append(mpa[i].config("data/Default_MPA.xml")) + +# Define MPA (1-6) (iMPA 2 or 5 for double assembly) + +mpaDict = {0:2,1:5} +iMPA = options.mpanum - 1 # Zero-indexed (from 0 to 5 on full assembly) + +# Set voltage steps of threshold DAC and trimming DAC (in mV/Step) +thrVoltStep = 1.456 +trimVoltStep = 3.75 + +# Modify config + +glib.getNode("Control").getNode("MPA_clock_enable").write(0x1) +glib.dispatch() + +glib.getNode("Configuration").getNode("num_MPA").write(0x2) + +# Define default config + +defaultPixelCfg = {'PML':1,'ARL':1,'CEL':int(options.calEnbl),'CW':0,'PMR':1,'ARR':1,'CER':int(options.calEnbl),'SP':0,'SR':1,'TRIMDACL':0,'TRIMDACR':0} +defaultPeripheryCfg = {'OM':3,'RT':0,'SCW':0,'SH2':0,'SH1':0,'THDAC':0,'CALDAC':options.calCharge} +if options.calEnbl: + mapsa.daq().Strobe_settings(options.calNum,0x8F,options.calLen,40,cal=1) # Push number of pulses, delay between shutter open and first pulse, length of pulses, time between pulses, enable calibration (on GLIB) to GLIB + +# Upload +for key in defaultPeripheryCfg: + conf[iMPA].modifyperiphery(key,defaultPeripheryCfg[key]) +for pix in range(0,24): + for key in defaultPixelCfg: + conf[iMPA].modifypixel(pix + 1,key,defaultPixelCfg[key]) + +conf[iMPA].upload() +glib.getNode("Configuration").getNode("mode").write(0x1) +glib.dispatch() + + + +# Arrays to be filled by trim scan. In the end they contain a threshold scan for each trimming value +eventTrimArray = [] +hitTrimArray = [] +thrTrimArray = [] +bxTrimArray = [] +hitTrimArrayCounter = [] + +for trim in range(0, 32): + for pix in range(0,24): # No dispatch, upload or write necessary as that happens in first threshold scan + conf[iMPA].modifypixel(pix + 1,'TRIMDACL',trim) + conf[iMPA].modifypixel(pix + 1,'TRIMDACR',trim) + + # Arrays to be filled by threshold scan + eventArray = [] + hitArray = [] + thrArray = [] + bxArray = [] + hitArrayCounter = [] + + # Start threshold scan + for thr in range(0,255, options.resolution): # Only every 'options.resolution'-steps, reflected in precision of falling edges after trimming + + #print thr + # Apply threshold + + conf[iMPA].modifyperiphery('THDAC',thr) + conf[iMPA].upload() + + glib.getNode("Configuration").getNode("mode").write(0x1) + conf[iMPA].spi_wait() # includes dispatch + + + ########################## + ####### Sequencer ######## + ########################## + # Opens shutter (mode = 0x0 single shutter, 0x1 four (buffers) consequitive shutter) + # Set shutter duration + # Write in first buffer (default and therefore not necessary to be defined) + # Readout has to be enabled in order to get the data. Default. + mapsa.daq().Sequencer_init(0, options.shutterDur ) + + counter = glib.getNode("Readout").getNode("Counter").getNode("MPA"+str(iMPA + 1)).getNode("buffer_1").readBlock(25) + glib.dispatch() + + + # Readout ripple counter + counterArray = [] + for x in range(1,len(counter)): # Skip header at [0] + counterArray.append(counter[x] & 0x7FFF) # Mask to select left pixel. First bit is not considered as this seems sometimes to be set erronously. (Lots of entries with 0b1000000000000000) + counterArray.append((counter[x] >> 16) & 0x7FFF) # Mask to select right pixel. Same as above. + + # Readout buffer (TRUE / FALSE : Wait for sequencer) + mem = mpa[mpaDict[iMPA]-1].daq().read_raw(1,1,True)[0] + + # Mem integer array to binary string in readable order (header,bx,pix) + binMemStr= "" + for i in range(0,216): + binMemStr = binMemStr + '{0:032b}'.format(mem[215-i]) + + # String to binary array + binMem = [binMemStr[x:x+72] for x in range(0,len(binMemStr),72)] + + # Get elements of binary string + hd = [] + bx = [] + pix = [] + for entry in binMem: + hd.append(entry[0:8]) + bx.append(entry[8:24]) + pix.append(entry[24:72]) + + # Count number of Events + nEvents = 0 + for event in hd: + if event == "11111111": + nEvents+=1 + + # Sum hits per pixel + sumPixHits = [0]*48 + for event in pix: + for i, ipix in enumerate(event): + sumPixHits[i]+=int(ipix) + + # bunch crossing from binary to int + bx=[int(ibx,2) for ibx in bx] + + eventArray.append(nEvents) + hitArray.append(sumPixHits) + thrArray.append(thr) + bxArray.append(bx) + hitArrayCounter.append(counterArray) + + + print "---END OF SCAN--- of trim %s" %trim + + eventTrimArray.append(eventArray) + hitTrimArray.append(hitArray) + thrTrimArray.append(thrArray) + bxTrimArray.append(bxArray) + hitTrimArrayCounter.append(hitArrayCounter) + +# New arrays with threshold scan for each trim +pxlVsThrMemTrim = [] +pxlVsThrCounterTrim = [] + +graphsMemTrim = [] +graphsCounterTrim = [] +maxHitsPerPixTrim = [] # For scaling of graphs +for trim in range(0,len(hitTrimArray)): + # Generate new list [TrimDAC1[[pix1_ThScan],[pix2_ThScan],..],TrimDAC1[[..]],...] from memory + pxlVsThrMem = [] + for ipix in range(0,len(hitTrimArray[trim][0])): + pxlVsThrMem.append([item[ipix] for item in hitTrimArray[trim]]) + pxlVsThrMemTrim.append(pxlVsThrMem) + + # Generate new list [[pix1_ThScan],[pix2_ThScan],..] from ripple counter + pxlVsThrCounter = [] + for ipix in range(0,len(hitTrimArrayCounter[trim][0])): + pxlVsThrCounter.append([item[ipix] for item in hitTrimArrayCounter[trim]]) + pxlVsThrCounterTrim.append(pxlVsThrCounter) + +# Find falling edges for each trim value and each pixel +trimFallingEdge = [] +for pxlVsThrCounter in pxlVsThrCounterTrim: + thrArrayFallingEdge = [] # Falling edges for this trimming value + + for pxl in pxlVsThrCounter: + + pxlMax = max(pxl) + thresholdValueAndPxl = zip(thrArray,pxl) # Match thresholds to amount of hits and create list of tuples + + maxBin = pxl.index(pxlMax) # Find lowest threshold with maximum amount of hits + pxlRightOfPeak = thresholdValueAndPxl[maxBin:] # Get rid of rising edge (less hits than maxbin) + + halfMax = pxlMax/2 # Middle of falling edge + for threshold in pxlRightOfPeak: # Find first threshold with less hits than middle of falling edge, then break + if threshold[1] < halfMax: + thrArrayFallingEdge.append(threshold[0]) + break # Only one threshold is needed, leave loop + + trimFallingEdge.append(thrArrayFallingEdge) + +# Turn array of trimming value arrays with pixels in the sub array into transposed array ( Pix1(trimDac[0-31]), Pix2(),.,,,Pix48(trimDac[0-31])) +pxlTrimFallingEdge = [list(trim) for trim in zip(*trimFallingEdge)] + +# Draw graphs on canvas +c1 = TCanvas("graph","graph",1024,768) + +graphs = [] +for pxl in pxlTrimFallingEdge: + graphs.append(TGraph(32,array('d',range(32)),array('d',pxl))) # Generate graph with trimDACs on x-axis and falling edge position (in threshold-steps) on y-axis + +for i,graph in enumerate(graphs): + graph.SetLineColor(i) + if i==0: + graph.SetTitle('Trim Scan;Trim (DAC);Falling Edge (Threshold)') + #graph.GetYaxis().SetRangeUser(0,max(maxHitsPerPixTrim[trim])*1.1) + graph.Draw("APL") + else: + graph.Draw("PL") + +pickle.dump(pxlTrimFallingEdge, open(str(sys.path[0])+"/trimDacFallingEdge.pickle", "w")) + + +raw_input("Press any key to exit") From 386ac6db6a5e65b1c599e43cfb99740e58aa3843 Mon Sep 17 00:00:00 2001 From: Gregor Vollmer Date: Mon, 20 Feb 2017 16:16:03 +0100 Subject: [PATCH 02/10] Added command line and ran autopep8 --- advancedTrimDacCalibration.py | 89 +++++++------ daq/daq_continuous_2MPA.py | 243 +++++++++++++++++++--------------- 2 files changed, 187 insertions(+), 145 deletions(-) diff --git a/advancedTrimDacCalibration.py b/advancedTrimDacCalibration.py index ed83474..12acab9 100644 --- a/advancedTrimDacCalibration.py +++ b/advancedTrimDacCalibration.py @@ -3,14 +3,16 @@ from ROOT import gStyle, TGraph, TCanvas, TLine, TF1, TFile import xml.etree.ElementTree as ET -assembly = [2,5] +assembly = [2, 5] calibration = MPACalibration(assembly) -mpaConfig = [] +mpaConfig = [] for MPA in assembly: - mpaConfig.append(ET.parse("data/Conf_default_MPA"+str(MPA)+"_config1.xml")) # Construct list of XML files, one for each MPA + # Construct list of XML files, one for each MPA + mpaConfig.append( + ET.parse("data/Conf_default_MPA" + str(MPA) + "_config1.xml")) -calibration.thresholdScan(calEnbl = True) +calibration.thresholdScan(calEnbl=True) calibration.writeCalibrationToMPA() calibration.thresholdScan() @@ -24,47 +26,51 @@ for iMPA, edge in enumerate(preScanEdges): plot = MPAPlot() plot.fillHisto(edge) - plot.setTitle('Falling edges of MPA ' + str(assembly[iMPA]) + ' after calibration with fixed ThrDAC/TrimDAC-ratio; Threshold (DAC);# of Pixels') + plot.setTitle('Falling edges of MPA ' + str(assembly[ + iMPA]) + ' after calibration with fixed ThrDAC/TrimDAC-ratio; Threshold (DAC);# of Pixels') plot.draw() histo = plot.getPlot(0) RMS.append(histo.GetRMS()) histo.Write() - -calibration.trimScan(resolution = 1) -trimScanEdges = calibration.getTrimScanEdges() # MPA[trim[pix]] +calibration.trimScan(resolution=1) + +trimScanEdges = calibration.getTrimScanEdges() # MPA[trim[pix]] trimArray = calibration.getTrimScanMetadata() fitvalsMPA = [] for nMPA, MPA in enumerate(trimScanEdges): - MPA = [list(pix) for pix in zip(*MPA)] #Turn trim[pix] into pix[trim] for easier plotting + # Turn trim[pix] into pix[trim] for easier plotting + MPA = [list(pix) for pix in zip(*MPA)] plot = MPAPlot() - for pix in MPA: + for pix in MPA: plot.createGraph(trimArray, pix) plot.draw() graphs = plot.getPlot() - fitFunc = TF1("fa1","[0]+x*[1]",0,32) + fitFunc = TF1("fa1", "[0]+x*[1]", 0, 32) fitvals = [] - mpaDir = rootFile.mkdir("Edges vs Trim "+str(assembly[nMPA]), "Edges vs Trim"+str(assembly[nMPA])) + mpaDir = rootFile.mkdir( + "Edges vs Trim " + str(assembly[nMPA]), "Edges vs Trim" + str(assembly[nMPA])) print graphs - for i,graph in enumerate(graphs): - graph.SetLineColor(i+1) + for i, graph in enumerate(graphs): + graph.SetLineColor(i + 1) graph.SetMarkerStyle(8) - fitFunc.SetName("Fit for pixel "+str(i+1)) + fitFunc.SetName("Fit for pixel " + str(i + 1)) result = graph.Fit(fitFunc.GetName(), "S") - graph.GetYaxis().SetRangeUser(0,255) - graph.GetXaxis().SetRangeUser(0,220) - if i==0: - graph.SetTitle('Trim Scan of MPA '+str(assembly[nMPA])+';Trim (DAC);Falling Edge (Threshold)') + graph.GetYaxis().SetRangeUser(0, 255) + graph.GetXaxis().SetRangeUser(0, 220) + if i == 0: + graph.SetTitle( + 'Trim Scan of MPA ' + str(assembly[nMPA]) + ';Trim (DAC);Falling Edge (Threshold)') mpaDir.Add(graph) graph.Draw("APL") else: - graph.SetTitle('Pixel ' +str(i+1)) + graph.SetTitle('Pixel ' + str(i + 1)) mpaDir.Add(graph) graph.Draw("PL") - fitvals.append(1/result.Parameter(1)) + fitvals.append(1 / result.Parameter(1)) mpaDir.Write() raw_input("Press any key to proceed") @@ -78,50 +84,55 @@ histo = plot.getPlot(0) histo.Write() -calibration.thresholdScan(calEnbl = True) +calibration.thresholdScan(calEnbl=True) -trimDac = calibration.getTrimBits(ratioThrTrim = fitvalsMPA) +trimDac = calibration.getTrimBits(ratioThrTrim=fitvalsMPA) -calibration.writeCalibrationToMPA(trimDAC = trimDac) +calibration.writeCalibrationToMPA(trimDAC=trimDac) -for iMPA, MPAtree in enumerate(mpaConfig): # loop over configs for individual MPAs +# loop over configs for individual MPAs +for iMPA, MPAtree in enumerate(mpaConfig): MPA = MPAtree.getroot() - for iPix,pixel in enumerate(MPA.findall('pixel')): - pixel.find('TRIMDACL').text = str(trimDac[iMPA][2*iPix]) - pixel.find('TRIMDACR').text = str(trimDac[iMPA][2*iPix+1]) + for iPix, pixel in enumerate(MPA.findall('pixel')): + pixel.find('TRIMDACL').text = str(trimDac[iMPA][2 * iPix]) + pixel.find('TRIMDACR').text = str(trimDac[iMPA][2 * iPix + 1]) if pixel.find('THRTRIMRATIOL') is None: ET.SubElement(pixel, 'THRTRIMRATIOL') if pixel.find('THRTRIMRATIOR') is None: ET.SubElement(pixel, 'THRTRIMRATIOR') - pixel.find('THRTRIMRATIOL').text = '{0:.5}'.format(str(fitvalsMPA[iMPA][2*iPix])) - pixel.find('THRTRIMRATIOR').text = '{0:.5}'.format(str(fitvalsMPA[iMPA][2*iPix + 1 ])) - - MPAtree.write('data/Conf_trimcalib_MPA'+str(assembly[iMPA])+'_config1.xml') + pixel.find('THRTRIMRATIOL').text = '{0:.5}'.format( + str(fitvalsMPA[iMPA][2 * iPix])) + pixel.find('THRTRIMRATIOR').text = '{0:.5}'.format( + str(fitvalsMPA[iMPA][2 * iPix + 1])) + + MPAtree.write('data/Conf_trimcalib_MPA' + + str(assembly[iMPA]) + '_config1.xml') calibration.thresholdScan() counter, _ = calibration.getThrScanPerPix() -postScanEdges = calibration.findFallingEdges() +postScanEdges = calibration.findFallingEdges() for mpa in counter: plot = MPAPlot() for pix in mpa: - plot.createGraph(range(0,255), pix) + plot.createGraph(range(0, 255), pix) graphs = plot.getPlot() for i, graph in enumerate(graphs): - graph.SetTitle('Pixel ' +str(i+1)) + graph.SetTitle('Pixel ' + str(i + 1)) if i == 0: graph.Draw("APL") else: graph.Draw("PL") - + raw_input() -for iMPA,edge in enumerate(postScanEdges): +for iMPA, edge in enumerate(postScanEdges): plot = MPAPlot() plot.fillHisto(edge) - plot.setTitle('Falling edges of MPA ' + str(assembly[iMPA]) + ' after calibration with ThrDAC/TrimDAC-ratios from trim scan; Threshold (DAC);# of Pixels') + plot.setTitle('Falling edges of MPA ' + str(assembly[ + iMPA]) + ' after calibration with ThrDAC/TrimDAC-ratios from trim scan; Threshold (DAC);# of Pixels') histo = plot.getPlot(0) RMS.append(histo.GetRMS()) histo.Write() @@ -130,4 +141,4 @@ print trimDac -print "Root mean squares before trim scan: %s and %s. Root mean squares after trim scan: %s and %s." %(RMS[0], RMS[1], RMS[2], RMS[3]) +print "Root mean squares before trim scan: %s and %s. Root mean squares after trim scan: %s and %s." % (RMS[0], RMS[1], RMS[2], RMS[3]) diff --git a/daq/daq_continuous_2MPA.py b/daq/daq_continuous_2MPA.py index 3994a29..fab03ba 100644 --- a/daq/daq_continuous_2MPA.py +++ b/daq/daq_continuous_2MPA.py @@ -2,14 +2,38 @@ import os from classes import * from array import array -from ROOT import TGraph, TCanvas, TLine, TTree, TFile import time +import argparse +import errno + +parser = argparse.ArgumentParser(description="MaPSA DAQ") +parser.add_argument("--external-clock", "-x", default=False, + help="Use external 40MHz clock, e.g. for testbeam operation.", action="store_true") +parser.add_argument("--threshold", "-t", type=int, + metavar="BYTE", help="Threshold value", default="100") +parser.add_argument("--assembly", "-a", metavar="NAME", + help="Name of the assembly, used to differentiate trimming configurations", default="default") +parser.add_argument("--mpa-index", "-i", metavar="IDX", type=int, choices=range(1, 7), + action="append", help="Specify the indices of the MPAs in the SPI chain", default=[]) +parser.add_argument("--output-dir", "-o", metavar="DIR", + help="Directory where run data is stored", default="./data") +parser.add_argument("--config", "-c", metavar="FILEFORMAT", + help="Filename format string for trimming and masking MPA configuration. The variables {assembly} and {mpa} are available.", default="data/Conf-{assembly}_MPA-{mpa}.xml") + +args = parser.parse_args() + +# Importing ROOT before parsing argument messes up the help output. Well +# done, root. +from ROOT import TGraph, TCanvas, TLine, TTree, TFile -assembly = [2,5] +if args.mpa_index: + assembly = list(sorted(args.mpa_index)) +else: + assembly = [2, 5] -# Connection and GLIB -a = uasic(connection="file://connections_test.xml",device="board0") -glib = a._hw +# Connection and GLIB +a = uasic(connection="file://connections_test.xml", device="board0") +glib = a._hw # Enable clock on MPA glib.getNode("Control").getNode("MPA_clock_enable").write(0x1) @@ -24,34 +48,48 @@ conf = [] mpa = [] -for iMPA, nMPA in enumerate(assembly): - mpa.append(MPA(glib, iMPA+1)) # List of instances of MPA, one for each MPA. SPI-chain numbering! - #conf.append(mpa[iMPA].config("data/Conf_trimcalib_MPA" + str(nMPA)+ "_masked.xml")) # Use trimcalibrated config - conf.append(mpa[iMPA].config("data/Conf_default_MPA" + str(nMPA)+ "_config1.xml")) - -threshold = 100 -print "Threshold:", threshold +try: + for iMPA, nMPA in enumerate(assembly): + # List of instances of MPA, one for each MPA. SPI-chain numbering! + mpa.append(MPA(glib, iMPA + 1)) + # conf.append(mpa[iMPA].config("data/Conf_trimcalib_MPA" + str(nMPA)+ + # "_masked.xml")) # Use trimcalibrated config + conf.append(mpa[iMPA].config( + args.config.format(mpa=nMPA, assembly=args.assembly))) +except IOError, e: + if e.filename and e.errno == errno.ENOENT: + parser.error( + "Cannot open MPA configuration '{0}'.\nCheck --config and --assembly settings, or perform trimming.".format(e.filename)) + else: + raise # Define default config -for iMPA in range(0,len(assembly)): - conf[iMPA].modifyperiphery('THDAC',threshold) # Write threshold to MPA 'iMPA' - conf[iMPA].modifypixel(range(1,25), 'SR', 1) # Enable synchronous readout on all pixels - conf[iMPA].upload() # Push configuration to GLIB +for iMPA in range(0, len(assembly)): + # Write threshold to MPA 'iMPA' + conf[iMPA].modifyperiphery('THDAC', args.threshold) + # Enable synchronous readout on all pixels + conf[iMPA].modifypixel(range(1, 25), 'SR', 1) + conf[iMPA].upload() # Push configuration to GLIB glib.getNode("Configuration").getNode("mode").write(len(assembly) - 1) -conf[iMPA].spi_wait() # includes dispatch +conf[iMPA].spi_wait() # includes dispatch glib.getNode("Configuration").getNode("num_MPA").write(len(assembly)) -glib.getNode("Configuration").getNode("mode").write(len(assembly) - 1) # This is a 'write' and pushes the configuration to the glib. Write must happen before starting the sequencer. -conf[0].spi_wait() # includes dispatch +# This is a 'write' and pushes the configuration to the glib. Write must +# happen before starting the sequencer. +glib.getNode("Configuration").getNode("mode").write(len(assembly) - 1) +conf[0].spi_wait() # includes dispatch -glib.getNode("Control").getNode('testbeam_clock').write(0x0) # Enable external clock -#glib.getNode("Control").getNode('testbeam_clock').write(0x1) # Enable external clock +if args.external_clock: + glib.getNode("Control").getNode('testbeam_clock').write(0x1) +else: + glib.getNode("Control").getNode('testbeam_clock').write(0x0) glib.getNode("Configuration").getNode("mode").write(len(assembly) - 1) glib.dispatch() -#shutterDur = 0xFFFFFFFF #0xFFFFFFFF is maximum, in clock cycles -shutterDur = 0xFFFFFF #0xFFFFFFFF is maximum, in clock cycles -mapsaClasses.daq().Sequencer_init(0x1,shutterDur, mem=1) # Start sequencer in continous daq mode. Already contains the 'write' +# shutterDur = 0xFFFFFFFF #0xFFFFFFFF is maximum, in clock cycles +shutterDur = 0xFFFFFF # 0xFFFFFFFF is maximum, in clock cycles +# Start sequencer in continous daq mode. Already contains the 'write' +mapsaClasses.daq().Sequencer_init(0x1, shutterDur, mem=1) ibuffer = 1 shutterCounter = 0 @@ -61,33 +99,52 @@ triggerStop = 500000 +print """Command Line Configuration +-------------------------- + Clock source is \x1b[1m{0}\x1b[m + Threshold = \x1b[1m{1}\x1b[m + MPA Indices = \x1b[1m{2}\x1b[m + Assembly Name = \x1b[1m{3}\x1b[m + Output Dir = \x1b[1m{4}\x1b[m +""".format("external" if args.external_clock else "internal", + args.threshold, + assembly, + args.assembly, + os.path.abspath(args.output_dir) + ) + try: while True: - freeBuffers = glib.getNode("Control").getNode('Sequencer').getNode('buffers_num').read() + freeBuffers = glib.getNode("Control").getNode( + 'Sequencer').getNode('buffers_num').read() glib.dispatch() - if freeBuffers < 3: # When set to 4 this produces duplicate entries, 3 (= 2 full buffers) avoids this. + # When set to 4 this produces duplicate entries, 3 (= 2 full buffers) + # avoids this. + if freeBuffers < 3: - if shutterCounter%2000 == 0: + if shutterCounter % 2000 == 0: startTime = time.time() shutterTimeStart = shutterCounter - if shutterCounter%100 == 0 and (shutterCounter - shutterTimeStart) >= 0.1: - frequency = (shutterCounter - shutterTimeStart)/(time.time() - startTime) - - + if shutterCounter % 100 == 0 and (shutterCounter - shutterTimeStart) >= 0.1: + frequency = (shutterCounter - shutterTimeStart) / \ + (time.time() - startTime) + MAPSACounter = [] MAPSAMemory = [] for iMPA, nMPA in enumerate(assembly): - counterData = glib.getNode("Readout").getNode("Counter").getNode("MPA"+str(iMPA + 1)).getNode("buffer_"+str(ibuffer)).readBlock(25) - memoryData = glib.getNode("Readout").getNode("Memory").getNode("MPA"+str(nMPA)).getNode("buffer_"+str(ibuffer)).readBlock(216) + counterData = glib.getNode("Readout").getNode("Counter").getNode( + "MPA" + str(iMPA + 1)).getNode("buffer_" + str(ibuffer)).readBlock(25) + memoryData = glib.getNode("Readout").getNode("Memory").getNode( + "MPA" + str(nMPA)).getNode("buffer_" + str(ibuffer)).readBlock(216) glib.dispatch() - #print "Buffer: %s iMPA: %s nMPA: %s" %(ibuffer, iMPA, nMPA) - #print counterData - #print '{0:032b}'.format(counterData[0]) - #print memoryData - #print "\n" + # print "Buffer: %s iMPA: %s nMPA: %s" %(ibuffer, iMPA, nMPA) + # print counterData + # print '{0:032b}'.format(counterData[0]) + # print memoryData + # print "\n" MAPSACounter.append(counterData) MAPSAMemory.append(memoryData) @@ -96,15 +153,14 @@ if ibuffer > 4: ibuffer = 1 - shutterCounter+=1 - + shutterCounter += 1 + # Only contains valVectors: - counterArray.append(MAPSACounter) + counterArray.append(MAPSACounter) memoryArray.append(MAPSAMemory) - print "Shutter counter: %s Free buffers: %s Frequency: %s " %(shutterCounter, freeBuffers, frequency) - + print "Shutter counter: %s Free buffers: %s Frequency: %s " % (shutterCounter, freeBuffers, frequency) - ############## Continuous operation in bash loop + # Continuous operation in bash loop if shutterCounter == triggerStop: endTimeStamp = time.time() @@ -112,61 +168,35 @@ if time.time() - endTimeStamp > 2: break - + except KeyboardInterrupt: pass -#finally: -# while ibuffer <= 4: -# -# freeBuffers = glib.getNode("Control").getNode('Sequencer').getNode('buffers_num').read() -# glib.dispatch() -# if freeBuffers < 3: -# MAPSACounter = [] -# MAPSAMemory = [] -# for iMPA, nMPA in enumerate(assembly): -# counterData = glib.getNode("Readout").getNode("Counter").getNode("MPA"+str(iMPA + 1)).getNode("buffer_"+str(ibuffer)).readBlock(25) -# memoryData = glib.getNode("Readout").getNode("Memory").getNode("MPA"+str(nMPA)).getNode("buffer_"+str(ibuffer)).readBlock(216) -# glib.dispatch() -# -# MAPSACounter.append(counterData) -# MAPSAMemory.append(memoryData) -# -# shutterCounter += 1 -# ibuffer += 1 -# -# # Only contains valVectors: -# counterArray.append(MAPSACounter) -# memoryArray.append(MAPSAMemory) -# print "Shutter counter: %s Buffers num: %s " %(shutterCounter, freeBuffers) -# - -runNumber = 0 -runNumberFile = '/home/readout/TBdata/currentRun.txt' - -with open(runNumberFile,'r') as runFile: - runNumber = int(runFile.read()) - -with open(runNumberFile,'w') as newRunFile: - newRunFile.write(str(runNumber+1)) - - -print "End of Run %s" %runNumber - -memoryFile = open('/home/readout/TBdata/run%s_memory.txt' %('{0:04d}'.format(runNumber)), 'w') -counterFile = open('/home/readout/TBdata/run%s_counter.txt' %('{0:04d}'.format(runNumber)), 'w') - -for i, shutter in enumerate(counterArray): - for j,mpa in enumerate(shutter): - counterFile.write(str(mpa.value())+"\n") - memoryFile.write(str(memoryArray[i][j].value())+"\n") - -counterFile.close() -memoryFile.close() - - -print "All files saved" - +if len(counterArray): + runNumber = 0 + runNumberFile = os.path.join(args.output_dir, 'currentRun.txt') + try: + with open(runNumberFile, 'r') as runFile: + runNumber = int(runFile.read()) + except IOError: + pass + with open(runNumberFile, 'w') as newRunFile: + newRunFile.write(str(runNumber + 1)) + print "End of Run %s" % runNumber + memoryFile = open(os.path.join( + args.output_dir, 'run%s_memory.txt' % ('{0:04d}'.format(runNumber))), 'w') + counterFile = open(os.path.join( + args.output_dir, 'run%s_counter.txt' % ('{0:04d}'.format(runNumber))), 'w') + for i, shutter in enumerate(counterArray): + for j, mpa in enumerate(shutter): + counterFile.write(str(mpa.value()) + "\n") + memoryFile.write(str(memoryArray[i][j].value()) + "\n") + counterFile.close() + memoryFile.close() + print "All files saved" +else: + print "\x1b[1mNo data acquired, ignore.\x1b[m" + # nHitMax = 95 # nPixMax = 48 @@ -220,14 +250,15 @@ # counterData = [] # for x in range(1,len(counterArray[k][i])): # Skip header at [0] -# counterData.append(counterArray[k][i][x] & 0x7FFF) # Mask to select left pixel. First bit is not considered as this seems sometimes to be set erronously. (Lots of entries with 0b1000000000000000) -# counterData.append((counterArray[k][i][x] >> 16) & 0x7FFF) # Mask to select right pixel. Same as above. +# counterData.append(counterArray[k][i][x] & 0x7FFF) # Mask to select left pixel. First bit is not considered as this seems sometimes to be set erronously. (Lots of entries with 0b1000000000000000) +# counterData.append((counterArray[k][i][x] >> 16) & 0x7FFF) # Mask to +# select right pixel. Same as above. # ########################################################################################## -# ### Memory: 216x 32-Bit Words -> Array of Hits (Header,BunchCrossing,Pixarray) (Bits) ### +# ### Memory: 216x 32-Bit Words -> Array of Hits (Header,BunchCrossing,Pixarray) (Bits) ### # ########################################################################################## - -# # Mem integer array to binary string in readable order (header,bx,pix) + +# # Mem integer array to binary string in readable order (header,bx,pix) # binMemStr= "" # for j in range(0,216): # binMemStr = binMemStr + '{0:032b}'.format(mpa[215-j]) @@ -246,21 +277,21 @@ # pix.append(entry[24:]) # ##################################################################### - + # # Tree stuff - + # nHitsTmp = 0 # for hit in hd: # if hit == "11111111": # nHitsTmp+=1 - + # nHits[i][0] = 95 # headerArray[i]=[int(ihd,2) for ihd in hd] # bxArray[i]=[int(ibx,2) for ibx in bx] # hitArrayMemory[i]=pix # hitArrayCounter[i]=counterData - - + + # treeMPA1.Fill() # treeMPA2.Fill() From 3624ea84b2bb02416e748a78b19b749724fd56a0 Mon Sep 17 00:00:00 2001 From: Gregor Vollmer Date: Mon, 20 Feb 2017 16:39:04 +0100 Subject: [PATCH 03/10] Added command line options and ran autopep8 --- advancedTrimDacCalibration.py | 43 +++++++++++++++++++++++++++++++---- daq/daq_continuous_2MPA.py | 7 ++++-- 2 files changed, 44 insertions(+), 6 deletions(-) diff --git a/advancedTrimDacCalibration.py b/advancedTrimDacCalibration.py index 12acab9..694d8e6 100644 --- a/advancedTrimDacCalibration.py +++ b/advancedTrimDacCalibration.py @@ -1,16 +1,51 @@ from MPACalibration import MPACalibration from MPAPlot import MPAPlot -from ROOT import gStyle, TGraph, TCanvas, TLine, TF1, TFile import xml.etree.ElementTree as ET +import argparse +import errno +import os + +parser = argparse.ArgumentParser(description="MaPSA DAQ") +parser.add_argument("--assembly", "-a", metavar="NAME", + help="Name of the assembly, used to differentiate trimming configurations", default="default") +parser.add_argument("--mpa-index", "-i", metavar="IDX", type=int, choices=range(1, 7), + action="append", help="Specify the indices of the MPAs in the SPI chain", default=[]) +parser.add_argument("--config", "-c", metavar="FILEFORMAT", + help="Filename format string for trimming and masking MPA configuration. The variables {assembly} and {mpa} are available.", default="Conf-{assembly}_MPA-{mpa}.xml") +parser.add_argument("--config-dir", metavar="DIR", default="data/", help="Configuration directory.") +parser.add_argument("--force", "-f", default="false", action="store_true", help="Force overriding of existing trim configurations.") + +args = parser.parse_args() + +# Importing ROOT before parsing argument messes up the help output. Well +# done, root. +from ROOT import gStyle, TGraph, TCanvas, TLine, TF1, TFile -assembly = [2, 5] +if args.mpa_index: + assembly = list(sorted(args.mpa_index)) +else: + assembly = [2, 5] calibration = MPACalibration(assembly) mpaConfig = [] +print """Command Line Configuration +-------------------------- + MPA Indices = \x1b[1m{0}\x1b[m + Assembly Name = \x1b[1m{1}\x1b[m +""".format(assembly, + args.assembly, + ) + for MPA in assembly: # Construct list of XML files, one for each MPA - mpaConfig.append( - ET.parse("data/Conf_default_MPA" + str(MPA) + "_config1.xml")) + filename = os.path.join(args.config_dir, + args.config.format(mpa=MPA, assembly=args.assembly)) + if os.path.exists(filename): + if args.force: + print "WARNING! Overwrite existing config {0}!".format(filename) + else: + args.error("Configuration file {0} exists. Please use --force or delete the file.") + mpaConfig.append(filename) calibration.thresholdScan(calEnbl=True) calibration.writeCalibrationToMPA() diff --git a/daq/daq_continuous_2MPA.py b/daq/daq_continuous_2MPA.py index fab03ba..d228141 100644 --- a/daq/daq_continuous_2MPA.py +++ b/daq/daq_continuous_2MPA.py @@ -18,7 +18,8 @@ parser.add_argument("--output-dir", "-o", metavar="DIR", help="Directory where run data is stored", default="./data") parser.add_argument("--config", "-c", metavar="FILEFORMAT", - help="Filename format string for trimming and masking MPA configuration. The variables {assembly} and {mpa} are available.", default="data/Conf-{assembly}_MPA-{mpa}.xml") + help="Filename format string for trimming and masking MPA configuration. The variables {assembly} and {mpa} are available.", default="Conf-{assembly}_MPA-{mpa}.xml") +parser.add_argument("--config-dir", metavar="DIR", default="data/", help="Configuration directory.") args = parser.parse_args() @@ -55,7 +56,9 @@ # conf.append(mpa[iMPA].config("data/Conf_trimcalib_MPA" + str(nMPA)+ # "_masked.xml")) # Use trimcalibrated config conf.append(mpa[iMPA].config( - args.config.format(mpa=nMPA, assembly=args.assembly))) + os.path.join( + args.config_dir, + args.config.format(mpa=nMPA, assembly=args.assembly)))) except IOError, e: if e.filename and e.errno == errno.ENOENT: parser.error( From a0caa7538ce6cca1d1a7f76e6588e1eb41016abc Mon Sep 17 00:00:00 2001 From: Gregor Vollmer Date: Tue, 21 Feb 2017 10:51:03 +0100 Subject: [PATCH 04/10] Input/output file handling --- advancedTrimDacCalibration.py | 31 ++++++++++++++++++------------- 1 file changed, 18 insertions(+), 13 deletions(-) diff --git a/advancedTrimDacCalibration.py b/advancedTrimDacCalibration.py index 694d8e6..1077682 100644 --- a/advancedTrimDacCalibration.py +++ b/advancedTrimDacCalibration.py @@ -10,10 +10,12 @@ help="Name of the assembly, used to differentiate trimming configurations", default="default") parser.add_argument("--mpa-index", "-i", metavar="IDX", type=int, choices=range(1, 7), action="append", help="Specify the indices of the MPAs in the SPI chain", default=[]) -parser.add_argument("--config", "-c", metavar="FILEFORMAT", - help="Filename format string for trimming and masking MPA configuration. The variables {assembly} and {mpa} are available.", default="Conf-{assembly}_MPA-{mpa}.xml") +parser.add_argument("--config-in", "-c", metavar="FILEFORMAT", + help="Filename format string for the default MPA configuration. The variables {assembly} and {mpa} are available.", default="Conf_default_MPA{mpa}_config1.xml") +parser.add_argument("--config-out", "-o", metavar="FILEFORMAT", + help="Filename format string where the trimmed MPA configuration is written to. The variables {assembly} and {mpa} are available.", default="Conf-{assembly}_MPA-{mpa}.xml") parser.add_argument("--config-dir", metavar="DIR", default="data/", help="Configuration directory.") -parser.add_argument("--force", "-f", default="false", action="store_true", help="Force overriding of existing trim configurations.") +parser.add_argument("--force", "-f", default="false", action="store_true", help="Force overwriting of existing trim configurations.") args = parser.parse_args() @@ -25,6 +27,14 @@ assembly = list(sorted(args.mpa_index)) else: assembly = [2, 5] +for MPA in assembly: + filename = os.path.join(args.config_dir, + args.config_out.format(mpa=MPA, assembly=args.assembly)) + if os.path.exists(filename): + if args.force: + print "WARNING! Trimming will overwrite existing config {0}!".format(filename) + else: + args.error("Configuration file {0} exists. Please use --force or delete the file.") calibration = MPACalibration(assembly) mpaConfig = [] @@ -39,13 +49,8 @@ for MPA in assembly: # Construct list of XML files, one for each MPA filename = os.path.join(args.config_dir, - args.config.format(mpa=MPA, assembly=args.assembly)) - if os.path.exists(filename): - if args.force: - print "WARNING! Overwrite existing config {0}!".format(filename) - else: - args.error("Configuration file {0} exists. Please use --force or delete the file.") - mpaConfig.append(filename) + args.config_in.format(mpa=MPA, assembly=args.assembly)) + mpaConfig.append(ET.parse(filename)) calibration.thresholdScan(calEnbl=True) calibration.writeCalibrationToMPA() @@ -140,9 +145,9 @@ pixel.find('THRTRIMRATIOR').text = '{0:.5}'.format( str(fitvalsMPA[iMPA][2 * iPix + 1])) - MPAtree.write('data/Conf_trimcalib_MPA' + - str(assembly[iMPA]) + '_config1.xml') - + filename = os.path.join(args.config_dir, + args.config_out.format(mpa=assembly[iMPA], assembly=args.assembly)) + MPAtree.write(filename) calibration.thresholdScan() From 70e87a3803ff440d80038479036a12e5686555fd Mon Sep 17 00:00:00 2001 From: Gregor Vollmer Date: Tue, 21 Feb 2017 10:52:53 +0100 Subject: [PATCH 05/10] Ignore VIM swap files, backup- and plot directories --- .gitignore | 3 +++ 1 file changed, 3 insertions(+) diff --git a/.gitignore b/.gitignore index 3c181bd..e35b4a7 100644 --- a/.gitignore +++ b/.gitignore @@ -1,4 +1,5 @@ plots/* +plots_kit/* data/* *.pyc *~ @@ -9,3 +10,5 @@ decoded/* *.root logs/* *.log +*.swp +backup/* From 3c5768c1b13f231814655feb1259ca4e1a0e81a0 Mon Sep 17 00:00:00 2001 From: Gregor Vollmer Date: Tue, 21 Feb 2017 15:21:38 +0100 Subject: [PATCH 06/10] Somehow some conflict markers ended up in this file MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Removed them. Hoooooorrible… --- test_address_table_v1.xml | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/test_address_table_v1.xml b/test_address_table_v1.xml index 8831a8c..2844af1 100644 --- a/test_address_table_v1.xml +++ b/test_address_table_v1.xml @@ -2,12 +2,8 @@ -<<<<<<< HEAD - -======= - / ->>>>>>> 8bd6ffb... Current state of the analysis. A horrible, horrible state… + From bb559918f0f75f98c42ae9f1c3cfb830120a91fc Mon Sep 17 00:00:00 2001 From: Gregor Vollmer Date: Thu, 23 Feb 2017 15:33:47 +0100 Subject: [PATCH 07/10] Fixed --force default settings --- advancedTrimDacCalibration.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/advancedTrimDacCalibration.py b/advancedTrimDacCalibration.py index 1077682..b521658 100644 --- a/advancedTrimDacCalibration.py +++ b/advancedTrimDacCalibration.py @@ -15,7 +15,7 @@ parser.add_argument("--config-out", "-o", metavar="FILEFORMAT", help="Filename format string where the trimmed MPA configuration is written to. The variables {assembly} and {mpa} are available.", default="Conf-{assembly}_MPA-{mpa}.xml") parser.add_argument("--config-dir", metavar="DIR", default="data/", help="Configuration directory.") -parser.add_argument("--force", "-f", default="false", action="store_true", help="Force overwriting of existing trim configurations.") +parser.add_argument("--force", "-f", default=False, action="store_true", help="Force overwriting of existing trim configurations.") args = parser.parse_args() @@ -34,7 +34,7 @@ if args.force: print "WARNING! Trimming will overwrite existing config {0}!".format(filename) else: - args.error("Configuration file {0} exists. Please use --force or delete the file.") + parser.error("Configuration file {0} exists. Please use --force or delete the file.".format(filename)) calibration = MPACalibration(assembly) mpaConfig = [] From 869187c1becceed09dc7c6168701d67cc469a42f Mon Sep 17 00:00:00 2001 From: Gregor Vollmer Date: Thu, 23 Feb 2017 15:34:20 +0100 Subject: [PATCH 08/10] Added ROOT file output to daq_continuous Raw memory and counter data is decoded on-the-fly and written into a ROOT TTree. --- daq/daq_continuous_2MPA.py | 213 ++++++++++++++++++++++++++----------- 1 file changed, 151 insertions(+), 62 deletions(-) diff --git a/daq/daq_continuous_2MPA.py b/daq/daq_continuous_2MPA.py index d228141..b1c4f54 100644 --- a/daq/daq_continuous_2MPA.py +++ b/daq/daq_continuous_2MPA.py @@ -1,10 +1,11 @@ import sys import os from classes import * -from array import array +from ctypes import * import time import argparse import errno +import itertools parser = argparse.ArgumentParser(description="MaPSA DAQ") parser.add_argument("--external-clock", "-x", default=False, @@ -20,8 +21,23 @@ parser.add_argument("--config", "-c", metavar="FILEFORMAT", help="Filename format string for trimming and masking MPA configuration. The variables {assembly} and {mpa} are available.", default="Conf-{assembly}_MPA-{mpa}.xml") parser.add_argument("--config-dir", metavar="DIR", default="data/", help="Configuration directory.") +parser.add_argument("--num-triggers", "-n", metavar="NTRIG", default=500000, help="Number of trigger events to record. Set to 0 for user-interrupted, unlimited recording.", type=int) +parser.add_argument("--root", "-R", default=False, action="store_true", + help="If set, write data to root file instead of plaintext output. It is" + "written into the directory specified with --output-dir, while the" + "name is specified with --root-fmt. The run numbering is used as with" + "the plaintext output.") +parser.add_argument("--root-fmt", "-F", metavar="ROOTFILE", default="run{number:04d}.root", + help="Format of the filename for ROOT file output. You can use the variables {number} and {assembly}.") args = parser.parse_args() +runNumber = 0 +runNumberFile = os.path.join(args.output_dir, 'currentRun.txt') +try: + with open(runNumberFile, 'r') as runFile: + runNumber = int(runFile.read()) +except IOError: + pass # Importing ROOT before parsing argument messes up the help output. Well # done, root. @@ -94,13 +110,6 @@ # Start sequencer in continous daq mode. Already contains the 'write' mapsaClasses.daq().Sequencer_init(0x1, shutterDur, mem=1) -ibuffer = 1 -shutterCounter = 0 -counterArray = [] -memoryArray = [] -frequency = "Wait" - -triggerStop = 500000 print """Command Line Configuration -------------------------- @@ -109,97 +118,177 @@ MPA Indices = \x1b[1m{2}\x1b[m Assembly Name = \x1b[1m{3}\x1b[m Output Dir = \x1b[1m{4}\x1b[m + Num Triggers = \x1b[1m{5}\x1b[m """.format("external" if args.external_clock else "internal", args.threshold, assembly, args.assembly, - os.path.abspath(args.output_dir) + os.path.abspath(args.output_dir), + args.num_triggers, ) - -try: +def acquire(numTriggers, stopDelay=2): + ibuffer = 0 + shutterCounter = 0 + frequency = float("NaN") while True: freeBuffers = glib.getNode("Control").getNode( 'Sequencer').getNode('buffers_num').read() glib.dispatch() - # When set to 4 this produces duplicate entries, 3 (= 2 full buffers) # avoids this. if freeBuffers < 3: - if shutterCounter % 2000 == 0: startTime = time.time() shutterTimeStart = shutterCounter - if shutterCounter % 100 == 0 and (shutterCounter - shutterTimeStart) >= 0.1: frequency = (shutterCounter - shutterTimeStart) / \ (time.time() - startTime) - MAPSACounter = [] MAPSAMemory = [] for iMPA, nMPA in enumerate(assembly): counterData = glib.getNode("Readout").getNode("Counter").getNode( - "MPA" + str(iMPA + 1)).getNode("buffer_" + str(ibuffer)).readBlock(25) + "MPA" + str(iMPA + 1)).getNode("buffer_" + str(ibuffer+1)).readBlock(25) memoryData = glib.getNode("Readout").getNode("Memory").getNode( - "MPA" + str(nMPA)).getNode("buffer_" + str(ibuffer)).readBlock(216) + "MPA" + str(nMPA)).getNode("buffer_" + str(ibuffer+1)).readBlock(216) glib.dispatch() - - # print "Buffer: %s iMPA: %s nMPA: %s" %(ibuffer, iMPA, nMPA) - # print counterData - # print '{0:032b}'.format(counterData[0]) - # print memoryData - # print "\n" - MAPSACounter.append(counterData) MAPSAMemory.append(memoryData) - - ibuffer += 1 - if ibuffer > 4: - ibuffer = 1 - + ibuffer = (ibuffer + 1) % 4 shutterCounter += 1 - - # Only contains valVectors: - counterArray.append(MAPSACounter) - memoryArray.append(MAPSAMemory) - print "Shutter counter: %s Free buffers: %s Frequency: %s " % (shutterCounter, freeBuffers, frequency) + yield shutterCounter, MAPSACounter, MAPSAMemory, freeBuffers, frequency # Continuous operation in bash loop - - if shutterCounter == triggerStop: + if shutterCounter == numTriggers: endTimeStamp = time.time() - if shutterCounter > triggerStop: - if time.time() - endTimeStamp > 2: + # Required for automation! Do not stop DAQ until at least + # 2 seconds after reaching the num trigger limit + if shutterCounter > numTriggers: + if time.time() - endTimeStamp > stopDelay: break - -except KeyboardInterrupt: - pass - -if len(counterArray): - runNumber = 0 - runNumberFile = os.path.join(args.output_dir, 'currentRun.txt') +class RippleCounterBranch(Structure): + _fields_ = [ + ("header", c_ulong), + ("pixels", c_ushort*48) + ] + +class MemoryNoProcessingBranch(Structure): + _fields_ = [ + ("pixelMatrix", c_ulonglong*96), + ("bunchCrossingId", c_ushort*96), + ("header", c_ubyte*96), + ("numEvents", c_ubyte), + ("corrupt", c_ubyte), + ] + + +def recordPlaintext(): + counterArray = [] + memoryArray = [] try: - with open(runNumberFile, 'r') as runFile: - runNumber = int(runFile.read()) - except IOError: + for shutter, counter, memory, freeBuffers, frequency in acquire(args.num_triggers): + counterArray.append(counter) + memoryArray.append(memory) + print "Shutter counter: %s Free buffers: %s Frequency: %s " % (shutter, freeBuffers, frequency) + except KeyboardInterrupt: pass + if len(counterArray): + with open(runNumberFile, 'w') as newRunFile: + newRunFile.write(str(runNumber + 1)) + print "End of Run %s" % runNumber + memoryFile = open(os.path.join( + args.output_dir, 'run%s_memory.txt' % ('{0:04d}'.format(runNumber))), 'w') + counterFile = open(os.path.join( + args.output_dir, 'run%s_counter.txt' % ('{0:04d}'.format(runNumber))), 'w') + for i, shutter in enumerate(counterArray): + for j, mpa in enumerate(shutter): + counterFile.write(str(mpa.value()) + "\n") + memoryFile.write(str(memoryArray[i][j].value()) + "\n") + counterFile.close() + memoryFile.close() + print "All files saved" + else: + print "\x1b[1mNo data acquired, ignore.\x1b[m" + +def recordRoot(): + spinner = "--\\\\||//" + progress = ["-"]*20 + filename = os.path.join(args.output_dir, + args.root_fmt.format(number=runNumber, assembly=args.assembly)) + tFile = TFile(filename, "CREATE") with open(runNumberFile, 'w') as newRunFile: newRunFile.write(str(runNumber + 1)) - print "End of Run %s" % runNumber - memoryFile = open(os.path.join( - args.output_dir, 'run%s_memory.txt' % ('{0:04d}'.format(runNumber))), 'w') - counterFile = open(os.path.join( - args.output_dir, 'run%s_counter.txt' % ('{0:04d}'.format(runNumber))), 'w') - for i, shutter in enumerate(counterArray): - for j, mpa in enumerate(shutter): - counterFile.write(str(mpa.value()) + "\n") - memoryFile.write(str(memoryArray[i][j].value()) + "\n") - counterFile.close() - memoryFile.close() - print "All files saved" -else: - print "\x1b[1mNo data acquired, ignore.\x1b[m" + trees = [] + counterFormat = "pixel[48]/s" + noProcessingFormat = "pixels[96]/l:bunchCrossingId[96]/s:header[96]/b:numEvents/b:corrupt/b" + flood = [{ + "counter": RippleCounterBranch(), + "noProcessing": MemoryNoProcessingBranch(), + }]*len(assembly) + for i, mpa in enumerate(assembly): + tree = TTree("mpa{0}".format(mpa), "MPA{0} event tree".format(mpa)) + trees.append(tree) + tree.Branch("rippleCounter", flood[i]["counter"], counterFormat) + tree.Branch("memoryNoProcessing", flood[i]["noProcessing"], noProcessingFormat) + try: + pixelMatrixMask = 2**49 - 1 + for shutter, counters, memories, freeBuffers, frequency in acquire(args.num_triggers): + for data, tree, counter, memory in zip(flood, trees, counters, memories): + for i, val in enumerate(itertools.islice(counter, 1, len(counter))): + # According to Moritz: + # "Mask to select left pixel. First bit is not + # considered as this seems sometimes to be set + # erronously. (Lots of entries with + # 0b1000000000000000)" + data["counter"].pixels[i*2 + 0] = val & 0x7FFF # left + data["counter"].pixels[i*2 + 1] = (val >> 16) & 0x7FFF # right + # convert memory from uhal-format to ctype bytes array + memory_ints = (c_ulong*216)(*memory) + memory_bytes = cast(memory_ints, POINTER(c_ubyte)) + # reset fill array + data["noProcessing"].pixelMatrix = (c_ulonglong*96)(0) + data["noProcessing"].bunchCrossingId = (c_ushort*96)(0) + data["noProcessing"].header = (c_ubyte*96)(0) + data["noProcessing"].corrupt = c_ubyte(0) + # iterate over memory in multipletts of 9 bytes (one 72 bit event) + evtIdx = 0 + gotEvtData = False + for evtIdx in xrange(0, 96): + evtData = tuple(itertools.islice(memory_bytes, evtIdx*9, evtIdx*9 + 9)) + data["noProcessing"].header[evtIdx] = evtData[0] + if data["noProcessing"].header[evtIdx] == 0x00: + break + elif data["noProcessing"].header[evtIdx] != 0xFF: + data["noProcessing"].corrupt = c_ubyte(evtIdx + 1) + break + gotEvtData = True + # bytes 1-8 as 64 bit integer, 1&2 are buch crossing id + postHeader = cast(c_ulonglong, POINTER(evtData[1])) + data["noProcessing"].bunchCrossingId[evtIdx] = (postHeader >> 48) & 0xFFFF + data["noProcessing"].pixelMatrix[evtIdx] = postHeader & pixelMatrixMask + if gotEvtData: + data["noProcessing"].numEvents = c_ubyte(evtIdx + 1) + tree.Fill() + # Fancy shmancy visual output + progress[int(len(progress)*float(shutter)/float(args.num_triggers)) % len(progress)] = "#" + sys.stdout.write("\r\x1b[K [{3}] Shutter={0} Free bufs={1} freq={2:.0f} Hz [{4}] {5:.0f}%".format( + shutter, freeBuffers, frequency, + spinner[shutter % len(spinner)], + "".join(progress), + float(shutter) / float(args.num_triggers) * 100 + )) + sys.stdout.flush() + except KeyboardInterrupt: + pass + sys.stdout.write("\n") + tFile.Write() + tFile.Close() + print "End of Run", runNumber +if args.root: + recordRoot() +else: + recordPlaintext() # nHitMax = 95 # nPixMax = 48 From cd3c46d50127efb56c4269cae56f34195b8d8fe9 Mon Sep 17 00:00:00 2001 From: Gregor Vollmer Date: Thu, 23 Feb 2017 17:02:39 +0100 Subject: [PATCH 09/10] Fixed ROOT output for memory-data Changed code to reflect the actual format of the MPA memory output in no-processing mode. Data looks fine in TBrowser. --- daq/daq_continuous_2MPA.py | 40 ++++++++++++++++++++++---------------- 1 file changed, 23 insertions(+), 17 deletions(-) diff --git a/daq/daq_continuous_2MPA.py b/daq/daq_continuous_2MPA.py index b1c4f54..0f4bb58 100644 --- a/daq/daq_continuous_2MPA.py +++ b/daq/daq_continuous_2MPA.py @@ -168,7 +168,7 @@ def acquire(numTriggers, stopDelay=2): class RippleCounterBranch(Structure): _fields_ = [ - ("header", c_ulong), + ("header", c_uint), ("pixels", c_ushort*48) ] @@ -231,7 +231,7 @@ def recordRoot(): tree.Branch("rippleCounter", flood[i]["counter"], counterFormat) tree.Branch("memoryNoProcessing", flood[i]["noProcessing"], noProcessingFormat) try: - pixelMatrixMask = 2**49 - 1 + totalEvents = 0 for shutter, counters, memories, freeBuffers, frequency in acquire(args.num_triggers): for data, tree, counter, memory in zip(flood, trees, counters, memories): for i, val in enumerate(itertools.islice(counter, 1, len(counter))): @@ -243,7 +243,7 @@ def recordRoot(): data["counter"].pixels[i*2 + 0] = val & 0x7FFF # left data["counter"].pixels[i*2 + 1] = (val >> 16) & 0x7FFF # right # convert memory from uhal-format to ctype bytes array - memory_ints = (c_ulong*216)(*memory) + memory_ints = (c_uint*216)(*memory) memory_bytes = cast(memory_ints, POINTER(c_ubyte)) # reset fill array data["noProcessing"].pixelMatrix = (c_ulonglong*96)(0) @@ -252,30 +252,36 @@ def recordRoot(): data["noProcessing"].corrupt = c_ubyte(0) # iterate over memory in multipletts of 9 bytes (one 72 bit event) evtIdx = 0 - gotEvtData = False - for evtIdx in xrange(0, 96): - evtData = tuple(itertools.islice(memory_bytes, evtIdx*9, evtIdx*9 + 9)) - data["noProcessing"].header[evtIdx] = evtData[0] - if data["noProcessing"].header[evtIdx] == 0x00: + numEvents = 0 + for evtIdx in reversed(xrange(0, 96)): + evtData = tuple( + itertools.islice(memory_bytes, + evtIdx*9, evtIdx*9 + 9)) + data["noProcessing"].header[95-evtIdx] = evtData[8] + if data["noProcessing"].header[95-evtIdx] == 0x00: break - elif data["noProcessing"].header[evtIdx] != 0xFF: + elif data["noProcessing"].header[95-evtIdx] != 0xFF: data["noProcessing"].corrupt = c_ubyte(evtIdx + 1) break - gotEvtData = True + numEvents += 1 # bytes 1-8 as 64 bit integer, 1&2 are buch crossing id - postHeader = cast(c_ulonglong, POINTER(evtData[1])) - data["noProcessing"].bunchCrossingId[evtIdx] = (postHeader >> 48) & 0xFFFF - data["noProcessing"].pixelMatrix[evtIdx] = postHeader & pixelMatrixMask - if gotEvtData: - data["noProcessing"].numEvents = c_ubyte(evtIdx + 1) + pixelMatrix = ((evtData[5] << 40) | (evtData[4] << 32) | + (evtData[3] << 24) | (evtData[2] << 16) | + (evtData[1] << 8) | evtData[0]) + bxid = ((evtData[7] << 8) | evtData[6]) + data["noProcessing"].bunchCrossingId[95-evtIdx] = bxid + data["noProcessing"].pixelMatrix[95-evtIdx] = pixelMatrix + totalEvents += numEvents + data["noProcessing"].numEvents = c_ubyte(numEvents) tree.Fill() # Fancy shmancy visual output progress[int(len(progress)*float(shutter)/float(args.num_triggers)) % len(progress)] = "#" - sys.stdout.write("\r\x1b[K [{3}] Shutter={0} Free bufs={1} freq={2:.0f} Hz [{4}] {5:.0f}%".format( + sys.stdout.write("\r\x1b[K [{3}] Shutter={0} Free bufs={1} freq={2:.0f} Hz #events={6} [{4}] {5:.0f}%".format( shutter, freeBuffers, frequency, spinner[shutter % len(spinner)], "".join(progress), - float(shutter) / float(args.num_triggers) * 100 + float(shutter) / float(args.num_triggers) * 100, + totalEvents )) sys.stdout.flush() except KeyboardInterrupt: From 9850e40b6bf206f2fb0a0bef6f2717bd61db0204 Mon Sep 17 00:00:00 2001 From: Gregor Vollmer Date: Fri, 3 Mar 2017 10:46:04 +0100 Subject: [PATCH 10/10] Updated version by Johannes Grossmann --- daq/daq_continuous_2MPA.py | 1 + 1 file changed, 1 insertion(+) diff --git a/daq/daq_continuous_2MPA.py b/daq/daq_continuous_2MPA.py index 0f4bb58..8c4e456 100644 --- a/daq/daq_continuous_2MPA.py +++ b/daq/daq_continuous_2MPA.py @@ -107,6 +107,7 @@ # shutterDur = 0xFFFFFFFF #0xFFFFFFFF is maximum, in clock cycles shutterDur = 0xFFFFFF # 0xFFFFFFFF is maximum, in clock cycles +#shutterDur = 0xF # 0xFFFFFFFF is maximum, in clock cycles # Start sequencer in continous daq mode. Already contains the 'write' mapsaClasses.daq().Sequencer_init(0x1, shutterDur, mem=1)