def configure(self): commands = [] commands.extend(self.register.get_commands("ConfMode")) # Enable enable_pixel_mask = make_box_pixel_mask_from_col_row(column=self.col_span, row=self.row_span) if not self.overwrite_enable_mask: enable_pixel_mask = np.logical_and(enable_pixel_mask, self.register.get_pixel_register_value('Enable')) self.register.set_pixel_register_value('Enable', enable_pixel_mask) commands.extend(self.register.get_commands("WrFrontEnd", same_mask_for_all_dc=False, name='Enable')) # Imon if self.use_enable_mask_for_imon: imon_pixel_mask = invert_pixel_mask(enable_pixel_mask) else: imon_pixel_mask = make_box_pixel_mask_from_col_row(column=self.col_span, row=self.row_span, default=1, value=0) # 0 for selected columns, else 1 imon_pixel_mask = np.logical_or(imon_pixel_mask, self.register.get_pixel_register_value('Imon')) self.register.set_pixel_register_value('Imon', imon_pixel_mask) commands.extend(self.register.get_commands("WrFrontEnd", same_mask_for_all_dc=False, name='Imon')) # C_High self.register.set_pixel_register_value('C_High', 0) commands.extend(self.register.get_commands("WrFrontEnd", same_mask_for_all_dc=True, name='C_High')) # C_Low self.register.set_pixel_register_value('C_Low', 0) commands.extend(self.register.get_commands("WrFrontEnd", same_mask_for_all_dc=True, name='C_Low')) # Registers self.register.set_global_register_value("Trig_Lat", self.trigger_latency) # set trigger latency self.register.set_global_register_value("Trig_Count", self.trig_count) # set number of consecutive triggers commands.extend(self.register.get_commands("WrRegister", name=["Trig_Lat", "Trig_Count"])) commands.extend(self.register.get_commands("RunMode")) self.register_utils.send_commands(commands)
def configure(self): commands = [] commands.extend(self.register.get_commands("ConfMode")) # Enable enable_pixel_mask = make_box_pixel_mask_from_col_row(column=self.col_span, row=self.row_span) if not self.overwrite_enable_mask: enable_pixel_mask = np.logical_and(enable_pixel_mask, self.register.get_pixel_register_value('Enable')) self.register.set_pixel_register_value('Enable', enable_pixel_mask) commands.extend(self.register.get_commands("WrFrontEnd", same_mask_for_all_dc=False, name='Enable')) # Imon if self.use_enable_mask_for_imon: imon_pixel_mask = invert_pixel_mask(enable_pixel_mask) else: imon_pixel_mask = make_box_pixel_mask_from_col_row(column=self.col_span, row=self.row_span, default=1, value=0) # 0 for selected columns, else 1 imon_pixel_mask = np.logical_or(imon_pixel_mask, self.register.get_pixel_register_value('Imon')) self.register.set_pixel_register_value('Imon', imon_pixel_mask) commands.extend(self.register.get_commands("WrFrontEnd", same_mask_for_all_dc=False, name='Imon')) # C_High self.register.set_pixel_register_value('C_High', 0) commands.extend(self.register.get_commands("WrFrontEnd", same_mask_for_all_dc=True, name='C_High')) # C_Low self.register.set_pixel_register_value('C_Low', 0) commands.extend(self.register.get_commands("WrFrontEnd", same_mask_for_all_dc=True, name='C_Low')) # Registers self.register.set_global_register_value("Trig_Lat", self.trigger_latency) # set trigger latency self.register.set_global_register_value("Trig_Count", 1) # set number of consecutive triggers commands.extend(self.register.get_commands("WrRegister", name=["Trig_Lat", "Trig_Count"])) commands.extend(self.register.get_commands("RunMode")) self.register_utils.send_commands(commands)
def configure(self): if self.trig_count == 0: self.consecutive_lvl1 = (2 ** self.register.global_registers['Trig_Count']['bitlength']) else: self.consecutive_lvl1 = self.trig_count self.abs_occ_limit = int(self.occupancy_limit * self.n_triggers * self.consecutive_lvl1) if self.abs_occ_limit < 1.0: logging.warning('Number of triggers too low for given occupancy limit. Any hit will result in a masked pixel.') else: logging.info('Masking pixels with occupancy >%d (sending %d triggers)', self.abs_occ_limit, self.n_triggers) commands = [] commands.extend(self.register.get_commands("ConfMode")) # Enable enable_pixel_mask = make_box_pixel_mask_from_col_row(column=self.col_span, row=self.row_span) if not self.overwrite_enable_mask: enable_pixel_mask = np.logical_and(enable_pixel_mask, self.register.get_pixel_register_value('Enable')) self.register.set_pixel_register_value('Enable', enable_pixel_mask) commands.extend(self.register.get_commands("WrFrontEnd", same_mask_for_all_dc=False, name='Enable')) # Imon if self.use_enable_mask_for_imon: imon_pixel_mask = invert_pixel_mask(enable_pixel_mask) else: imon_pixel_mask = make_box_pixel_mask_from_col_row(column=self.col_span, row=self.row_span, default=1, value=0) # 0 for selected columns, else 1 imon_pixel_mask = np.logical_or(imon_pixel_mask, self.register.get_pixel_register_value('Imon')) self.register.set_pixel_register_value('Imon', imon_pixel_mask) commands.extend(self.register.get_commands("WrFrontEnd", same_mask_for_all_dc=False, name='Imon')) # C_High self.register.set_pixel_register_value('C_High', 0) commands.extend(self.register.get_commands("WrFrontEnd", same_mask_for_all_dc=True, name='C_High')) # C_Low self.register.set_pixel_register_value('C_Low', 0) commands.extend(self.register.get_commands("WrFrontEnd", same_mask_for_all_dc=True, name='C_Low')) # Registers # self.register.set_global_register_value("Trig_Lat", self.trigger_latency) # set trigger latency self.register.set_global_register_value("Trig_Count", self.trig_count) # set number of consecutive triggers commands.extend(self.register.get_commands("WrRegister", name=["Trig_Count"])) commands.extend(self.register.get_commands("RunMode")) self.register_utils.send_commands(commands)
def configure(self): if self.trig_count == 0: self.consecutive_lvl1 = (2 ** self.register.global_registers['Trig_Count']['bitlength']) else: self.consecutive_lvl1 = self.trig_count self.abs_occ_limit = int(self.occupancy_limit * self.n_triggers * self.consecutive_lvl1) if self.abs_occ_limit <= 0: logging.info('Any noise hit will lead to an increased pixel threshold.') else: logging.info('The pixel threshold of any pixel with an occpancy >%d will be increased' % self.abs_occ_limit) commands = [] commands.extend(self.register.get_commands("ConfMode")) # TDAC tdac_max = 2 ** self.register.pixel_registers['TDAC']['bitlength'] - 1 self.register.set_pixel_register_value("TDAC", tdac_max) commands.extend(self.register.get_commands("WrFrontEnd", same_mask_for_all_dc=False, name="TDAC")) mask = make_box_pixel_mask_from_col_row(column=self.col_span, row=self.row_span) # Enable if self.use_enable_mask: self.register.set_pixel_register_value("Enable", np.logical_and(mask, self.register.get_pixel_register_value("Enable"))) else: self.register.set_pixel_register_value("Enable", mask) commands.extend(self.register.get_commands("WrFrontEnd", same_mask_for_all_dc=False, name="Enable")) # Imon self.register.set_pixel_register_value('Imon', 1) commands.extend(self.register.get_commands("WrFrontEnd", same_mask_for_all_dc=True, name='Imon')) # C_High self.register.set_pixel_register_value('C_High', 0) commands.extend(self.register.get_commands("WrFrontEnd", same_mask_for_all_dc=True, name='C_High')) # C_Low self.register.set_pixel_register_value('C_Low', 0) commands.extend(self.register.get_commands("WrFrontEnd", same_mask_for_all_dc=True, name='C_Low')) # Registers # self.register.set_global_register_value("Trig_Lat", self.trigger_latency) # set trigger latency self.register.set_global_register_value("Trig_Count", self.trig_count) # set number of consecutive triggers commands.extend(self.register.get_commands("WrRegister", name=["Trig_Count"])) commands.extend(self.register.get_commands("RunMode")) self.register_utils.send_commands(commands) self.interpreter = PyDataInterpreter() self.histograming = PyDataHistograming() self.interpreter.set_trig_count(self.trig_count) self.interpreter.set_warning_output(False) self.histograming.set_no_scan_parameter() self.histograming.create_occupancy_hist(True)
def configure(self): if self.trig_count == 0: self.consecutive_lvl1 = (2 ** self.register.global_registers['Trig_Count']['bitlength']) else: self.consecutive_lvl1 = self.trig_count self.abs_occ_limit = int(self.occupancy_limit * self.n_triggers * self.consecutive_lvl1) if self.abs_occ_limit <= 0: logging.info('Any noise hit will lead to an increased pixel threshold.') else: logging.info('The pixel threshold of any pixel with an occpancy >%d will be increased' % self.abs_occ_limit) commands = [] commands.extend(self.register.get_commands("ConfMode")) # TDAC tdac_max = 2 ** self.register.pixel_registers['TDAC']['bitlength'] - 1 self.register.set_pixel_register_value("TDAC", tdac_max) commands.extend(self.register.get_commands("WrFrontEnd", same_mask_for_all_dc=False, name="TDAC")) mask = make_box_pixel_mask_from_col_row(column=self.col_span, row=self.row_span) # Enable if self.use_enable_mask: self.register.set_pixel_register_value("Enable", np.logical_and(mask, self.register.get_pixel_register_value("Enable"))) else: self.register.set_pixel_register_value("Enable", mask) commands.extend(self.register.get_commands("WrFrontEnd", same_mask_for_all_dc=False, name="Enable")) # Imon self.register.set_pixel_register_value('Imon', 1) commands.extend(self.register.get_commands("WrFrontEnd", same_mask_for_all_dc=True, name='Imon')) # C_High self.register.set_pixel_register_value('C_High', 0) commands.extend(self.register.get_commands("WrFrontEnd", same_mask_for_all_dc=True, name='C_High')) # C_Low self.register.set_pixel_register_value('C_Low', 0) commands.extend(self.register.get_commands("WrFrontEnd", same_mask_for_all_dc=True, name='C_Low')) # Registers # self.register.set_global_register_value("Trig_Lat", self.trigger_latency) # set trigger latency self.register.set_global_register_value("Trig_Count", self.trig_count) # set number of consecutive triggers commands.extend(self.register.get_commands("WrRegister", name=["Trig_Count"])) commands.extend(self.register.get_commands("RunMode")) self.register_utils.send_commands(commands) self.interpreter = PyDataInterpreter() self.histogram = PyDataHistograming() self.interpreter.set_trig_count(self.trig_count) self.interpreter.set_warning_output(False) self.histogram.set_no_scan_parameter() self.histogram.create_occupancy_hist(True)
def configure(self): commands = [] commands.extend(self.register.get_commands("ConfMode")) # GDAC self.gdac_range = [self.register.get_global_register_value("Vthin_AltFine"), 0] # default GDAC range if self.start_gdac is not None: self.gdac_range[0] = min(self.start_gdac, 2 ** self.register.global_registers['Vthin_AltFine']['bitlength']) if self.gdac_lower_limit is not None: self.gdac_range[1] = max(self.gdac_lower_limit, 0) self.register.set_global_register_value("Vthin_AltFine", self.gdac_range[0]) # set to start threshold value commands.extend(self.register.get_commands("WrRegister", name=["Vthin_AltFine"])) # TDAC tdac_max = 2 ** self.register.pixel_registers['TDAC']['bitlength'] - 1 self.register.set_pixel_register_value("TDAC", tdac_max) commands.extend(self.register.get_commands("WrFrontEnd", same_mask_for_all_dc=False, name="TDAC")) mask = make_box_pixel_mask_from_col_row(column=self.col_span, row=self.row_span) # Enable if self.use_enable_mask: self.register.set_pixel_register_value("Enable", np.logical_and(mask, self.register.get_pixel_register_value("Enable"))) else: self.register.set_pixel_register_value("Enable", mask) commands.extend(self.register.get_commands("WrFrontEnd", same_mask_for_all_dc=False, name="Enable")) # Imon self.register.set_pixel_register_value('Imon', 1) commands.extend(self.register.get_commands("WrFrontEnd", same_mask_for_all_dc=True, name='Imon')) # C_High self.register.set_pixel_register_value('C_High', 0) commands.extend(self.register.get_commands("WrFrontEnd", same_mask_for_all_dc=True, name='C_High')) # C_Low self.register.set_pixel_register_value('C_Low', 0) commands.extend(self.register.get_commands("WrFrontEnd", same_mask_for_all_dc=True, name='C_Low')) # Registers # self.register.set_global_register_value("Trig_Lat", self.trigger_latency) # set trigger latency self.register.set_global_register_value("Trig_Count", self.trig_count) # set number of consecutive triggers commands.extend(self.register.get_commands("WrRegister", name=["Trig_Count"])) commands.extend(self.register.get_commands("RunMode")) self.register_utils.send_commands(commands)
class IleakScan(Fei4RunBase): '''Pixel leakage current scan using external multimeter. ''' _default_run_conf = { "broadcast_commands": False, "threaded_scan": False, "pixels": (np.dstack( np.where(make_box_pixel_mask_from_col_row([1, 16], [1, 36]) == 1)) + 1).tolist()[0], # list of (col, row) tupels. From 1 to 80/336. } def configure(self): commands = [] commands.extend(self.register.get_commands("ConfMode")) self.register.set_pixel_register_value('Imon', 0) commands.extend( self.register.get_commands("WrFrontEnd", same_mask_for_all_dc=True, name='Imon')) self.register_utils.send_commands(commands) self.ileakmap = np.zeros(shape=(80, 336)) def scan(self): logging.info("Scanning %d pixels" % len(self.pixels)) progress_bar = progressbar.ProgressBar(widgets=[ '', progressbar.Percentage(), ' ', progressbar.Bar(marker='*', left='|', right='|'), ' ', progressbar.AdaptiveETA() ], maxval=len(self.pixels), term_width=80) progress_bar.start() data_out = self.raw_data_file.h5_file.create_carray( self.raw_data_file.h5_file.root, name='Ileak_map', title='Leakage current per pixel in arbitrary units', atom=tb.Atom.from_dtype(self.ileakmap.dtype), shape=self.ileakmap.shape, filters=tb.Filters(complib='blosc', complevel=5, fletcher32=False)) for pixel_index, (column, row) in enumerate(self.pixels): if self.stop_run.is_set(): break # Set Imon for actual pixel and configure FE mask = np.zeros(shape=(80, 336)) mask[column - 1, row - 1] = 1 commands = [] commands.extend(self.register.get_commands("ConfMode")) self.register.set_pixel_register_value('Imon', mask) commands.extend( self.register.get_commands("WrFrontEnd", same_mask_for_all_dc=False, name='Imon')) self.register_utils.send_commands(commands) # Read and store voltage voltage_string = self.dut['Multimeter'].get_voltage() voltage = float(voltage_string.split(',')[0][:-4]) self.ileakmap[column - 1, row - 1] = voltage progress_bar.update(pixel_index) progress_bar.finish() data_out[:] = self.ileakmap def analyze(self): with tb.open_file(self.output_filename + '.h5', 'r') as in_file_h5: data = in_file_h5.root.Ileak_map[:] data = np.ma.masked_where(data == 0, data) plot_three_way(hist=data.transpose(), title="Ileak", x_axis_title="Ileak", filename=self.output_filename + '.pdf') # , minimum=0, maximum=np.amax(data))
def configure(self): if self.trig_count == 0: self.consecutive_lvl1 = ( 2**self.register.global_registers['Trig_Count']['bitlength']) else: self.consecutive_lvl1 = self.trig_count if self.occupancy_limit * self.n_triggers * self.consecutive_lvl1 < 1.0: logging.warning( 'Number of triggers too low for given occupancy limit. Any noise hit will lead to a masked pixel.' ) commands = [] commands.extend(self.register.get_commands("ConfMode")) # TDAC tdac_max = 2**self.register.pixel_registers['TDAC']['bitlength'] - 1 self.register.set_pixel_register_value("TDAC", tdac_max) commands.extend( self.register.get_commands("WrFrontEnd", same_mask_for_all_dc=False, name="TDAC")) mask = make_box_pixel_mask_from_col_row(column=self.col_span, row=self.row_span) # Enable if self.use_enable_mask: self.register.set_pixel_register_value( "Enable", np.logical_and( mask, self.register.get_pixel_register_value("Enable"))) else: self.register.set_pixel_register_value("Enable", mask) commands.extend( self.register.get_commands("WrFrontEnd", same_mask_for_all_dc=False, name="Enable")) # Imon self.register.set_pixel_register_value('Imon', 1) commands.extend( self.register.get_commands("WrFrontEnd", same_mask_for_all_dc=True, name='Imon')) # C_High self.register.set_pixel_register_value('C_High', 0) commands.extend( self.register.get_commands("WrFrontEnd", same_mask_for_all_dc=True, name='C_High')) # C_Low self.register.set_pixel_register_value('C_Low', 0) commands.extend( self.register.get_commands("WrFrontEnd", same_mask_for_all_dc=True, name='C_Low')) # Registers # self.register.set_global_register_value("Trig_Lat", self.trigger_latency) # set trigger latency self.register.set_global_register_value( "Trig_Count", self.trig_count) # set number of consecutive triggers commands.extend( self.register.get_commands("WrRegister", name=["Trig_Count"])) commands.extend(self.register.get_commands("RunMode")) self.register_utils.send_commands(commands)
class HitOrCalibration(Fei4RunBase): ''' Hit Or calibration scan ''' _default_run_conf = { "repeat_command": 200, "injection_delay": 5000, # for really low feedbacks (ToT >> 300 ns) one needs to increase the injection delay "scan_parameters": [('column', None), ('row', None), ('PlsrDAC', [40, 50, 60, 80, 130, 180, 230, 280, 340, 440, 540, 640, 740])], # 0 400 sufficient "reset_rx_on_error": True, "plot_tdc_histograms": False, "pixels": (np.dstack( np.where( make_box_pixel_mask_from_col_row([40, 41], [150, 151]) == 1)) + 1).tolist() [0], # list of (col, row) tupels. From 1 to 80/336. "enable_masks": ["Enable", "C_Low", "C_High"], "disable_masks": ["Imon"] } def configure(self): commands = [] commands.extend(self.register.get_commands("ConfMode")) self.register.set_global_register_value( "Trig_Count", 6) # decrease trigger count to reduce data self.register.set_global_register_value( "Trig_Lat", 215) # adjust delay for smaller bcid window self.register.set_global_register_value( "ErrorMask", 1536) # deactivate hit bus service record commands.extend( self.register.get_commands( "WrRegister", name=["Trig_Lat", "Trig_Count", "ErrorMask"])) self.register_utils.send_commands(commands) def scan(self): def write_double_column(column): return (column - 1) / 2 def inject_double_column(column): if column == 80: return 39 else: return (column) / 2 cal_lvl1_command = self.register.get_commands( "CAL")[0] + self.register.get_commands( "zeros", length=40)[0] + self.register.get_commands( "LV1")[0] + self.register.get_commands( "zeros", length=self.injection_delay)[0] scan_par_name = self.scan_parameters._fields[ -1] # scan parameter is in inner loop scan_parameters_values = self.scan_parameters[ -1][:] # create deep copy of scan_parameters, they are overwritten in self.readout logging.info("Scanning %d pixels" % len(self.pixels)) for pixel_index, pixel in enumerate(self.pixels): if self.stop_run.is_set(): break column = pixel[0] row = pixel[1] logging.info('Scanning pixel: %d / %d (column / row)', column, row) if pixel_index: dcs = [write_double_column(column)] dcs.append(write_double_column(self.pixels[pixel_index - 1][0])) else: dcs = [] commands = [] commands.extend(self.register.get_commands("ConfMode")) single_pixel_enable_mask = make_pixel_mask_from_col_row([column], [row]) map( lambda mask_name: self.register.set_pixel_register_value( mask_name, single_pixel_enable_mask), self.enable_masks) commands.extend( self.register.get_commands("WrFrontEnd", same_mask_for_all_dc=False, dcs=dcs, name=self.enable_masks, joint_write=True)) single_pixel_disable_mask = make_pixel_mask_from_col_row([column], [row], default=1, value=0) map( lambda mask_name: self.register.set_pixel_register_value( mask_name, single_pixel_disable_mask), self.disable_masks) commands.extend( self.register.get_commands("WrFrontEnd", same_mask_for_all_dc=False, dcs=dcs, name=self.disable_masks, joint_write=True)) self.register.set_global_register_value( "Colpr_Addr", inject_double_column(column)) commands.append( self.register.get_commands("WrRegister", name=["Colpr_Addr"])[0]) self.register_utils.send_commands(commands) # self.fifo_readout.reset_sram_fifo() # after mask shifting you have AR VR in SRAM that are not of interest but reset takes a long time, so ignore the warning self.dut['TDC']['ENABLE'] = True for scan_parameter_value in scan_parameters_values: if self.stop_run.is_set(): break commands = [] commands.extend(self.register.get_commands("ConfMode")) self.register.set_global_register_value( scan_par_name, scan_parameter_value) commands.extend( self.register.get_commands("WrRegister", name=[scan_par_name])) commands.extend(self.register.get_commands("RunMode")) self.register_utils.send_commands(commands) self.dut['TDC']['EN_ARMING'] = True with self.readout(column=column, row=row, **{scan_par_name: scan_parameter_value}): self.register_utils.send_command( command=cal_lvl1_command, repeat=self.repeat_command) self.dut['TDC']['EN_ARMING'] = False self.dut['TDC']['ENABLE'] = False def handle_data(self, data): self.raw_data_file.append_item( data, scan_parameters=self.scan_parameters._asdict(), new_file=['column'], flush=False) # Create new file for each scan parameter change def analyze(self): create_hitor_calibration(self.output_filename)
if __name__ == "__main__": # Settings bias_voltage = -80 max_iv_voltage = -100 # Tuning cref = 12 target_threshold = 34 target_charge = 300 target_tot = 9 # TDC measurements plsr_dacs = [target_threshold, 40, 50, 60, 80, 100, 120, 150, 200, 250, 300, 350, 400, 500, 600, 700, 800] # PlsrDAC range for TDC calibration, should start at threshold col_span = [55, 75]#[50, 78] # pixel column range to use in TDC scans row_span = [125, 225]#[20, 315] # pixel row range to use in TDC scans tdc_pixel = make_box_pixel_mask_from_col_row(column=[col_span[0], col_span[1]], row=[row_span[0], row_span[1]]) # edge pixel are not used in analysis runmngr = RunManager('configuration.yaml') # IV scan runmngr.run_run(run=IVScan, run_conf={"voltages": np.arange(-1, max_iv_voltage - 1, -1), "max_voltage": max_iv_voltage, "bias_voltage": bias_voltage, "minimum_delay": 0.5}) # FE check and complete tuning runmngr.run_run(run=RegisterTest) runmngr.run_run(run=DigitalScan) # digital scan with std. settings if runmngr.current_run.register.flavor == 'fei4a': # FEI4 A related config changes, Deactivate noisy edge columns if FE-I4A runmngr.current_run.register.set_global_register_value("DisableColumnCnfg", 549755813891) # Disable noisy columns runmngr.current_run.register.set_global_register_value("Cref", cref) # Set correct cref runmngr.current_run.register.save_configuration(runmngr.current_run.register.configuration_file) runmngr.run_run(run=DigitalScan) # repeat digital scan with specific settings
class HitOrCalibration(Fei4RunBase): ''' Hit Or calibration scan ''' _default_run_conf = { "repeat_command": 1000, "scan_parameters": [('column', None), ('row', None), ('PlsrDAC', [ i for j in (range(26, 70, 10), range(80, 200, 50), range(240, 400, 100)) for i in j ])], # 0 400 sufficient "plot_tdc_histograms": False, "pixels": (np.dstack( np.where( make_box_pixel_mask_from_col_row([40, 45], [150, 155]) == 1)) + 1)[0], # list of (col, row) tupels. From 1 to 80/336. "enable_masks": ["Enable", "C_Low", "C_High"], "disable_masks": ["Imon"] } def configure(self): commands = [] commands.extend(self.register.get_commands("ConfMode")) self.register.set_global_register_value( "Trig_Count", 5) # decrease trigger count to reduce data self.register.set_global_register_value( "Trig_Lat", 216) # adjust delay for smaller bcid window self.register.set_global_register_value( "ErrorMask", 1536) # deactivate hit bus service record commands.extend( self.register.get_commands( "WrRegister", name=["Trig_Lat", "Trig_Count", "ErrorMask"])) self.register_utils.send_commands(commands) def scan(self): def write_double_column(column): return (column - 1) / 2 def inject_double_column(column): if column == 80: return 39 else: return (column) / 2 cal_lvl1_command = self.register.get_commands( "CAL")[0] + self.register.get_commands( "zeros", length=40)[0] + self.register.get_commands( "LV1")[0] + self.register.get_commands("zeros", length=250)[0] scan_par_name = self.scan_parameters._fields[ -1] # scan parameter is in inner loop scan_parameters_values = self.scan_parameters[ -1][:] # create deep copy of scan_parameters, they are overwritten in self.readout for pixel_index, pixel in enumerate(self.pixels): column = pixel[0] row = pixel[1] logging.info('Scanning pixel: %d / %d (column / row)' % (column, row)) if pixel_index: dcs = [write_double_column(column)] dcs.append(write_double_column(self.pixels[pixel_index - 1][0])) else: dcs = [] commands = [] commands.extend(self.register.get_commands("ConfMode")) single_pixel_enable_mask = make_pixel_mask_from_col_row([column], [row]) map( lambda mask_name: self.register.set_pixel_register_value( mask_name, single_pixel_enable_mask), self.enable_masks) commands.extend( self.register.get_commands("WrFrontEnd", same_mask_for_all_dc=False, dcs=dcs, name=self.enable_masks, joint_write=True)) single_pixel_disable_mask = make_pixel_mask_from_col_row([column], [row], default=1, value=0) map( lambda mask_name: self.register.set_pixel_register_value( mask_name, single_pixel_disable_mask), self.disable_masks) commands.extend( self.register.get_commands("WrFrontEnd", same_mask_for_all_dc=False, dcs=dcs, name=self.disable_masks, joint_write=True)) self.register.set_global_register_value( "Colpr_Addr", inject_double_column(column)) commands.append( self.register.get_commands("WrRegister", name=["Colpr_Addr"])[0]) self.register_utils.send_commands(commands) # self.fifo_readout.reset_sram_fifo() # after mask shifting you have AR VR in Sram that are not of interest but reset takes a long time self.dut['tdc_rx2']['ENABLE'] = True for scan_parameter_value in scan_parameters_values: if self.stop_run.is_set(): break logging.info('Scan step: %s %d' % (scan_par_name, scan_parameter_value)) commands = [] commands.extend(self.register.get_commands("ConfMode")) self.register.set_global_register_value( scan_par_name, scan_parameter_value) commands.extend( self.register.get_commands("WrRegister", name=[scan_par_name])) commands.extend(self.register.get_commands("RunMode")) self.register_utils.send_commands(commands) self.dut['tdc_rx2']['EN_ARMING'] = True with self.readout(column=column, row=row, PlsrDAC=scan_parameter_value): self.register_utils.send_command( command=cal_lvl1_command, repeat=self.repeat_command) self.dut['tdc_rx2']['EN_ARMING'] = False self.dut['tdc_rx2']['ENABLE'] = False def analyze(self): logging.info('Analyze and plot results') def plot_calibration(col_row_combinations, scan_parameter, calibration_data, repeat_command, filename): # Result calibration plot function for index, (column, row) in enumerate(col_row_combinations): logging.info("Plot calibration for pixel " + str(column) + '/' + str(row)) fig = Figure() canvas = FigureCanvas(fig) ax = fig.add_subplot(111) fig.patch.set_facecolor('white') ax.grid(True) ax.errorbar( scan_parameter, calibration_data[column - 1, row - 1, :, 0] * 25. + 25., yerr=[ calibration_data[column - 1, row - 1, :, 2] * 25, calibration_data[column - 1, row - 1, :, 2] * 25 ], fmt='o', label='FE-I4 ToT [ns]') ax.errorbar( scan_parameter, calibration_data[column - 1, row - 1, :, 1] * 1.5625, yerr=[ calibration_data[column - 1, row - 1, :, 3] * 1.5625, calibration_data[column - 1, row - 1, :, 3] * 1.5625 ], fmt='o', label='TDC ToT [ns]') ax.set_title('Calibration for pixel ' + str(column) + '/' + str(row) + '; ' + str(repeat_command) + ' injections per setting') ax.set_xlabel('Charge [PlsrDAC]') ax.set_ylabel('TOT') ax.legend(loc=0) filename.savefig(fig) if index > 100: # stop for too many plots break with AnalyzeRawData( raw_data_file=self.output_filename, create_pdf=True ) as analyze_raw_data: # Interpret the raw data file analyze_raw_data.create_occupancy_hist = False # too many scan parameters to do in ram histograming analyze_raw_data.create_hit_table = True analyze_raw_data.create_tdc_hist = True analyze_raw_data.interpreter.use_tdc_word( True ) # align events at TDC words, first word of event has to be a tdc word analyze_raw_data.interpret_word_table() analyze_raw_data.interpreter.print_summary() analyze_raw_data.plot_histograms() with tb.open_file( self.output_filename + '_interpreted.h5', 'r' ) as in_file_h5: # Get scan parameters from interpreted file scan_parameters_dict = get_scan_parameter( in_file_h5.root.meta_data[:]) inner_loop_parameter_values = scan_parameters_dict[next( reversed(scan_parameters_dict) )] # inner loop parameter name is unknown scan_parameter_names = scan_parameters_dict.keys() n_par_combinations = len( get_unique_scan_parameter_combinations( in_file_h5.root.meta_data[:])) col_row_combinations = get_unique_scan_parameter_combinations( in_file_h5.root.meta_data[:], scan_parameters=('column', 'row'), scan_parameter_columns_only=True) with tb.openFile(self.output_filename + "_calibration.h5", mode="w") as calibration_data_file: logging.info('Create calibration') output_pdf = PdfPages(self.output_filename + "_calibration.pdf") calibration_data = np.zeros( shape=(80, 336, len(inner_loop_parameter_values), 4), dtype='f4' ) # result of the calibration is a histogram with col_index, row_index, plsrDAC value, mean discrete tot, rms discrete tot, mean tot from TDC, rms tot from TDC progress_bar = progressbar.ProgressBar(widgets=[ '', progressbar.Percentage(), ' ', progressbar.Bar(marker='*', left='|', right='|'), ' ', progressbar.AdaptiveETA() ], maxval=n_par_combinations, term_width=80) old_scan_parameters = None tot_data = None tdc_data = None for index, (actual_scan_parameters, hits) in enumerate( get_hits_of_scan_parameter(self.output_filename + '_interpreted.h5', scan_parameter_names, chunk_size=1.5e7)): if index == 0: progress_bar.start( ) # start after the event index is created to get reasonable ETA actual_col, actual_row, _ = actual_scan_parameters if len(hits[np.logical_and(hits['column'] != actual_col, hits['row'] != actual_row)]): logging.warning( 'There are %d hits from not selected pixels in the data' % len(hits[np.logical_and(hits['column'] != actual_col, hits['row'] != actual_row)])) hits = hits[ (hits['event_status'] & 0b0000011110001000) == 0b0000000100000000] # only take hits from good events (one TDC word only, no error) column, row, tot, tdc = hits['column'], hits['row'], hits[ 'tot'], hits['TDC'] if old_scan_parameters != actual_scan_parameters: # Store the data of the actual PlsrDAC value if old_scan_parameters: # Special case for the first PlsrDAC setting inner_loop_scan_parameter_index = np.where( old_scan_parameters[-1] == inner_loop_parameter_values )[0][ 0] # translate the scan parameter value to an index for the result histogram calibration_data[column - 1, row - 1, inner_loop_scan_parameter_index, 0] = np.mean(tot_data) calibration_data[column - 1, row - 1, inner_loop_scan_parameter_index, 1] = np.mean(tdc_data) calibration_data[column - 1, row - 1, inner_loop_scan_parameter_index, 2] = np.std(tot_data) calibration_data[column - 1, row - 1, inner_loop_scan_parameter_index, 3] = np.std(tdc_data) progress_bar.update(index) tot_data = np.array(tot) tdc_data = np.array(tdc) old_scan_parameters = actual_scan_parameters else: np.concatenate((tot_data, tot)) np.concatenate((tdc_data, tdc)) else: inner_loop_scan_parameter_index = np.where( old_scan_parameters[-1] == inner_loop_parameter_values )[0][ 0] # translate the scan parameter value to an index for the result histogram calibration_data[column - 1, row - 1, inner_loop_scan_parameter_index, 0] = np.mean(tot_data) calibration_data[column - 1, row - 1, inner_loop_scan_parameter_index, 1] = np.mean(tdc_data) calibration_data[column - 1, row - 1, inner_loop_scan_parameter_index, 2] = np.std(tot_data) calibration_data[column - 1, row - 1, inner_loop_scan_parameter_index, 3] = np.std(tdc_data) calibration_data_out = calibration_data_file.createCArray( calibration_data_file.root, name='HitOrCalibration', title='Hit OR calibration data', atom=tb.Atom.from_dtype(calibration_data.dtype), shape=calibration_data.shape, filters=tb.Filters(complib='blosc', complevel=5, fletcher32=False)) calibration_data_out[:] = calibration_data calibration_data_out.attrs.dimensions = scan_parameter_names calibration_data_out.attrs.scan_parameter_values = inner_loop_parameter_values plot_calibration(col_row_combinations, scan_parameter=inner_loop_parameter_values, calibration_data=calibration_data, repeat_command=self.repeat_command, filename=output_pdf) output_pdf.close() progress_bar.finish()
max_iv_voltage = -100 # Tuning cref = 12 target_threshold = 34 target_charge = 300 target_tot = 9 # TDC measurements plsr_dacs = [ target_threshold, 40, 50, 60, 80, 100, 120, 150, 200, 250, 300, 350, 400, 500, 600, 700, 800 ] # PlsrDAC range for TDC calibration, should start at threshold col_span = [55, 75] # [50, 78] # pixel column range to use in TDC scans row_span = [125, 225] # [20, 315] # pixel row range to use in TDC scans tdc_pixel = make_box_pixel_mask_from_col_row( column=[col_span[0], col_span[1]], row=[row_span[0], row_span[1]]) # edge pixel are not used in analysis runmngr = RunManager('configuration.yaml') # IV scan runmngr.run_run(run=IVScan, run_conf={ "voltages": np.arange(-1, max_iv_voltage - 1, -1), "max_voltage": max_iv_voltage, "bias_voltage": bias_voltage, "minimum_delay": 0.5 }) # FE check and complete tuning runmngr.run_run(run=RegisterTest)
class HitOrCalibration(Fei4RunBase): ''' HitOR calibration scan ''' _default_run_conf = { "broadcast_commands": True, "threaded_scan": True, "n_injections": 200, # number of injections "injection_delay": 5000, # for really low feedbacks (ToT >> 300 ns) one needs to increase the injection delay "scan_parameters": [('column', None), ('row', None), ('PlsrDAC', [40, 50, 60, 80, 130, 180, 230, 280, 340, 440, 540, 640, 740])], # 0 400 sufficient for most tunings "reset_rx_on_error": True, # reset RX on errors that may occur during scan "pixels": (np.dstack( np.where( make_box_pixel_mask_from_col_row([40, 41], [150, 151]) == 1)) + 1).tolist() [0], # list of (col, row) tupels. From 1 to 80/336. "enable_shift_masks": ["Enable", "C_Low", "C_High"], # enable masks shifted during scan "disable_shift_masks": ["Imon"] # disable masks shifted during scan } def configure(self): commands = [] commands.extend(self.register.get_commands("ConfMode")) self.register.set_global_register_value( "Trig_Count", 6) # decrease trigger count to reduce data self.register.set_global_register_value( "Trig_Lat", 215) # adjust delay for smaller bcid window self.register.set_global_register_value( "ErrorMask", 1536) # deactivate hit bus service record commands.extend( self.register.get_commands( "WrRegister", name=["Trig_Lat", "Trig_Count", "ErrorMask"])) self.register_utils.send_commands(commands) def scan(self): def write_double_column(column): return (column - 1) / 2 def inject_double_column(column): if column == 80: return 39 else: return (column) / 2 cal_lvl1_command = self.register.get_commands( "CAL")[0] + self.register.get_commands( "zeros", length=40)[0] + self.register.get_commands( "LV1")[0] + self.register.get_commands( "zeros", length=self.injection_delay)[0] scan_parameter_name = self.scan_parameters._fields[ -1] # scan parameter is in inner loop scan_parameter_values = self.scan_parameters[ -1][:] # create deep copy of scan_parameters, they are overwritten in self.readout pixels_sorted = sorted(self.pixels) # , key=lambda tup: tup[0]) logging.info("Scanning %d pixels" % len(self.pixels)) # use sorted pixels to prevent overwriting of raw data file when writing a file per column for pixel_index, pixel in enumerate(pixels_sorted): if self.stop_run.is_set(): break column = pixel[0] row = pixel[1] logging.info('Scanning pixel: %d / %d (column / row)', column, row) if pixel_index: dcs = [write_double_column(column)] dcs.append(write_double_column(self.pixels[pixel_index - 1][0])) else: dcs = [] commands = [] commands.extend(self.register.get_commands("ConfMode")) single_pixel_enable_mask = make_pixel_mask_from_col_row([column], [row]) map( lambda mask_name: self.register.set_pixel_register_value( mask_name, single_pixel_enable_mask), self.enable_shift_masks) commands.extend( self.register.get_commands("WrFrontEnd", same_mask_for_all_dc=False, dcs=dcs, name=self.enable_shift_masks, joint_write=True)) single_pixel_disable_mask = make_pixel_mask_from_col_row([column], [row], default=1, value=0) map( lambda mask_name: self.register.set_pixel_register_value( mask_name, single_pixel_disable_mask), self.disable_shift_masks) commands.extend( self.register.get_commands("WrFrontEnd", same_mask_for_all_dc=False, dcs=dcs, name=self.disable_shift_masks, joint_write=True)) self.register.set_global_register_value( "Colpr_Addr", inject_double_column(column)) commands.append( self.register.get_commands("WrRegister", name=["Colpr_Addr"])[0]) self.register_utils.send_commands(commands) self.dut['TDC']['ENABLE'] = True self.dut['TDC'][ 'EN_NO_WRITE_TRIG_ERR'] = False # Do not trigger TDC words for scan_parameter_value in scan_parameter_values: if self.stop_run.is_set(): break commands = [] commands.extend(self.register.get_commands("ConfMode")) self.register.set_global_register_value( scan_parameter_name, scan_parameter_value) commands.extend( self.register.get_commands("WrRegister", name=[scan_parameter_name])) commands.extend(self.register.get_commands("RunMode")) self.register_utils.send_commands(commands) self.dut['TDC']['EN_ARMING'] = True with self.readout( reset_fifo=True, column=column, row=row, **{scan_parameter_name: scan_parameter_value}): self.register_utils.send_command(command=cal_lvl1_command, repeat=self.n_injections) self.dut['TDC']['EN_ARMING'] = False self.dut['TDC']['ENABLE'] = False def handle_data( self, data, new_file=['column'], flush=True): # Create new file for each scan parameter change super(HitOrCalibration, self).handle_data(data=data, new_file=new_file, flush=flush) def analyze(self): create_hitor_calibration(self.output_filename, plot_pixel_calibrations=True)