def scan(self): delay_parameter_name = self.scan_parameters._fields[1] logging.info("Scanning PlsrDAC = %s and %s = %s", str(self.scan_parameters[0]), delay_parameter_name, str(self.scan_parameters[1])) plsr_dac_values = self.scan_parameters.PlsrDAC[:] # create deep copy of scan_parameters, they are overwritten in self.readout delay_parameter_values = self.scan_parameters.PlsrDelay[:] # create deep copy of scan_parameters, they are overwritten in self.readout for plsr_dac_value in plsr_dac_values: # Change the Plsr DAC parameter commands = [] commands.extend(self.register.get_commands("ConfMode")) self.register.set_global_register_value('PlsrDAC', plsr_dac_value) commands.extend(self.register.get_commands("WrRegister", name=['PlsrDAC'])) self.register_utils.send_commands(commands) for delay_parameter_value in delay_parameter_values: # Loop over the Plsr delay parameter if self.stop_run.is_set(): break # Change the Plsr delay parameter commands = [] commands.extend(self.register.get_commands("ConfMode")) self.register.set_global_register_value(delay_parameter_name, delay_parameter_value) commands.extend(self.register.get_commands("WrRegister", name=[delay_parameter_name])) self.register_utils.send_commands(commands) cal_lvl1_command = self.register.get_commands("CAL")[0] + self.register.get_commands("zeros", length=40)[0] + self.register.get_commands("LV1")[0] with self.readout(plsr_dac_value, delay_parameter_value): scan_loop(self, cal_lvl1_command, repeat_command=self.n_injections, use_delay=True, mask_steps=self.mask_steps, enable_mask_steps=None, enable_double_columns=None, same_mask_for_all_dc=True, eol_function=None, digital_injection=False, enable_shift_masks=self.enable_shift_masks, disable_shift_masks=self.disable_shift_masks, restore_shift_masks=False, mask=invert_pixel_mask(self.register.get_pixel_register_value('Enable')) if self.use_enable_mask else None, double_column_correction=self.pulser_dac_correction)
def scan(self): delay_parameter_name = self.scan_parameters._fields[1] logging.info("Scanning PlsrDAC = %s and %s = %s" % (str(self.scan_parameters[0]), delay_parameter_name, str(self.scan_parameters[1]))) plsr_dac_values = self.scan_parameters.PlsrDAC[:] # create deep copy of scan_parameters, they are overwritten in self.readout delay_parameter_values = self.scan_parameters.PlsrDelay[:] # create deep copy of scan_parameters, they are overwritten in self.readout for plsr_dac_value in plsr_dac_values: # Change the Plsr DAC parameter commands = [] commands.extend(self.register.get_commands("ConfMode")) self.register.set_global_register_value('PlsrDAC', plsr_dac_value) commands.extend( self.register.get_commands("WrRegister", name=['PlsrDAC'])) self.register_utils.send_commands(commands) for delay_parameter_value in delay_parameter_values: # Loop over the Plsr delay parameter if self.stop_run.is_set(): break logging.info('Scan step: PlsrDAC %s, %s %d' % (plsr_dac_value, delay_parameter_name, delay_parameter_value)) # Change the Plsr delay parameter commands = [] commands.extend(self.register.get_commands("ConfMode")) self.register.set_global_register_value( delay_parameter_name, delay_parameter_value) commands.extend( self.register.get_commands("WrRegister", name=[delay_parameter_name])) self.register_utils.send_commands(commands) with self.readout(plsr_dac_value, delay_parameter_value): cal_lvl1_command = self.register.get_commands( "CAL")[0] + self.register.get_commands( "zeros", length=40 )[0] + self.register.get_commands("LV1")[0] scan_loop( self, cal_lvl1_command, repeat_command=self.n_injections, use_delay=True, mask_steps=self.mask_steps, enable_mask_steps=None, enable_double_columns=None, same_mask_for_all_dc=True, eol_function=None, digital_injection=False, enable_shift_masks=self.enable_shift_masks, disable_shift_masks=self.disable_shift_masks, restore_shift_masks=False, mask=invert_pixel_mask( self.register.get_pixel_register_value('Enable')) if self.use_enable_mask else None, double_column_correction=self.pulser_dac_correction)
def scan(self): with self.readout(): cal_lvl1_command = self.register.get_commands("CAL")[0] + self.register.get_commands("zeros", length=40)[0] + self.register.get_commands("LV1")[0] if self.enable_tdc: # activate TDC arming self.dut['TDC']['EN_ARMING'] = True scan_loop(self, cal_lvl1_command, repeat_command=self.n_injections, use_delay=True, mask_steps=self.mask_steps, enable_mask_steps=None, enable_double_columns=None, same_mask_for_all_dc=self.same_mask_for_all_dc, bol_function=self.activate_tdc, eol_function=self.deactivate_tdc, digital_injection=False, enable_shift_masks=self.enable_shift_masks, disable_shift_masks=self.disable_shift_masks, restore_shift_masks=False, mask=invert_pixel_mask(self.register.get_pixel_register_value('Enable')) if self.use_enable_mask else None, double_column_correction=self.pulser_dac_correction) else: scan_loop(self, cal_lvl1_command, repeat_command=self.n_injections, use_delay=True, mask_steps=self.mask_steps, enable_mask_steps=None, enable_double_columns=None, same_mask_for_all_dc=self.same_mask_for_all_dc, digital_injection=False, enable_shift_masks=self.enable_shift_masks, disable_shift_masks=self.disable_shift_masks, restore_shift_masks=False, mask=invert_pixel_mask(self.register.get_pixel_register_value('Enable')) if self.use_enable_mask else None, double_column_correction=self.pulser_dac_correction)
def scan(self): with self.readout(): cal_lvl1_command = self.register.get_commands("CAL")[0] + self.register.get_commands("zeros", length=40)[0] + self.register.get_commands("LV1")[0] if self.enable_tdc: # activate TDC arming self.dut['TDC']['EN_ARMING'] = True scan_loop(self, cal_lvl1_command, repeat_command=self.n_injections, use_delay=True, mask_steps=self.mask_steps, enable_mask_steps=self.enable_mask_steps, enable_double_columns=self.enable_double_columns, same_mask_for_all_dc=self.same_mask_for_all_dc, bol_function=self.activate_tdc, eol_function=self.deactivate_tdc, digital_injection=False, enable_shift_masks=self.enable_shift_masks, disable_shift_masks=self.disable_shift_masks, restore_shift_masks=False, mask=invert_pixel_mask(self.register.get_pixel_register_value('Enable')) if self.use_enable_mask else None, double_column_correction=self.pulser_dac_correction) else: scan_loop(self, cal_lvl1_command, repeat_command=self.n_injections, use_delay=True, mask_steps=self.mask_steps, enable_mask_steps=self.enable_mask_steps, enable_double_columns=self.enable_double_columns, same_mask_for_all_dc=self.same_mask_for_all_dc, digital_injection=False, enable_shift_masks=self.enable_shift_masks, disable_shift_masks=self.disable_shift_masks, restore_shift_masks=False, mask=invert_pixel_mask(self.register.get_pixel_register_value('Enable')) if self.use_enable_mask else None, double_column_correction=self.pulser_dac_correction)
def scan(self): scan_parameter_range = [ 0, (2**self.register.global_registers['PlsrDAC']['bitlength']) ] if self.scan_parameters.PlsrDAC[0]: scan_parameter_range[0] = self.scan_parameters.PlsrDAC[0] if self.scan_parameters.PlsrDAC[1]: scan_parameter_range[1] = self.scan_parameters.PlsrDAC[1] scan_parameter_range = range(scan_parameter_range[0], scan_parameter_range[1] + 1, self.step_size) logging.info( "Scanning %s from %d to %d" % ('PlsrDAC', scan_parameter_range[0], scan_parameter_range[-1])) for scan_parameter_value in scan_parameter_range: if self.stop_run.is_set(): break logging.info('Scan step: %s %d' % ('PlsrDAC', scan_parameter_value)) commands = [] commands.extend(self.register.get_commands("ConfMode")) self.register.set_global_register_value('PlsrDAC', scan_parameter_value) commands.extend( self.register.get_commands("WrRegister", name=['PlsrDAC'])) self.register_utils.send_commands(commands) with self.readout(PlsrDAC=scan_parameter_value): cal_lvl1_command = self.register.get_commands( "CAL")[0] + self.register.get_commands( "zeros", length=40)[0] + self.register.get_commands("LV1")[0] scan_loop(self, cal_lvl1_command, repeat_command=self.n_injections, use_delay=True, mask_steps=self.mask_steps, enable_mask_steps=None, enable_double_columns=None, same_mask_for_all_dc=True, eol_function=None, digital_injection=False, enable_shift_masks=self.enable_shift_masks, disable_shift_masks=self.disable_shift_masks, restore_shift_masks=False, mask=invert_pixel_mask( self.register.get_pixel_register_value('Enable')) if self.use_enable_mask else None, double_column_correction=self.pulser_dac_correction)
def scan(self): scan_parameter_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 %s from %d to %d", scan_parameter_name, scan_parameters_values[0], scan_parameters_values[-1]) 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_parameter_name, scan_parameter_value) commands.extend( self.register.get_commands("WrRegister", name=[scan_parameter_name])) self.register_utils.send_commands(commands) with self.readout(**{scan_parameter_name: scan_parameter_value}): cal_lvl1_command = self.register.get_commands( "CAL")[0] + self.register.get_commands( "zeros", length=40)[0] + self.register.get_commands("LV1")[0] scan_loop(self, cal_lvl1_command, repeat_command=self.n_injections, use_delay=True, mask_steps=self.mask_steps, enable_mask_steps=None, enable_double_columns=None, same_mask_for_all_dc=True, fast_dc_loop=True, bol_function=None, eol_function=None, digital_injection=False, enable_shift_masks=self.enable_shift_masks, disable_shift_masks=self.disable_shift_masks, restore_shift_masks=False, mask=invert_pixel_mask( self.register.get_pixel_register_value('Enable')) if self.use_enable_mask else None, double_column_correction=self.pulser_dac_correction)
def scan(self): with self.readout(): cal_lvl1_command = self.register.get_commands( "CAL")[0] + self.register.get_commands( "zeros", length=40)[0] + self.register.get_commands("LV1")[0] scan_loop(self, cal_lvl1_command, repeat_command=self.n_injections, use_delay=True, mask_steps=self.mask_steps, enable_mask_steps=None, enable_double_columns=None, same_mask_for_all_dc=True, eol_function=None, digital_injection=True, enable_shift_masks=["Enable", "EnableDigInj"], restore_shift_masks=False, mask=invert_pixel_mask( self.register.get_pixel_register_value('Enable')) if self.use_enable_mask else None)
def scan(self): scan_parameter_range = [0, (2 ** self.register.global_registers['PlsrDAC']['bitlength'])] if self.scan_parameters.PlsrDAC[0]: scan_parameter_range[0] = self.scan_parameters.PlsrDAC[0] if self.scan_parameters.PlsrDAC[1]: scan_parameter_range[1] = self.scan_parameters.PlsrDAC[1] scan_parameter_range = range(scan_parameter_range[0], scan_parameter_range[1] + 1, self.step_size) logging.info("Scanning %s from %d to %d", 'PlsrDAC', scan_parameter_range[0], scan_parameter_range[-1]) for scan_parameter_value in scan_parameter_range: if self.stop_run.is_set(): break commands = [] commands.extend(self.register.get_commands("ConfMode")) self.register.set_global_register_value('PlsrDAC', scan_parameter_value) commands.extend(self.register.get_commands("WrRegister", name=['PlsrDAC'])) self.register_utils.send_commands(commands) with self.readout(PlsrDAC=scan_parameter_value): cal_lvl1_command = self.register.get_commands("CAL")[0] + self.register.get_commands("zeros", length=40)[0] + self.register.get_commands("LV1")[0] scan_loop(self, cal_lvl1_command, repeat_command=self.n_injections, use_delay=True, mask_steps=self.mask_steps, enable_mask_steps=None, enable_double_columns=None, same_mask_for_all_dc=True, fast_dc_loop=True, bol_function=None, eol_function=None, digital_injection=False, enable_shift_masks=self.enable_shift_masks, disable_shift_masks=self.disable_shift_masks, restore_shift_masks=False, mask=invert_pixel_mask(self.register.get_pixel_register_value('Enable')) if self.use_enable_mask else None, double_column_correction=self.pulser_dac_correction)
def scan(self): if not self.plots_filename: self.plots_filename = PdfPages(self.output_filename + '.pdf') self.close_plots = True else: self.close_plots = False mask_steps = 3 enable_mask_steps = [] 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", mask_steps=mask_steps)[0] self.write_target_threshold() additional_scan = True lastBitResult = np.zeros(shape=self.register.get_pixel_register_value("TDAC").shape, dtype=self.register.get_pixel_register_value("TDAC").dtype) self.set_start_tdac() self.occupancy_best = np.empty(shape=(80, 336)) # array to store the best occupancy (closest to Ninjections/2) of the pixel self.occupancy_best.fill(self.n_injections_tdac) self.tdac_mask_best = self.register.get_pixel_register_value("TDAC") for scan_parameter_value, tdac_bit in enumerate(self.tdac_tune_bits): if additional_scan: self.set_tdac_bit(tdac_bit) logging.info('TDAC setting: bit %d = 1', tdac_bit) else: self.set_tdac_bit(tdac_bit, bit_value=0) logging.info('TDAC setting: bit %d = 0', tdac_bit) self.write_tdac_config() with self.readout(TDAC=scan_parameter_value, reset_sram_fifo=True, fill_buffer=True, clear_buffer=True, callback=self.handle_data): scan_loop(self, cal_lvl1_command, repeat_command=self.n_injections_tdac, mask_steps=mask_steps, enable_mask_steps=enable_mask_steps, enable_double_columns=None, same_mask_for_all_dc=True, eol_function=None, digital_injection=False, enable_shift_masks=self.enable_shift_masks, disable_shift_masks=self.disable_shift_masks, restore_shift_masks=True, mask=None, double_column_correction=self.pulser_dac_correction) occupancy_array, _, _ = np.histogram2d(*convert_data_array(data_array_from_data_iterable(self.fifo_readout.data), filter_func=is_data_record, converter_func=get_col_row_array_from_data_record_array), bins=(80, 336), range=[[1, 80], [1, 336]]) select_better_pixel_mask = abs(occupancy_array - self.n_injections_tdac / 2) <= abs(self.occupancy_best - self.n_injections_tdac / 2) pixel_with_too_high_occupancy_mask = occupancy_array > self.n_injections_tdac / 2 self.occupancy_best[select_better_pixel_mask] = occupancy_array[select_better_pixel_mask] if self.plot_intermediate_steps: plotThreeWay(occupancy_array.transpose(), title="Occupancy (TDAC tuning bit " + str(tdac_bit) + ")", x_axis_title='Occupancy', filename=self.plots_filename, maximum=self.n_injections_tdac) tdac_mask = self.register.get_pixel_register_value("TDAC") self.tdac_mask_best[select_better_pixel_mask] = tdac_mask[select_better_pixel_mask] if tdac_bit > 0: tdac_mask[pixel_with_too_high_occupancy_mask] = tdac_mask[pixel_with_too_high_occupancy_mask] & ~(1 << tdac_bit) self.register.set_pixel_register_value("TDAC", tdac_mask) if tdac_bit == 0: if additional_scan: # scan bit = 0 with the correct value again additional_scan = False lastBitResult = occupancy_array.copy() self.tdac_tune_bits.append(0) # bit 0 has to be scanned twice else: tdac_mask[abs(occupancy_array - self.n_injections_tdac / 2) > abs(lastBitResult - self.n_injections_tdac / 2)] = tdac_mask[abs(occupancy_array - self.n_injections_tdac / 2) > abs(lastBitResult - self.n_injections_tdac / 2)] | (1 << tdac_bit) occupancy_array[abs(occupancy_array - self.n_injections_tdac / 2) > abs(lastBitResult - self.n_injections_tdac / 2)] = lastBitResult[abs(occupancy_array - self.n_injections_tdac / 2) > abs(lastBitResult - self.n_injections_tdac / 2)] self.occupancy_best[abs(occupancy_array - self.n_injections_tdac / 2) <= abs(self.occupancy_best - self.n_injections_tdac / 2)] = occupancy_array[abs(occupancy_array - self.n_injections_tdac / 2) <= abs(self.occupancy_best - self.n_injections_tdac / 2)] self.tdac_mask_best[abs(occupancy_array - self.n_injections_tdac / 2) <= abs(self.occupancy_best - self.n_injections_tdac / 2)] = tdac_mask[abs(occupancy_array - self.n_injections_tdac / 2) <= abs(self.occupancy_best - self.n_injections_tdac / 2)] self.register.set_pixel_register_value("TDAC", self.tdac_mask_best) # set value for meta scan self.write_tdac_config()
def scan(self): self.start_condition_triggered = False # set to true if the start condition is true once self.stop_condition_triggered = False # set to true if the stop condition is true once self.start_at = 0.01 # if more than start_at*activated_pixel see at least one hit the precise scanning is started self.stop_at = 0.95 # if more than stop_at*activated_pixel see the maximum numbers of injection, the scan is stopped self.record_data = False # set to true to activate data storage, so far not everything is recorded to ease data analysis scan_parameter_range = [0, (2 ** self.register.global_registers['PlsrDAC']['bitlength'] - 1)] if self.scan_parameters.PlsrDAC[0]: scan_parameter_range[0] = self.scan_parameters.PlsrDAC[0] if self.scan_parameters.PlsrDAC[1]: scan_parameter_range[1] = self.scan_parameters.PlsrDAC[1] logging.info("Scanning %s from %d to %d", 'PlsrDAC', scan_parameter_range[0], scan_parameter_range[1]) self.scan_parameter_value = scan_parameter_range[0] # set to start value self.search_distance = self.search_distance self.data_points = 0 # counter variable to count the data points already recorded, have to be at least minimum_data_ponts # calculate DCs to scan from the columns to ignore enable_double_columns = range(0, 40) if 1 in self.ignore_columns: enable_double_columns.remove(0) if set((78, 79, 80)).issubset(self.ignore_columns): enable_double_columns.remove(39) for double_column in range(1, 39): if set((double_column * 2, (double_column * 2) + 1)).issubset(self.ignore_columns): enable_double_columns.remove(double_column) logging.info("Use DCs: %s", str(enable_double_columns)) self.select_arr_columns = range(0, 80) for column in self.ignore_columns: self.select_arr_columns.remove(column - 1) while self.scan_parameter_value <= scan_parameter_range[1]: # scan as long as scan parameter is smaller than defined maximum if self.stop_run.is_set(): break commands = [] commands.extend(self.register.get_commands("ConfMode")) self.register.set_global_register_value('PlsrDAC', self.scan_parameter_value) commands.extend(self.register.get_commands("WrRegister", name=['PlsrDAC'])) self.register_utils.send_commands(commands) with self.readout(PlsrDAC=self.scan_parameter_value, reset_sram_fifo=True, fill_buffer=True, clear_buffer=True, callback=self.handle_data if self.record_data else None): cal_lvl1_command = self.register.get_commands("CAL")[0] + self.register.get_commands("zeros", length=40)[0] + self.register.get_commands("LV1")[0] scan_loop(self, cal_lvl1_command, repeat_command=self.n_injections, use_delay=True, mask_steps=self.mask_steps, enable_mask_steps=self.enable_mask_steps, enable_double_columns=enable_double_columns, same_mask_for_all_dc=True, eol_function=None, digital_injection=False, enable_shift_masks=self.enable_shift_masks, disable_shift_masks=self.disable_shift_masks, restore_shift_masks=False, mask=invert_pixel_mask(self.register.get_pixel_register_value('Enable')) if self.use_enable_mask else None, double_column_correction=self.pulser_dac_correction) if not self.start_condition_triggered or self.data_points > self.minimum_data_points: # speed up, only create histograms when needed. Python is much too slow here. if not self.start_condition_triggered and not self.record_data: logging.info('Testing for start condition: %s %d', 'PlsrDAC', self.scan_parameter_value) if not self.stop_condition_triggered and self.record_data: logging.info('Testing for stop condition: %s %d', 'PlsrDAC', self.scan_parameter_value) col, row = convert_data_array(data_array_from_data_iterable(self.fifo_readout.data), filter_func=is_data_record, converter_func=get_col_row_array_from_data_record_array) if np.any(np.logical_and(col < 1, col > 80)) or np.any(np.logical_and(row < 1, row > 336)): # filter bad data records that can happen logging.warning('There are undefined %d data records (e.g. random data)', np.count_nonzero(np.logical_and(col < 1, col > 80)) + np.count_nonzero(np.logical_and(row < 1, row > 336))) col, row = col[np.logical_and(col > 0, col <= 80)], row[np.logical_and(row > 0, row < 336)] occupancy_array = hist_2d_index(col - 1, row - 1, shape=(80, 336)) self.scan_condition(occupancy_array) # start condition is met for the first time if self.start_condition_triggered and not self.record_data: self.scan_parameter_value = self.scan_parameter_value - self.search_distance + self.step_size if self.scan_parameter_value < 0: self.scan_parameter_value = 0 logging.info('Starting threshold scan at %s %d', 'PlsrDAC', self.scan_parameter_value) self.scan_parameter_start = self.scan_parameter_value self.record_data = True continue # saving data if self.record_data: self.data_points = self.data_points + 1 # stop condition is met for the first time if self.stop_condition_triggered and self.record_data: logging.info('Stopping threshold scan at %s %d', 'PlsrDAC', self.scan_parameter_value) break # increase scan parameter value if not self.start_condition_triggered: self.scan_parameter_value = self.scan_parameter_value + self.search_distance else: self.scan_parameter_value = self.scan_parameter_value + self.step_size if self.scan_parameter_value >= scan_parameter_range[1]: logging.warning("Reached maximum of PlsrDAC range... stopping scan")
def scan(self): scan_parameter_range = [ 0, (2**self.register.global_registers['PlsrDAC']['bitlength']) ] if self.scan_parameters.PlsrDAC[0]: scan_parameter_range[0] = self.scan_parameters.PlsrDAC[0] if self.scan_parameters.PlsrDAC[1]: scan_parameter_range[1] = self.scan_parameters.PlsrDAC[1] scan_parameter_range = range(scan_parameter_range[0], scan_parameter_range[1] + 1, self.step_size) logging.info("Scanning %s from %d to %d", 'PlsrDAC', scan_parameter_range[0], scan_parameter_range[-1]) def set_xtalk_mask(): frame = inspect.currentframe() if frame.f_back.f_locals['index'] == 0: mask = make_pixel_mask( steps=self.mask_steps, shift=frame.f_back.f_locals['mask_step']) mask = make_xtalk_mask(mask) map( lambda mask_name: self.register.set_pixel_register_value( mask_name, mask), self.disable_shift_masks) commands = [] commands.append(self.register.get_commands("ConfMode")[0]) commands.extend( self.register.get_commands("WrFrontEnd", same_mask_for_all_dc=True, name=self.xtalk_shift_mask, joint_write=True)) commands.append(self.register.get_commands("RunMode")[0]) self.register_utils.send_commands(commands, concatenate=True) for scan_parameter_value in scan_parameter_range: if self.stop_run.is_set(): break commands = [] commands.extend(self.register.get_commands("ConfMode")) self.register.set_global_register_value('PlsrDAC', scan_parameter_value) commands.extend( self.register.get_commands("WrRegister", name=['PlsrDAC'])) self.register_utils.send_commands(commands) with self.readout(PlsrDAC=scan_parameter_value): cal_lvl1_command = self.register.get_commands( "CAL")[0] + self.register.get_commands( "zeros", length=40)[0] + self.register.get_commands("LV1")[0] scan_loop(self, cal_lvl1_command, repeat_command=self.n_injections, use_delay=True, mask_steps=self.mask_steps, enable_mask_steps=None, enable_double_columns=None, same_mask_for_all_dc=False, fast_dc_loop=False, bol_function=set_xtalk_mask, eol_function=None, digital_injection=False, enable_shift_masks=self.enable_shift_masks, disable_shift_masks=self.disable_shift_masks, restore_shift_masks=False, mask=invert_pixel_mask( self.register.get_pixel_register_value('Enable')) if self.use_enable_mask else None, double_column_correction=self.pulser_dac_correction)
def scan(self): with self.readout(): cal_lvl1_command = self.register.get_commands("CAL")[0] + self.register.get_commands("zeros", length=40)[0] + self.register.get_commands("LV1")[0] scan_loop(self, cal_lvl1_command, repeat_command=self.n_injections, use_delay=True, mask_steps=self.mask_steps, enable_mask_steps=None, enable_double_columns=None, same_mask_for_all_dc=True, eol_function=None, digital_injection=True, enable_shift_masks=["Enable", "EnableDigInj"], restore_shift_masks=False, mask=invert_pixel_mask(self.register.get_pixel_register_value('Enable')) if self.use_enable_mask else None)
def scan(self): if not self.plots_filename: self.plots_filename = PdfPages(self.output_filename + '.pdf') self.close_plots = True else: self.close_plots = False enable_mask_steps = [] 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", mask_steps=self.mask_steps)[0] self.write_target_charge() additional_scan = True lastBitResult = np.zeros(shape=self.register.get_pixel_register_value("FDAC").shape, dtype=self.register.get_pixel_register_value("FDAC").dtype) self.set_start_fdac() self.tot_mean_best = np.empty(shape=(80, 336)) # array to store the best occupancy (closest to Ninjections/2) of the pixel self.tot_mean_best.fill(0) self.fdac_mask_best = self.register.get_pixel_register_value("FDAC") for scan_parameter_value, fdac_bit in enumerate(self.fdac_tune_bits): if additional_scan: self.set_fdac_bit(fdac_bit) logging.info('FDAC setting: bit %d = 1', fdac_bit) else: self.set_fdac_bit(fdac_bit, bit_value=0) logging.info('FDAC setting: bit %d = 0', fdac_bit) self.write_fdac_config() with self.readout(FDAC=scan_parameter_value, reset_sram_fifo=True, fill_buffer=True, clear_buffer=True, callback=self.handle_data): scan_loop(self, cal_lvl1_command, repeat_command=self.n_injections_fdac, mask_steps=self.mask_steps, enable_mask_steps=enable_mask_steps, enable_double_columns=None, same_mask_for_all_dc=True, eol_function=None, digital_injection=False, enable_shift_masks=self.enable_shift_masks, disable_shift_masks=self.disable_shift_masks, restore_shift_masks=True, mask=None, double_column_correction=self.pulser_dac_correction) col_row_tot = np.column_stack(convert_data_array(data_array_from_data_iterable(self.fifo_readout.data), filter_func=is_data_record, converter_func=get_col_row_tot_array_from_data_record_array)) tot_array = np.histogramdd(col_row_tot, bins=(80, 336, 16), range=[[1, 80], [1, 336], [0, 15]])[0] tot_mean_array = np.average(tot_array, axis=2, weights=range(0, 16)) * sum(range(0, 16)) / self.n_injections_fdac select_better_pixel_mask = abs(tot_mean_array - self.target_tot) <= abs(self.tot_mean_best - self.target_tot) pixel_with_too_small_mean_tot_mask = tot_mean_array < self.target_tot self.tot_mean_best[select_better_pixel_mask] = tot_mean_array[select_better_pixel_mask] if self.plot_intermediate_steps: plot_three_way(hist=tot_mean_array.transpose().transpose(), title="Mean ToT (FDAC tuning bit " + str(fdac_bit) + ")", x_axis_title='mean ToT', filename=self.plots_filename, minimum=0, maximum=15) fdac_mask = self.register.get_pixel_register_value("FDAC") self.fdac_mask_best[select_better_pixel_mask] = fdac_mask[select_better_pixel_mask] if fdac_bit > 0: fdac_mask[pixel_with_too_small_mean_tot_mask] = fdac_mask[pixel_with_too_small_mean_tot_mask] & ~(1 << fdac_bit) self.register.set_pixel_register_value("FDAC", fdac_mask) if fdac_bit == 0: if additional_scan: # scan bit = 0 with the correct value again additional_scan = False lastBitResult = tot_mean_array.copy() self.fdac_tune_bits.append(0) # bit 0 has to be scanned twice else: fdac_mask[abs(tot_mean_array - self.target_tot) > abs(lastBitResult - self.target_tot)] = fdac_mask[abs(tot_mean_array - self.target_tot) > abs(lastBitResult - self.target_tot)] | (1 << fdac_bit) tot_mean_array[abs(tot_mean_array - self.target_tot) > abs(lastBitResult - self.target_tot)] = lastBitResult[abs(tot_mean_array - self.target_tot) > abs(lastBitResult - self.target_tot)] self.tot_mean_best[abs(tot_mean_array - self.target_tot) <= abs(self.tot_mean_best - self.n_injections_fdac / 2)] = tot_mean_array[abs(tot_mean_array - self.target_tot) <= abs(self.tot_mean_best - self.n_injections_fdac / 2)] self.fdac_mask_best[abs(tot_mean_array - self.target_tot) <= abs(self.tot_mean_best - self.n_injections_fdac / 2)] = fdac_mask[abs(tot_mean_array - self.target_tot) <= abs(self.tot_mean_best - self.n_injections_fdac / 2)] self.register.set_pixel_register_value("FDAC", self.fdac_mask_best) # set value for meta scan self.write_fdac_config()
def scan(self): if not self.plots_filename: self.plots_filename = PdfPages(self.output_filename + '.pdf') self.close_plots = True else: self.close_plots = False 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", mask_steps=self.mask_steps_gdac)[0] self.write_target_threshold() for gdac_bit in self.gdac_tune_bits: # reset all GDAC bits self.set_gdac_bit(gdac_bit, bit_value=0, send_command=False) last_bit_result = self.n_injections_gdac decreased_threshold = False # needed to determine if the FE is noisy all_bits_zero = True def bits_set(int_type): int_type = int(int_type) position = 0 bits_set = [] while (int_type): if (int_type & 1): bits_set.append(position) position += 1 int_type = int_type >> 1 return bits_set # calculate selected pixels from the mask and the disabled columns select_mask_array = np.zeros(shape=(80, 336), dtype=np.uint8) if not self.enable_mask_steps_gdac: self.enable_mask_steps_gdac = range(self.mask_steps_gdac) for mask_step in self.enable_mask_steps_gdac: select_mask_array += make_pixel_mask(steps=self.mask_steps_gdac, shift=mask_step) for column in bits_set( self.register.get_global_register_value("DisableColumnCnfg")): logging.info('Deselect double column %d' % column) select_mask_array[column, :] = 0 additional_scan = True occupancy_best = 0 gdac_best = self.register_utils.get_gdac() for gdac_bit in self.gdac_tune_bits: if additional_scan: self.set_gdac_bit(gdac_bit) scan_parameter_value = ( self.register.get_global_register_value("Vthin_AltCoarse") << 8 ) + self.register.get_global_register_value("Vthin_AltFine") logging.info('GDAC setting: %d, bit %d = 1', scan_parameter_value, gdac_bit) else: self.set_gdac_bit(gdac_bit, bit_value=0) scan_parameter_value = ( self.register.get_global_register_value("Vthin_AltCoarse") << 8 ) + self.register.get_global_register_value("Vthin_AltFine") logging.info('GDAC setting: %d, bit %d = 0', scan_parameter_value, gdac_bit) with self.readout(GDAC=scan_parameter_value, reset_sram_fifo=True, fill_buffer=True, clear_buffer=True, callback=self.handle_data): scan_loop(self, cal_lvl1_command, repeat_command=self.n_injections_gdac, mask_steps=self.mask_steps_gdac, enable_mask_steps=self.enable_mask_steps_gdac, enable_double_columns=None, same_mask_for_all_dc=True, eol_function=None, digital_injection=False, enable_shift_masks=self.enable_shift_masks, disable_shift_masks=self.disable_shift_masks, restore_shift_masks=True, mask=None, double_column_correction=self.pulser_dac_correction) occupancy_array, _, _ = np.histogram2d(*convert_data_array( data_array_from_data_iterable(self.fifo_readout.data), filter_func=is_data_record, converter_func=get_col_row_array_from_data_record_array), bins=(80, 336), range=[[1, 80], [1, 336]]) self.occ_array_sel_pixel = np.ma.array( occupancy_array, mask=np.logical_not(np.ma.make_mask(select_mask_array)) ) # take only selected pixel into account by creating a mask median_occupancy = np.ma.median(self.occ_array_sel_pixel) if abs(median_occupancy - self.n_injections_gdac / 2) < abs(occupancy_best - self.n_injections_gdac / 2): occupancy_best = median_occupancy gdac_best = self.register_utils.get_gdac() if self.plot_intermediate_steps: plot_three_way(self.occ_array_sel_pixel.transpose(), title="Occupancy (GDAC " + str(scan_parameter_value) + " with tuning bit " + str(gdac_bit) + ")", x_axis_title='Occupancy', filename=self.plots_filename, maximum=self.n_injections_gdac) if abs( median_occupancy - self.n_injections_gdac / 2 ) < self.max_delta_threshold and gdac_bit > 0: # abort if good value already found to save time logging.info( 'Median = %f, good result already achieved (median - Ninj/2 < %f), skipping not varied bits', median_occupancy, self.max_delta_threshold) break if median_occupancy == 0 and decreased_threshold and all_bits_zero: logging.info('Chip may be noisy') if gdac_bit > 0: if ( median_occupancy < self.n_injections_gdac / 2 ): # set GDAC bit to 0 if the occupancy is too lowm, thus decrease threshold logging.info('Median = %f < %f, set bit %d = 0', median_occupancy, self.n_injections_gdac / 2, gdac_bit) self.set_gdac_bit(gdac_bit, bit_value=0) decreased_threshold = True else: # set GDAC bit to 1 if the occupancy is too high, thus increase threshold logging.info('Median = %f > %f, leave bit %d = 1', median_occupancy, self.n_injections_gdac / 2, gdac_bit) decreased_threshold = False all_bits_zero = False elif gdac_bit == 0: if additional_scan: # scan bit = 0 with the correct value again additional_scan = False last_bit_result = self.occ_array_sel_pixel.copy() self.gdac_tune_bits.append( self.gdac_tune_bits[-1] ) # the last tune bit has to be scanned twice else: last_bit_result_median = np.median( last_bit_result[select_mask_array > 0]) logging.info('Scanned bit 0 = 0 with %f instead of %f', median_occupancy, last_bit_result_median) if abs(median_occupancy - self.n_injections_gdac / 2) > abs( last_bit_result_median - self.n_injections_gdac / 2 ): # if bit 0 = 0 is worse than bit 0 = 1, so go back self.set_gdac_bit(gdac_bit, bit_value=1) logging.info('Set bit 0 = 1') self.occ_array_sel_pixel = last_bit_result median_occupancy = np.ma.median( self.occ_array_sel_pixel) else: logging.info('Set bit 0 = 0') if abs(occupancy_best - self.n_injections_gdac / 2) < abs( median_occupancy - self.n_injections_gdac / 2): logging.info( "Binary search converged to non optimal value, take best measured value instead" ) median_occupancy = occupancy_best self.register_utils.set_gdac(gdac_best, send_command=False) self.gdac_best = self.register_utils.get_gdac() if np.all((((self.gdac_best & (1 << np.arange(16)))) > 0 ).astype(int)[self.gdac_tune_bits[:-2]] == 1): logging.warning('Selected GDAC bits reached maximum value') elif np.all((((self.gdac_best & (1 << np.arange(16)))) > 0 ).astype(int)[self.gdac_tune_bits] == 0): logging.warning('Selected GDAC bits reached minimum value') if abs(median_occupancy - self.n_injections_gdac / 2) > 2 * self.max_delta_threshold: logging.warning( 'Global threshold tuning failed. Delta threshold = %f > %f. Vthin_AltCoarse / Vthin_AltFine = %d / %d', abs(median_occupancy - self.n_injections_gdac / 2), self.max_delta_threshold, self.register.get_global_register_value("Vthin_AltCoarse"), self.register.get_global_register_value("Vthin_AltFine")) else: logging.info( 'Tuned GDAC to Vthin_AltCoarse / Vthin_AltFine = %d / %d', self.register.get_global_register_value("Vthin_AltCoarse"), self.register.get_global_register_value("Vthin_AltFine")) self.gdac_best = self.register_utils.get_gdac()
def scan(self): if not self.plots_filename: self.plots_filename = PdfPages(self.output_filename + '.pdf') self.close_plots = True else: self.close_plots = False enable_mask_steps = [0] # one mask step to increase speed, no effect on precision 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", mask_steps=self.mask_steps)[0] self.write_target_charge() for feedback_bit in self.feedback_tune_bits: # reset all GDAC bits self.set_prmp_vbpf_bit(feedback_bit, bit_value=0) additional_scan = True last_bit_result = self.n_injections_feedback tot_mean_best = 0 feedback_best = self.register.get_global_register_value("PrmpVbpf") for feedback_bit in self.feedback_tune_bits: if additional_scan: self.set_prmp_vbpf_bit(feedback_bit) logging.info('PrmpVbpf setting: %d, bit %d = 1', self.register.get_global_register_value("PrmpVbpf"), feedback_bit) else: self.set_prmp_vbpf_bit(feedback_bit, bit_value=0) logging.info('PrmpVbpf setting: %d, bit %d = 0', self.register.get_global_register_value("PrmpVbpf"), feedback_bit) scan_parameter_value = self.register.get_global_register_value("PrmpVbpf") with self.readout(PrmpVbpf=scan_parameter_value, reset_sram_fifo=True, fill_buffer=True, clear_buffer=True, callback=self.handle_data): scan_loop(self, cal_lvl1_command, repeat_command=self.n_injections_feedback, mask_steps=self.mask_steps, enable_mask_steps=enable_mask_steps, enable_double_columns=None, same_mask_for_all_dc=True, eol_function=None, digital_injection=False, enable_shift_masks=self.enable_shift_masks, disable_shift_masks=self.disable_shift_masks, restore_shift_masks=True, mask=None, double_column_correction=self.pulser_dac_correction) tots = convert_data_array(data_array_from_data_iterable(self.fifo_readout.data), filter_func=is_data_record, converter_func=get_tot_array_from_data_record_array) mean_tot = np.mean(tots) if np.isnan(mean_tot): logging.error("No hits, ToT calculation not possible, tuning will fail") if abs(mean_tot - self.target_tot) < abs(tot_mean_best - self.target_tot): tot_mean_best = mean_tot feedback_best = self.register.get_global_register_value("PrmpVbpf") logging.info('Mean ToT = %f', mean_tot) self.tot_array, _ = np.histogram(a=tots, range=(0, 16), bins=16) if self.plot_intermediate_steps: plot_tot(hist=self.tot_array, title='ToT distribution (PrmpVbpf ' + str(scan_parameter_value) + ')', filename=self.plots_filename) if abs(mean_tot - self.target_tot) < self.max_delta_tot and feedback_bit > 0: # abort if good value already found to save time logging.info('Good result already achieved, skipping missing bits') break if feedback_bit > 0 and mean_tot < self.target_tot: self.set_prmp_vbpf_bit(feedback_bit, bit_value=0) logging.info('Mean ToT = %f < %d ToT, set bit %d = 0', mean_tot, self.target_tot, feedback_bit) if feedback_bit == 0: if additional_scan: # scan bit = 0 with the correct value again additional_scan = False last_bit_result = mean_tot self.feedback_tune_bits.append(0) # bit 0 has to be scanned twice else: logging.info('Scanned bit 0 = 0 with %f instead of %f for scanned bit 0 = 1', mean_tot, last_bit_result) if(abs(mean_tot - self.target_tot) > abs(last_bit_result - self.target_tot)): # if bit 0 = 0 is worse than bit 0 = 1, so go back self.set_prmp_vbpf_bit(feedback_bit, bit_value=1) mean_tot = last_bit_result logging.info('Set bit 0 = 1') else: logging.info('Set bit 0 = 0') if abs(mean_tot - self.target_tot) > abs(tot_mean_best - self.target_tot): logging.info("Binary search converged to non optimal value, take best measured value instead") mean_tot = tot_mean_best self.register.set_global_register_value("PrmpVbpf", feedback_best) if self.register.get_global_register_value("PrmpVbpf") == 0 or self.register.get_global_register_value("PrmpVbpf") == 254: logging.warning('PrmpVbpf reached minimum/maximum value') if self.fail_on_warning: raise RuntimeWarning('PrmpVbpf reached minimum/maximum value') if abs(mean_tot - self.target_tot) > 2 * self.max_delta_tot: logging.warning('Global feedback tuning failed. Delta ToT = %f > %f. PrmpVbpf = %d', abs(mean_tot - self.target_tot), self.max_delta_tot, self.register.get_global_register_value("PrmpVbpf")) if self.fail_on_warning: raise RuntimeWarning('Global feedback tuning failed.') else: logging.info('Tuned PrmpVbpf to %d', self.register.get_global_register_value("PrmpVbpf")) self.feedback_best = self.register.get_global_register_value("PrmpVbpf")
def scan(self): cal_lvl1_command = self.register.get_commands( "CAL")[0] + self.register.get_commands( "zeros", length=40)[0] + self.register.get_commands("LV1")[0] self.write_target_threshold() scan_parameter_range = [ (2**self.register.global_registers['Vthin_AltFine']['bitlength']), 0 ] # high to low if self.start_gdac: scan_parameter_range[0] = self.start_gdac if self.gdac_lower_limit: scan_parameter_range[1] = self.gdac_lower_limit scan_parameter_range = np.arange(scan_parameter_range[0], scan_parameter_range[1] - 1, self.step_size) logging.info("Scanning %s from %d to %d", 'GDAC', scan_parameter_range[0], scan_parameter_range[-1]) def bits_set(int_type): int_type = int(int_type) position = 0 bits_set = [] while (int_type): if (int_type & 1): bits_set.append(position) position += 1 int_type = int_type >> 1 return bits_set # calculate selected pixels from the mask and the disabled columns select_mask_array = np.zeros(shape=(80, 336), dtype=np.uint8) self.occ_array_sel_pixels_best = select_mask_array.copy() self.occ_array_desel_pixels_best = select_mask_array.copy() if not self.enable_mask_steps_gdac: self.enable_mask_steps_gdac = range(self.mask_steps) for mask_step in self.enable_mask_steps_gdac: select_mask_array += make_pixel_mask(steps=self.mask_steps, shift=mask_step) for column in bits_set( self.register.get_global_register_value("DisableColumnCnfg")): logging.info('Deselect double column %d' % column) select_mask_array[column, :] = 0 gdac_values = [] gdac_occupancies = [] gdac_occ_array_sel_pixels = [] gdac_occ_array_desel_pixels = [] median_occupancy_last_step = None for scan_parameter_value in scan_parameter_range: if self.stop_run.is_set(): break self.register_utils.set_gdac(scan_parameter_value) with self.readout(GDAC=scan_parameter_value, fill_buffer=True): scan_loop(self, command=cal_lvl1_command, repeat_command=self.n_injections_gdac, mask_steps=self.mask_steps, enable_mask_steps=self.enable_mask_steps_gdac, enable_double_columns=None, same_mask_for_all_dc=self.same_mask_for_all_dc, eol_function=None, digital_injection=False, enable_shift_masks=self.enable_shift_masks, disable_shift_masks=self.disable_shift_masks, restore_shift_masks=True, mask=None, double_column_correction=self.pulser_dac_correction) data = convert_data_array( array=self.read_data(), filter_func=is_data_record, converter_func=get_col_row_array_from_data_record_array) occupancy_array, _, _ = np.histogram2d(*data, bins=(80, 336), range=[[1, 80], [1, 336]]) occ_array_sel_pixels = np.ma.array( occupancy_array, mask=np.logical_not(np.ma.make_mask(select_mask_array)) ) # take only selected pixel into account by using the mask occ_array_desel_pixels = np.ma.array( occupancy_array, mask=np.ma.make_mask(select_mask_array) ) # take only de-selected pixel into account by using the inverted mask median_occupancy = np.ma.median(occ_array_sel_pixels) percentile_noise_occupancy = np.percentile( occ_array_desel_pixels.compressed(), 99.0) occupancy_almost_zero = np.allclose(median_occupancy, 0) no_noise = np.allclose(percentile_noise_occupancy, 0) gdac_values.append(self.register_utils.get_gdac()) gdac_occupancies.append(median_occupancy) gdac_occ_array_sel_pixels.append(occ_array_sel_pixels.copy()) gdac_occ_array_desel_pixels.append(occ_array_desel_pixels.copy()) self.occ_array_sel_pixels_best = occ_array_sel_pixels.copy() self.occ_array_desel_pixels_best = occ_array_desel_pixels.copy() # abort early if threshold is found if no_noise and not occupancy_almost_zero and ( median_occupancy_last_step is not None and median_occupancy >= median_occupancy_last_step ) and median_occupancy >= self.n_injections_gdac / 2.0: break if no_noise and not occupancy_almost_zero: median_occupancy_last_step = median_occupancy else: median_occupancy_last_step = 0.0 if not self.stop_run.is_set(): # select best GDAC value sorted_indices = np.argsort(np.array(gdac_values)) occupancy_sorted = np.array(gdac_occupancies)[sorted_indices] gdac_sorted = np.sort(gdac_values) gdac_min_idx = np.where( occupancy_sorted >= self.n_injections_gdac / 2.0)[0][-1] occupancy_sorted_sel = occupancy_sorted[gdac_min_idx:] gdac_sorted_sel = gdac_sorted[gdac_min_idx:] best_index_sel = np.abs( np.array(occupancy_sorted_sel) - self.n_injections_gdac / 2.0).argmin() best_index = sorted_indices[gdac_min_idx:][::-1][best_index_sel] gdac_best = gdac_values[best_index] median_occupancy = gdac_occupancies[best_index] self.register_utils.set_gdac(gdac_best, send_command=False) # for plotting self.occ_array_sel_pixels_best = gdac_occ_array_sel_pixels[ best_index] self.occ_array_desel_pixels_best = gdac_occ_array_desel_pixels[ best_index] self.gdac_best = self.register_utils.get_gdac() if abs(median_occupancy - self.n_injections_gdac / 2.0 ) > self.max_delta_threshold and not self.stop_run.is_set(): if np.all((((self.gdac_best & (1 << np.arange( self.register.global_registers['Vthin_AltFine'] ['bitlength'] + self.register. global_registers['Vthin_AltFine']['bitlength'])))) > 0 ).astype(int) == 0): if self.fail_on_warning: raise RuntimeWarning( 'Selected GDAC bits reached minimum value') else: logging.warning( 'Selected GDAC bits reached minimum value') else: if self.fail_on_warning: raise RuntimeWarning( 'Global threshold tuning failed. Delta threshold = %.2f > %.2f. Vthin_AltCoarse / Vthin_AltFine = %d / %d' % (abs(median_occupancy - self.n_injections_gdac / 2.0), self.max_delta_threshold, self.register.get_global_register_value( "Vthin_AltCoarse"), self.register.get_global_register_value( "Vthin_AltFine"))) else: logging.warning( 'Global threshold tuning failed. Delta threshold = %.2f > %.2f. Vthin_AltCoarse / Vthin_AltFine = %d / %d', abs(median_occupancy - self.n_injections_gdac / 2.0), self.max_delta_threshold, self.register.get_global_register_value( "Vthin_AltCoarse"), self.register.get_global_register_value( "Vthin_AltFine")) else: logging.info( 'Tuned GDAC to Vthin_AltCoarse / Vthin_AltFine = %d / %d', self.register.get_global_register_value("Vthin_AltCoarse"), self.register.get_global_register_value("Vthin_AltFine"))
def scan(self): enable_mask_steps = [] cal_lvl1_command = self.register.get_commands( "CAL")[0] + self.register.get_commands( "zeros", length=40)[0] + self.register.get_commands("LV1")[0] self.write_target_threshold() additional_scan = True lastBitResult = np.zeros( shape=self.register.get_pixel_register_value("TDAC").shape, dtype=self.register.get_pixel_register_value("TDAC").dtype) self.set_start_tdac() self.occupancy_best = np.full( shape=(80, 336), fill_value=self.n_injections_tdac ) # array to store the best occupancy (closest to Ninjections/2) of the pixel self.tdac_mask_best = self.register.get_pixel_register_value("TDAC") tdac_tune_bits = self.tdac_tune_bits[:] for scan_parameter_value, tdac_bit in enumerate(tdac_tune_bits): if self.stop_run.is_set(): break if additional_scan: self.set_tdac_bit(tdac_bit) logging.info('TDAC setting: bit %d = 1', tdac_bit) else: self.set_tdac_bit(tdac_bit, bit_value=0) logging.info('TDAC setting: bit %d = 0', tdac_bit) self.write_tdac_config() with self.readout(TDAC=scan_parameter_value, fill_buffer=True): scan_loop(self, command=cal_lvl1_command, repeat_command=self.n_injections_tdac, mask_steps=self.mask_steps, enable_mask_steps=enable_mask_steps, enable_double_columns=None, same_mask_for_all_dc=self.same_mask_for_all_dc, eol_function=None, digital_injection=False, enable_shift_masks=self.enable_shift_masks, disable_shift_masks=self.disable_shift_masks, restore_shift_masks=True, mask=None, double_column_correction=self.pulser_dac_correction) data = convert_data_array( array=self.read_data(), filter_func=is_data_record, converter_func=get_col_row_array_from_data_record_array) occupancy_array, _, _ = np.histogram2d(*data, bins=(80, 336), range=[[1, 80], [1, 336]]) select_better_pixel_mask = abs(occupancy_array - self.n_injections_tdac / 2) <= abs( self.occupancy_best - self.n_injections_tdac / 2) pixel_with_too_high_occupancy_mask = occupancy_array > self.n_injections_tdac / 2 self.occupancy_best[select_better_pixel_mask] = occupancy_array[ select_better_pixel_mask] if self.plot_intermediate_steps: plot_three_way(occupancy_array.transpose(), title="Occupancy (TDAC tuning bit " + str(tdac_bit) + ")", x_axis_title='Occupancy', filename=self.plots_filename, maximum=self.n_injections_tdac) tdac_mask = self.register.get_pixel_register_value("TDAC") self.tdac_mask_best[select_better_pixel_mask] = tdac_mask[ select_better_pixel_mask] if tdac_bit > 0: tdac_mask[pixel_with_too_high_occupancy_mask] = tdac_mask[ pixel_with_too_high_occupancy_mask] & ~(1 << tdac_bit) self.register.set_pixel_register_value("TDAC", tdac_mask) if tdac_bit == 0: if additional_scan: # scan bit = 0 with the correct value again additional_scan = False lastBitResult = occupancy_array.copy() tdac_tune_bits.append(0) # bit 0 has to be scanned twice else: tdac_mask[ abs(occupancy_array - self.n_injections_tdac / 2) > abs(lastBitResult - self.n_injections_tdac / 2)] = tdac_mask[ abs(occupancy_array - self.n_injections_tdac / 2) > abs(lastBitResult - self.n_injections_tdac / 2)] | ( 1 << tdac_bit) occupancy_array[ abs(occupancy_array - self.n_injections_tdac / 2) > abs(lastBitResult - self.n_injections_tdac / 2)] = lastBitResult[ abs(occupancy_array - self.n_injections_tdac / 2) > abs(lastBitResult - self.n_injections_tdac / 2)] self.occupancy_best[ abs(occupancy_array - self.n_injections_tdac / 2) <= abs(self.occupancy_best - self.n_injections_tdac / 2)] = occupancy_array[ abs(occupancy_array - self.n_injections_tdac / 2) <= abs(self.occupancy_best - self.n_injections_tdac / 2)] self.tdac_mask_best[ abs(occupancy_array - self.n_injections_tdac / 2) <= abs(self.occupancy_best - self.n_injections_tdac / 2)] = tdac_mask[ abs(occupancy_array - self.n_injections_tdac / 2) <= abs(self.occupancy_best - self.n_injections_tdac / 2)] self.register.set_pixel_register_value( "TDAC", self.tdac_mask_best) # set value for meta scan self.write_tdac_config()
def scan(self): if not self.plots_filename: self.plots_filename = PdfPages(self.output_filename + '.pdf') self.close_plots = True else: self.close_plots = False enable_mask_steps = [] cal_lvl1_command = self.register.get_commands( "CAL")[0] + self.register.get_commands( "zeros", length=40)[0] + self.register.get_commands("LV1")[0] self.write_target_charge() additional_scan = True lastBitResult = np.zeros( shape=self.register.get_pixel_register_value("FDAC").shape, dtype=self.register.get_pixel_register_value("FDAC").dtype) self.set_start_fdac() self.tot_mean_best = np.full( shape=(80, 336), fill_value=0 ) # array to store the best occupancy (closest to Ninjections/2) of the pixel self.fdac_mask_best = self.register.get_pixel_register_value("FDAC") fdac_tune_bits = self.fdac_tune_bits[:] for scan_parameter_value, fdac_bit in enumerate(fdac_tune_bits): if additional_scan: self.set_fdac_bit(fdac_bit) logging.info('FDAC setting: bit %d = 1', fdac_bit) else: self.set_fdac_bit(fdac_bit, bit_value=0) logging.info('FDAC setting: bit %d = 0', fdac_bit) self.write_fdac_config() with self.readout(FDAC=scan_parameter_value, reset_sram_fifo=True, fill_buffer=True, clear_buffer=True, callback=self.handle_data): scan_loop(self, command=cal_lvl1_command, repeat_command=self.n_injections_fdac, mask_steps=self.mask_steps, enable_mask_steps=enable_mask_steps, enable_double_columns=None, same_mask_for_all_dc=self.same_mask_for_all_dc, eol_function=None, digital_injection=False, enable_shift_masks=self.enable_shift_masks, disable_shift_masks=self.disable_shift_masks, restore_shift_masks=True, mask=None, double_column_correction=self.pulser_dac_correction) col_row_tot = np.column_stack( convert_data_array( data_array_from_data_iterable(self.fifo_readout.data), filter_func=logical_and(is_fe_word, is_data_record), converter_func=get_col_row_tot_array_from_data_record_array )) tot_array = np.histogramdd(col_row_tot, bins=(80, 336, 16), range=[[1, 80], [1, 336], [0, 15]])[0] tot_mean_array = np.average( tot_array, axis=2, weights=range(0, 16)) * sum(range( 0, 16)) / self.n_injections_fdac select_better_pixel_mask = abs( tot_mean_array - self.target_tot) <= abs(self.tot_mean_best - self.target_tot) pixel_with_too_small_mean_tot_mask = tot_mean_array < self.target_tot self.tot_mean_best[select_better_pixel_mask] = tot_mean_array[ select_better_pixel_mask] if self.plot_intermediate_steps: plot_three_way(hist=tot_mean_array.transpose().transpose(), title="Mean ToT (FDAC tuning bit " + str(fdac_bit) + ")", x_axis_title='mean ToT', filename=self.plots_filename, minimum=0, maximum=15) fdac_mask = self.register.get_pixel_register_value("FDAC") self.fdac_mask_best[select_better_pixel_mask] = fdac_mask[ select_better_pixel_mask] if fdac_bit > 0: fdac_mask[pixel_with_too_small_mean_tot_mask] = fdac_mask[ pixel_with_too_small_mean_tot_mask] & ~(1 << fdac_bit) self.register.set_pixel_register_value("FDAC", fdac_mask) if fdac_bit == 0: if additional_scan: # scan bit = 0 with the correct value again additional_scan = False lastBitResult = tot_mean_array.copy() fdac_tune_bits.append(0) # bit 0 has to be scanned twice else: fdac_mask[abs(tot_mean_array - self.target_tot) > abs( lastBitResult - self.target_tot )] = fdac_mask[abs(tot_mean_array - self.target_tot) > abs( lastBitResult - self.target_tot)] | (1 << fdac_bit) tot_mean_array[abs(tot_mean_array - self.target_tot) > abs( lastBitResult - self.target_tot)] = lastBitResult[ abs(tot_mean_array - self.target_tot) > abs(lastBitResult - self.target_tot)] self.tot_mean_best[ abs(tot_mean_array - self.target_tot) <= abs( self.tot_mean_best - self.n_injections_fdac / 2)] = tot_mean_array[ abs(tot_mean_array - self.target_tot) <= abs( self.tot_mean_best - self.n_injections_fdac / 2)] self.fdac_mask_best[ abs(tot_mean_array - self.target_tot) <= abs( self.tot_mean_best - self.n_injections_fdac / 2)] = fdac_mask[ abs(tot_mean_array - self.target_tot) <= abs( self.tot_mean_best - self.n_injections_fdac / 2)] self.register.set_pixel_register_value( "FDAC", self.fdac_mask_best) # set value for meta scan self.write_fdac_config()
def scan(self): cal_lvl1_command = self.register.get_commands( "CAL")[0] + self.register.get_commands( "zeros", length=40)[0] + self.register.get_commands("LV1")[0] self.write_target_threshold() def bits_set(int_type): int_type = int(int_type) position = 0 bits_set = [] while (int_type): if (int_type & 1): bits_set.append(position) position += 1 int_type = int_type >> 1 return bits_set # calculate selected pixels from the mask and the disabled columns select_mask_array = np.zeros(shape=(80, 336), dtype=np.uint8) if not self.enable_mask_steps_gdac: self.enable_mask_steps_gdac = range(self.mask_steps) for mask_step in self.enable_mask_steps_gdac: select_mask_array += make_pixel_mask(steps=self.mask_steps, shift=mask_step) for column in bits_set( self.register.get_global_register_value("DisableColumnCnfg")): logging.info('Deselect double column %d' % column) select_mask_array[column, :] = 0 gdacs_above_threshold = [] additional_scan_ongoing = False last_good_gdac_bit = self.gdac_tune_bits[0] last_good_gdac_scan_step = 0 gdac_tune_bits_permutation = 0 gdac_values = [] gdac_occupancies = [] gdac_occ_array_sel_pixels = [] gdac_occ_array_desel_pixels = [] gdac_tune_bits = self.gdac_tune_bits[:] min_gdac_with_occupancy = None for gdac_scan_step, gdac_bit in enumerate(gdac_tune_bits): if self.stop_run.is_set(): break # set all higher GDAC bits gdac_tune_bits_permutation_header = map( int, bin(2**last_good_gdac_scan_step - 1 - gdac_tune_bits_permutation)[2:].zfill( last_good_gdac_scan_step))[-last_good_gdac_scan_step:] for gdac_permutation_bit, gdac_permutation_bit_value in enumerate( gdac_tune_bits_permutation_header): self.set_gdac_bit(self.gdac_tune_bits[gdac_permutation_bit], bit_value=gdac_permutation_bit_value, send_command=False) # clear all lower GDAC bits for clear_gdac_bit in self.gdac_tune_bits: if clear_gdac_bit < gdac_bit: self.set_gdac_bit(clear_gdac_bit, bit_value=0, send_command=False) if additional_scan_ongoing: self.set_gdac_bit(gdac_bit, bit_value=0, send_command=True) scan_parameter_value = ( self.register.get_global_register_value("Vthin_AltCoarse") << 8 ) + self.register.get_global_register_value("Vthin_AltFine") logging.info('GDAC setting: %d, set bit %d = 0', scan_parameter_value, gdac_bit) else: # default self.set_gdac_bit(gdac_bit, bit_value=1, send_command=False) scan_parameter_value = ( self.register.get_global_register_value("Vthin_AltCoarse") << 8 ) + self.register.get_global_register_value("Vthin_AltFine") logging.info('GDAC setting: %d, set bit %d = 1', scan_parameter_value, gdac_bit) # check if GDAC values are too low or were already scanned if not additional_scan_ongoing and ( (self.register_utils.get_gdac() in gdac_values) or (self.gdac_lower_limit and self.register_utils.get_gdac() < self.gdac_lower_limit) or (min_gdac_with_occupancy and self.register_utils.get_gdac() <= min_gdac_with_occupancy)): if gdac_tune_bits_permutation + 1 == 2**last_good_gdac_scan_step: # next permutation step gdac_tune_bits_permutation = 0 last_good_gdac_scan_step += 1 else: gdac_tune_bits_permutation += 1 for i in range(len(gdac_tune_bits) - (gdac_scan_step + 1)): gdac_tune_bits.pop() gdac_tune_bits.extend( self.gdac_tune_bits[last_good_gdac_scan_step:] ) # repeat all scan steps from last bit continue # write GDAC self.register_utils.set_gdac(self.register_utils.get_gdac(), send_command=True) # start scan loop with self.readout(GDAC=scan_parameter_value, fill_buffer=True): scan_loop(self, command=cal_lvl1_command, repeat_command=self.n_injections_gdac, mask_steps=self.mask_steps, enable_mask_steps=self.enable_mask_steps_gdac, enable_double_columns=None, same_mask_for_all_dc=self.same_mask_for_all_dc, eol_function=None, digital_injection=False, enable_shift_masks=self.enable_shift_masks, disable_shift_masks=self.disable_shift_masks, restore_shift_masks=True, mask=None, double_column_correction=self.pulser_dac_correction) # calculate arrays from data data = convert_data_array( array=self.read_data(), filter_func=is_data_record, converter_func=get_col_row_array_from_data_record_array) occupancy_array, _, _ = np.histogram2d(*data, bins=(80, 336), range=[[1, 80], [1, 336]]) occ_array_sel_pixels = np.ma.array( occupancy_array, mask=np.logical_not(np.ma.make_mask(select_mask_array)) ) # take only selected pixel into account by using the mask occ_array_desel_pixels = np.ma.array( occupancy_array, mask=np.ma.make_mask(select_mask_array) ) # take only de-selected pixel into account by using the inverted mask median_occupancy = np.ma.median(occ_array_sel_pixels) percentile_noise_occupancy = np.percentile( occ_array_desel_pixels.compressed(), 99.0) occupancy_almost_zero = np.allclose(median_occupancy, 0) no_noise = np.allclose(percentile_noise_occupancy, 0) gdac_values.append(self.register_utils.get_gdac()) gdac_occupancies.append(median_occupancy) gdac_occ_array_sel_pixels.append(occ_array_sel_pixels.copy()) gdac_occ_array_desel_pixels.append(occ_array_desel_pixels.copy()) self.occ_array_sel_pixels_best = occ_array_sel_pixels.copy() self.occ_array_desel_pixels_best = occ_array_desel_pixels.copy() if len(gdac_values) >= 2: for index, scanned_gdac in enumerate(gdac_values[:-1]): if (self.register_utils.get_gdac() < scanned_gdac and median_occupancy <= gdac_occupancies[index] and gdac_occupancies[index] != 0): if min_gdac_with_occupancy is None: min_gdac_with_occupancy = self.register_utils.get_gdac( ) else: min_gdac_with_occupancy = max( min_gdac_with_occupancy, self.register_utils.get_gdac()) if (scanned_gdac < self.register_utils.get_gdac() and gdac_occupancies[index] <= median_occupancy and median_occupancy != 0): if min_gdac_with_occupancy is None: min_gdac_with_occupancy = scanned_gdac else: min_gdac_with_occupancy = max( min_gdac_with_occupancy, scanned_gdac) for gdac_above_threshold in gdacs_above_threshold: if gdac_above_threshold <= min_gdac_with_occupancy: # check for valid values gdacs_above_threshold.remove(gdac_above_threshold) if gdac_scan_step + 1 == len( gdac_tune_bits): # last GDAC scan step if not additional_scan_ongoing and ( (occupancy_almost_zero and no_noise) or not gdacs_above_threshold or (self.gdac_lower_limit and self.register_utils.get_gdac() < self.gdac_lower_limit) or (min_gdac_with_occupancy and self.register_utils.get_gdac() <= min_gdac_with_occupancy) or not no_noise ) and len( self.gdac_tune_bits ) >= last_good_gdac_scan_step + 2: # min. 2 bits for bin search self.set_gdac_bit( gdac_bit, bit_value=0, send_command=False) # clear current tuning bit if gdac_tune_bits_permutation + 1 == 2**last_good_gdac_scan_step: # next permutation step gdac_tune_bits_permutation = 0 last_good_gdac_scan_step += 1 else: gdac_tune_bits_permutation += 1 gdac_tune_bits.extend( self.gdac_tune_bits[last_good_gdac_scan_step:] ) # repeat all scan steps from last bit elif gdac_bit == 0 and not additional_scan_ongoing: # scan bit 0 = 1 additional_scan_ongoing = True last_occ_array_sel_pixels = occ_array_sel_pixels.copy() last_occ_array_desel_pixels = occ_array_desel_pixels.copy() last_median_occupancy = median_occupancy gdac_tune_bits.append( 0) # the last tune bit has to be scanned twice elif gdac_bit == 0 and additional_scan_ongoing: # scan bit 0 = 0 additional_scan_ongoing = False logging.info( 'Measured %.2f with bit 0 = 0 with and %.2f with bit 0 = 1', median_occupancy, last_median_occupancy) if (abs(median_occupancy - self.n_injections_gdac / 2.0) >= abs(last_median_occupancy - self.n_injections_gdac / 2.0) ) or ( last_median_occupancy >= self.n_injections_gdac / 2.0 ): # if bit 0 = 0 is worse than bit 0 = 1, so go back logging.info('Set bit 0 = 1') self.set_gdac_bit( 0, bit_value=1, send_command=True) # write GDAC value occ_array_sel_pixels = last_occ_array_sel_pixels.copy() occ_array_desel_pixels = last_occ_array_desel_pixels.copy( ) median_occupancy = last_median_occupancy else: logging.info('Keep bit 0 = 0') else: # regular GDAC scan step # GDAC too low, no hits if (self.gdac_lower_limit and self.register_utils.get_gdac() < self.gdac_lower_limit ) or (min_gdac_with_occupancy and self.register_utils.get_gdac() <= min_gdac_with_occupancy) or not no_noise: logging.info( 'Median = %.2f > %.2f, GDAC possibly too low, keep bit %d = 1', median_occupancy, self.n_injections_gdac / 2.0, gdac_bit) # GDAC too high, less hits, decrease GDAC elif median_occupancy < self.n_injections_gdac / 2.0: # set GDAC bit to 0 if the occupancy is too low, thus decrease threshold logging.info('Median = %.2f < %.2f, set bit %d = 0', median_occupancy, self.n_injections_gdac / 2.0, gdac_bit) self.set_gdac_bit( gdac_bit, bit_value=0, send_command=False ) # do not write, might be too low, do this in next iteration # GDAC too low, more hits, increase GDAC else: gdacs_above_threshold.append( self.register_utils.get_gdac()) logging.info('Median = %.2f > %.2f, keep bit %d = 1', median_occupancy, self.n_injections_gdac / 2.0, gdac_bit) if not self.stop_run.is_set(): # select best GDAC value sorted_indices = np.argsort(np.array(gdac_values)) occupancy_sorted = np.array(gdac_occupancies)[sorted_indices] gdac_sorted = np.sort(gdac_values) try: diff_occupancy = occupancy_sorted[1:] - occupancy_sorted[:-1] gdac_min_idx = np.where(diff_occupancy > 0)[0][-1] + 1 except IndexError: gdac_min_idx = None occupancy_sorted_sel = occupancy_sorted[gdac_min_idx:] best_index_sel = np.abs( np.array(occupancy_sorted_sel[::-1]) - self.n_injections_gdac / 2.0).argmin() best_index = sorted_indices[gdac_min_idx:][::-1][best_index_sel] gdac_best = gdac_values[best_index] median_occupancy = gdac_occupancies[best_index] # for plotting self.occ_array_sel_pixels_best = gdac_occ_array_sel_pixels[ best_index] self.occ_array_desel_pixels_best = gdac_occ_array_desel_pixels[ best_index] if gdac_best != self.register_utils.get_gdac(): logging.info( "Binary search converged to non-optimal value, apply best GDAC value, change GDAC from %d to %d", self.register_utils.get_gdac(), gdac_best) self.register_utils.set_gdac(gdac_best, send_command=False) self.gdac_best = self.register_utils.get_gdac() if abs(median_occupancy - self.n_injections_gdac / 2.0) > abs( self.n_injections_gdac * 0.01 * self.max_delta_threshold) and not self.stop_run.is_set(): if np.all((((self.gdac_best & (1 << np.arange( self.register.global_registers['Vthin_AltFine'] ['bitlength'] + self.register. global_registers['Vthin_AltFine']['bitlength'])))) > 0 ).astype(int)[self.gdac_tune_bits] == 1): if self.fail_on_warning: raise RuntimeWarning( 'Selected GDAC bits reached maximum value') else: logging.warning( 'Selected GDAC bits reached maximum value') elif np.all((((self.gdac_best & (1 << np.arange( self.register.global_registers['Vthin_AltFine'] ['bitlength'] + self.register. global_registers['Vthin_AltFine']['bitlength'])))) > 0 ).astype(int)[self.gdac_tune_bits] == 0): if self.fail_on_warning: raise RuntimeWarning( 'Selected GDAC bits reached minimum value') else: logging.warning( 'Selected GDAC bits reached minimum value') else: if self.fail_on_warning: raise RuntimeWarning( 'Global threshold tuning failed. Delta threshold = %.2f > %.2f. Vthin_AltCoarse / Vthin_AltFine = %d / %d' % (abs(median_occupancy - self.n_injections_gdac / 2.0), abs(self.n_injections_gdac * 0.01 * self.max_delta_threshold), self.register.get_global_register_value( "Vthin_AltCoarse"), self.register.get_global_register_value( "Vthin_AltFine"))) else: logging.warning( 'Global threshold tuning failed. Delta threshold = %.2f > %.2f. Vthin_AltCoarse / Vthin_AltFine = %d / %d', abs(median_occupancy - self.n_injections_gdac / 2.0), abs(self.n_injections_gdac * 0.01 * self.max_delta_threshold), self.register.get_global_register_value( "Vthin_AltCoarse"), self.register.get_global_register_value( "Vthin_AltFine")) else: logging.info( 'Tuned GDAC to Vthin_AltCoarse / Vthin_AltFine = %d / %d', self.register.get_global_register_value("Vthin_AltCoarse"), self.register.get_global_register_value("Vthin_AltFine"))
def scan(self): if not self.plots_filename: self.plots_filename = PdfPages(self.output_filename + '.pdf') self.close_plots = True else: self.close_plots = False cal_lvl1_command = self.register.get_commands( "CAL")[0] + self.register.get_commands( "zeros", length=40)[0] + self.register.get_commands("LV1")[0] self.write_target_threshold() scan_parameter_range = [ (2**self.register.global_registers['Vthin_AltFine']['bitlength']), 0 ] # high to low if self.scan_parameters.GDAC[0]: scan_parameter_range[0] = self.scan_parameters.GDAC[0] if self.scan_parameters.GDAC[1]: scan_parameter_range[1] = self.scan_parameters.GDAC[1] scan_parameter_range = range(scan_parameter_range[0], scan_parameter_range[1] - 1, self.step_size) logging.info("Scanning %s from %d to %d", 'GDAC', scan_parameter_range[0], scan_parameter_range[-1]) def bits_set(int_type): int_type = int(int_type) position = 0 bits_set = [] while (int_type): if (int_type & 1): bits_set.append(position) position += 1 int_type = int_type >> 1 return bits_set # calculate selected pixels from the mask and the disabled columns select_mask_array = np.zeros(shape=(80, 336), dtype=np.uint8) self.occ_array_sel_pixels_best = select_mask_array.copy() self.occ_array_desel_pixels_best = select_mask_array.copy() if not self.enable_mask_steps_gdac: self.enable_mask_steps_gdac = range(self.mask_steps) for mask_step in self.enable_mask_steps_gdac: select_mask_array += make_pixel_mask(steps=self.mask_steps, shift=mask_step) for column in bits_set( self.register.get_global_register_value("DisableColumnCnfg")): logging.info('Deselect double column %d' % column) select_mask_array[column, :] = 0 occupancy_best = 0.0 median_occupancy_last_step = 0.0 gdac_best = self.register_utils.get_gdac() for gdac_scan_step, scan_parameter_value in enumerate( scan_parameter_range): self.register_utils.set_gdac(scan_parameter_value) with self.readout(GDAC=scan_parameter_value, reset_sram_fifo=True, fill_buffer=True, clear_buffer=True, callback=self.handle_data): scan_loop(self, command=cal_lvl1_command, repeat_command=self.n_injections_gdac, mask_steps=self.mask_steps, enable_mask_steps=self.enable_mask_steps_gdac, enable_double_columns=None, same_mask_for_all_dc=self.same_mask_for_all_dc, eol_function=None, digital_injection=False, enable_shift_masks=self.enable_shift_masks, disable_shift_masks=self.disable_shift_masks, restore_shift_masks=True, mask=None, double_column_correction=self.pulser_dac_correction) occupancy_array, _, _ = np.histogram2d(*convert_data_array( data_array_from_data_iterable(self.fifo_readout.data), filter_func=logical_and(is_fe_word, is_data_record), converter_func=get_col_row_array_from_data_record_array), bins=(80, 336), range=[[1, 80], [1, 336]]) occ_array_sel_pixels = np.ma.array( occupancy_array, mask=np.logical_not(np.ma.make_mask(select_mask_array)) ) # take only selected pixel into account by using the mask occ_array_desel_pixels = np.ma.array( occupancy_array, mask=np.ma.make_mask(select_mask_array) ) # take only de-selected pixel into account by using the inverted mask median_occupancy = np.ma.median(occ_array_sel_pixels) noise_occupancy = np.ma.median(occ_array_desel_pixels) occupancy_almost_zero = np.allclose(median_occupancy, 0) no_noise = np.allclose(noise_occupancy, 0) if no_noise and not occupancy_almost_zero and abs( median_occupancy - self.n_injections_gdac / 2) < abs(occupancy_best - self.n_injections_gdac / 2): occupancy_best = median_occupancy gdac_best = self.register_utils.get_gdac() self.occ_array_sel_pixels_best = occ_array_sel_pixels.copy() self.occ_array_desel_pixels_best = occ_array_desel_pixels.copy( ) if self.plot_intermediate_steps: plot_three_way(self.occ_array_sel_pixel.transpose(), title="Occupancy (GDAC " + str(scan_parameter_value) + ")", x_axis_title='Occupancy', filename=self.plots_filename, maximum=self.n_injections_gdac) if no_noise and not occupancy_almost_zero and median_occupancy >= median_occupancy_last_step and median_occupancy >= self.n_injections_gdac / 2: break if no_noise and not occupancy_almost_zero: median_occupancy_last_step = median_occupancy else: median_occupancy_last_step = 0.0 self.register_utils.set_gdac(gdac_best, send_command=False) median_occupancy = occupancy_best self.gdac_best = self.register_utils.get_gdac() if abs(median_occupancy - self.n_injections_gdac / 2) > self.max_delta_threshold: if np.all((((self.gdac_best & (1 << np.arange( self.register.global_registers['Vthin_AltFine'] ['bitlength'] + self.register.global_registers['Vthin_AltFine'] ['bitlength'])))) > 0).astype(int) == 0): if self.fail_on_warning: raise RuntimeWarning( 'Selected GDAC bits reached minimum value') else: logging.warning('Selected GDAC bits reached minimum value') else: if self.fail_on_warning: raise RuntimeWarning( 'Global threshold tuning failed. Delta threshold = %.2f > %.2f. Vthin_AltCoarse / Vthin_AltFine = %d / %d' % (abs(median_occupancy - self.n_injections_gdac / 2), self.max_delta_threshold, self.register.get_global_register_value( "Vthin_AltCoarse"), self.register.get_global_register_value( "Vthin_AltFine"))) else: logging.warning( 'Global threshold tuning failed. Delta threshold = %.2f > %.2f. Vthin_AltCoarse / Vthin_AltFine = %d / %d', abs(median_occupancy - self.n_injections_gdac / 2), self.max_delta_threshold, self.register.get_global_register_value( "Vthin_AltCoarse"), self.register.get_global_register_value( "Vthin_AltFine")) else: logging.info( 'Tuned GDAC to Vthin_AltCoarse / Vthin_AltFine = %d / %d', self.register.get_global_register_value("Vthin_AltCoarse"), self.register.get_global_register_value("Vthin_AltFine"))
def scan(self): def bits_set(int_type): int_type = int(int_type) position = 0 bits_set = [] while(int_type): if(int_type & 1): bits_set.append(position) position += 1 int_type = int_type >> 1 return bits_set # calculate selected pixels from the mask and the disabled columns select_mask_array = np.zeros(shape=(80, 336), dtype=np.uint8) if not self.enable_mask_steps_feedback: self.enable_mask_steps_feedback = range(self.mask_steps) for mask_step in self.enable_mask_steps_feedback: select_mask_array += make_pixel_mask(steps=self.mask_steps, shift=mask_step) for column in bits_set(self.register.get_global_register_value("DisableColumnCnfg")): logging.info('Deselect double column %d' % column) select_mask_array[column, :] = 0 cal_lvl1_command = self.register.get_commands("CAL")[0] + self.register.get_commands("zeros", length=40)[0] + self.register.get_commands("LV1")[0] self.write_target_charge() for feedback_bit in self.feedback_tune_bits: # reset all feedback bits self.set_prmp_vbpf_bit(feedback_bit, bit_value=0) additional_scan = True tot_mean_best = 0.0 feedback_best = self.register.get_global_register_value("PrmpVbpf") feedback_tune_bits = self.feedback_tune_bits[:] for feedback_bit in feedback_tune_bits: if self.stop_run.is_set(): break if additional_scan: self.set_prmp_vbpf_bit(feedback_bit, bit_value=1) logging.info('PrmpVbpf setting: %d, set bit %d = 1', self.register.get_global_register_value("PrmpVbpf"), feedback_bit) else: self.set_prmp_vbpf_bit(feedback_bit, bit_value=0) logging.info('PrmpVbpf setting: %d, set bit %d = 0', self.register.get_global_register_value("PrmpVbpf"), feedback_bit) scan_parameter_value = self.register.get_global_register_value("PrmpVbpf") with self.readout(PrmpVbpf=scan_parameter_value, fill_buffer=True): scan_loop(self, command=cal_lvl1_command, repeat_command=self.n_injections_feedback, mask_steps=self.mask_steps, enable_mask_steps=self.enable_mask_steps_feedback, enable_double_columns=None, same_mask_for_all_dc=self.same_mask_for_all_dc, eol_function=None, digital_injection=False, enable_shift_masks=self.enable_shift_masks, disable_shift_masks=self.disable_shift_masks, restore_shift_masks=True, mask=None, double_column_correction=self.pulser_dac_correction) data = convert_data_array(array=self.read_data(), filter_func=is_data_record, converter_func=get_col_row_tot_array_from_data_record_array) col_row_tot_array = np.column_stack(data) occupancy_array, _, _ = np.histogram2d(col_row_tot_array[:, 0], col_row_tot_array[:, 1], bins=(80, 336), range=[[1, 80], [1, 336]]) occupancy_array = np.ma.array(occupancy_array, mask=np.logical_not(np.ma.make_mask(select_mask_array))) # take only selected pixel into account by creating a mask occupancy_array = np.ma.masked_where(occupancy_array > self.n_injections_feedback, occupancy_array) col_row_tot_hist = np.histogramdd(col_row_tot_array, bins=(80, 336, 16), range=[[1, 80], [1, 336], [0, 15]])[0] tot_mean_array = np.average(col_row_tot_hist, axis=2, weights=range(0, 16)) * sum(range(0, 16)) / self.n_injections_feedback tot_mean_array = np.ma.array(tot_mean_array, mask=occupancy_array.mask) # keep noisy pixels out mean_tot = np.ma.mean(tot_mean_array) if abs(mean_tot - self.target_tot) < abs(tot_mean_best - self.target_tot): tot_mean_best = mean_tot feedback_best = self.register.get_global_register_value("PrmpVbpf") logging.info('Mean ToT = %.2f', mean_tot) tot_array = col_row_tot_array[:, 2] self.tot_hist, _ = np.histogram(a=tot_array, range=(0, 16), bins=16) if self.plot_intermediate_steps: plot_tot(hist=self.tot_hist, title='ToT distribution (PrmpVbpf ' + str(scan_parameter_value) + ')', filename=self.plots_filename) # if abs(mean_tot - self.target_tot) < self.max_delta_tot and feedback_bit > 0: # abort if good value already found to save time # logging.info('Good result already achieved, skipping missing bits') # break if feedback_bit > 0: # TODO: if feedback is to high, no hits if mean_tot < self.target_tot: self.set_prmp_vbpf_bit(feedback_bit, bit_value=0) logging.info('Mean ToT = %.2f < %.2f ToT, set bit %d = 0', mean_tot, self.target_tot, feedback_bit) else: logging.info('Mean ToT = %.2f > %.2f ToT, keep bit %d = 1', mean_tot, self.target_tot, feedback_bit) elif feedback_bit == 0: if additional_scan: # scan bit = 0 with the correct value again additional_scan = False last_mean_tot = mean_tot last_tot_hist = self.tot_hist.copy() feedback_tune_bits.append(0) # bit 0 has to be scanned twice else: logging.info('Measured %.2f with bit 0 = 0 and %.2f with bit 0 = 1', mean_tot, last_mean_tot) if(abs(mean_tot - self.target_tot) > abs(last_mean_tot - self.target_tot)): # if bit 0 = 0 is worse than bit 0 = 1, so go back logging.info('Set bit 0 = 1') self.set_prmp_vbpf_bit(0, bit_value=1) self.tot_hist = last_tot_hist.copy() mean_tot = last_mean_tot else: logging.info('Keep bit 0 = 0') # select best Feedback value if abs(mean_tot - self.target_tot) > abs(tot_mean_best - self.target_tot): logging.info("Binary search converged to non-optimal value, apply best Feedback value, change PrmpVbpf from %d to %d", self.register.get_global_register_value("PrmpVbpf"), feedback_best) mean_tot = tot_mean_best self.register.set_global_register_value("PrmpVbpf", feedback_best) self.feedback_best = self.register.get_global_register_value("PrmpVbpf") if abs(mean_tot - self.target_tot) > 2 * self.max_delta_tot and not self.stop_run.is_set(): if np.all((((self.feedback_best & (1 << np.arange(self.register.global_registers['PrmpVbpf']['bitlength'])))) > 0).astype(int)[self.feedback_tune_bits] == 1): if self.fail_on_warning: raise RuntimeWarning('Selected Feedback bits reached maximum value') else: logging.warning('Selected Feedback bits reached maximum value') elif np.all((((self.feedback_best & (1 << np.arange(self.register.global_registers['PrmpVbpf']['bitlength'])))) > 0).astype(int)[self.feedback_tune_bits] == 0): if self.fail_on_warning: raise RuntimeWarning('Selected Feedback bits reached minimum value') else: logging.warning('Selected Feedback bits reached minimum value') else: if self.fail_on_warning: raise RuntimeWarning('Global feedback tuning failed. Delta ToT = %.2f > %.2f. PrmpVbpf = %d' % (abs(mean_tot - self.target_tot), self.max_delta_tot, self.register.get_global_register_value("PrmpVbpf"))) else: logging.warning('Global feedback tuning failed. Delta ToT = %.2f > %.2f. PrmpVbpf = %d', abs(mean_tot - self.target_tot), self.max_delta_tot, self.register.get_global_register_value("PrmpVbpf")) else: logging.info('Tuned PrmpVbpf to %d', self.register.get_global_register_value("PrmpVbpf"))
def scan(self): if not self.plots_filename: self.plots_filename = PdfPages(self.output_filename + ".pdf") self.close_plots = True else: self.close_plots = False 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", mask_steps=self.mask_steps_gdac)[0] ) self.write_target_threshold() for gdac_bit in self.gdac_tune_bits: # reset all GDAC bits self.set_gdac_bit(gdac_bit, bit_value=0, send_command=False) last_bit_result = self.n_injections_gdac decreased_threshold = False # needed to determine if the FE is noisy all_bits_zero = True def bits_set(int_type): int_type = int(int_type) position = 0 bits_set = [] while int_type: if int_type & 1: bits_set.append(position) position += 1 int_type = int_type >> 1 return bits_set # calculate selected pixels from the mask and the disabled columns select_mask_array = np.zeros(shape=(80, 336), dtype=np.uint8) if not self.enable_mask_steps_gdac: self.enable_mask_steps_gdac = range(self.mask_steps_gdac) for mask_step in self.enable_mask_steps_gdac: select_mask_array += make_pixel_mask(steps=self.mask_steps_gdac, shift=mask_step) for column in bits_set(self.register.get_global_register_value("DisableColumnCnfg")): logging.info("Deselect double column %d" % column) select_mask_array[column, :] = 0 additional_scan = True occupancy_best = 0 gdac_best = self.register_utils.get_gdac() for gdac_bit in self.gdac_tune_bits: if additional_scan: self.set_gdac_bit(gdac_bit) scan_parameter_value = ( self.register.get_global_register_value("Vthin_AltCoarse") << 8 ) + self.register.get_global_register_value("Vthin_AltFine") logging.info("GDAC setting: %d, bit %d = 1", scan_parameter_value, gdac_bit) else: self.set_gdac_bit(gdac_bit, bit_value=0) scan_parameter_value = ( self.register.get_global_register_value("Vthin_AltCoarse") << 8 ) + self.register.get_global_register_value("Vthin_AltFine") logging.info("GDAC setting: %d, bit %d = 0", scan_parameter_value, gdac_bit) with self.readout( GDAC=scan_parameter_value, reset_sram_fifo=True, fill_buffer=True, clear_buffer=True, callback=self.handle_data, ): scan_loop( self, cal_lvl1_command, repeat_command=self.n_injections_gdac, mask_steps=self.mask_steps_gdac, enable_mask_steps=self.enable_mask_steps_gdac, enable_double_columns=None, same_mask_for_all_dc=True, eol_function=None, digital_injection=False, enable_shift_masks=self.enable_shift_masks, disable_shift_masks=self.disable_shift_masks, restore_shift_masks=True, mask=None, double_column_correction=self.pulser_dac_correction, ) occupancy_array, _, _ = np.histogram2d( *convert_data_array( data_array_from_data_iterable(self.fifo_readout.data), filter_func=is_data_record, converter_func=get_col_row_array_from_data_record_array, ), bins=(80, 336), range=[[1, 80], [1, 336]] ) self.occ_array_sel_pixel = np.ma.array( occupancy_array, mask=np.logical_not(np.ma.make_mask(select_mask_array)) ) # take only selected pixel into account by creating a mask median_occupancy = np.ma.median(self.occ_array_sel_pixel) if abs(median_occupancy - self.n_injections_gdac / 2) < abs(occupancy_best - self.n_injections_gdac / 2): occupancy_best = median_occupancy gdac_best = self.register_utils.get_gdac() if self.plot_intermediate_steps: plot_three_way( self.occ_array_sel_pixel.transpose(), title="Occupancy (GDAC " + str(scan_parameter_value) + " with tuning bit " + str(gdac_bit) + ")", x_axis_title="Occupancy", filename=self.plots_filename, maximum=self.n_injections_gdac, ) if ( abs(median_occupancy - self.n_injections_gdac / 2) < self.max_delta_threshold and gdac_bit > 0 ): # abort if good value already found to save time logging.info( "Median = %f, good result already achieved (median - Ninj/2 < %f), skipping not varied bits", median_occupancy, self.max_delta_threshold, ) break if median_occupancy == 0 and decreased_threshold and all_bits_zero: logging.info("Chip may be noisy") if gdac_bit > 0: if ( median_occupancy < self.n_injections_gdac / 2 ): # set GDAC bit to 0 if the occupancy is too lowm, thus decrease threshold logging.info( "Median = %f < %f, set bit %d = 0", median_occupancy, self.n_injections_gdac / 2, gdac_bit ) self.set_gdac_bit(gdac_bit, bit_value=0) decreased_threshold = True else: # set GDAC bit to 1 if the occupancy is too high, thus increase threshold logging.info( "Median = %f > %f, leave bit %d = 1", median_occupancy, self.n_injections_gdac / 2, gdac_bit ) decreased_threshold = False all_bits_zero = False elif gdac_bit == 0: if additional_scan: # scan bit = 0 with the correct value again additional_scan = False last_bit_result = self.occ_array_sel_pixel.copy() self.gdac_tune_bits.append(self.gdac_tune_bits[-1]) # the last tune bit has to be scanned twice else: last_bit_result_median = np.median(last_bit_result[select_mask_array > 0]) logging.info("Scanned bit 0 = 0 with %f instead of %f", median_occupancy, last_bit_result_median) if abs(median_occupancy - self.n_injections_gdac / 2) > abs( last_bit_result_median - self.n_injections_gdac / 2 ): # if bit 0 = 0 is worse than bit 0 = 1, so go back self.set_gdac_bit(gdac_bit, bit_value=1) logging.info("Set bit 0 = 1") self.occ_array_sel_pixel = last_bit_result median_occupancy = np.ma.median(self.occ_array_sel_pixel) else: logging.info("Set bit 0 = 0") if abs(occupancy_best - self.n_injections_gdac / 2) < abs( median_occupancy - self.n_injections_gdac / 2 ): logging.info("Binary search converged to non optimal value, take best measured value instead") median_occupancy = occupancy_best self.register_utils.set_gdac(gdac_best, send_command=False) self.gdac_best = self.register_utils.get_gdac() if np.all((((self.gdac_best & (1 << np.arange(16)))) > 0).astype(int)[self.gdac_tune_bits[:-2]] == 1): logging.warning("Selected GDAC bits reached maximum value") elif np.all((((self.gdac_best & (1 << np.arange(16)))) > 0).astype(int)[self.gdac_tune_bits] == 0): logging.warning("Selected GDAC bits reached minimum value") if abs(median_occupancy - self.n_injections_gdac / 2) > 2 * self.max_delta_threshold: logging.warning( "Global threshold tuning failed. Delta threshold = %f > %f. Vthin_AltCoarse / Vthin_AltFine = %d / %d", abs(median_occupancy - self.n_injections_gdac / 2), self.max_delta_threshold, self.register.get_global_register_value("Vthin_AltCoarse"), self.register.get_global_register_value("Vthin_AltFine"), ) else: logging.info( "Tuned GDAC to Vthin_AltCoarse / Vthin_AltFine = %d / %d", self.register.get_global_register_value("Vthin_AltCoarse"), self.register.get_global_register_value("Vthin_AltFine"), ) self.gdac_best = self.register_utils.get_gdac()
def scan(self): if not self.plots_filename: self.plots_filename = PdfPages(self.output_filename + '.pdf') self.close_plots = True else: self.close_plots = False mask_steps = 3 enable_mask_steps = [ 0 ] # one mask step to increase speed, no effect on precision 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", mask_steps=mask_steps)[0] self.write_target_charge() for feedback_bit in self.feedback_tune_bits: # reset all GDAC bits self.set_prmp_vbpf_bit(feedback_bit, bit_value=0) additional_scan = True last_bit_result = self.n_injections_feedback tot_mean_best = 0 feedback_best = self.register.get_global_register_value("PrmpVbpf") for feedback_bit in self.feedback_tune_bits: if additional_scan: self.set_prmp_vbpf_bit(feedback_bit) logging.info( 'PrmpVbpf setting: %d, bit %d = 1' % (self.register.get_global_register_value("PrmpVbpf"), feedback_bit)) else: self.set_prmp_vbpf_bit(feedback_bit, bit_value=0) logging.info( 'PrmpVbpf setting: %d, bit %d = 0' % (self.register.get_global_register_value("PrmpVbpf"), feedback_bit)) scan_parameter_value = self.register.get_global_register_value( "PrmpVbpf") with self.readout(PrmpVbpf=scan_parameter_value): scan_loop(self, cal_lvl1_command, repeat_command=self.n_injections_feedback, mask_steps=mask_steps, enable_mask_steps=enable_mask_steps, enable_double_columns=None, same_mask_for_all_dc=True, eol_function=None, digital_injection=False, enable_shift_masks=self.enable_shift_masks, disable_shift_masks=self.disable_shift_masks, restore_shift_masks=True, mask=None, double_column_correction=self.pulser_dac_correction) self.raw_data_file.append( self.fifo_readout.data, scan_parameters=self.scan_parameters._asdict()) tots = convert_data_array( data_array_from_data_iterable(self.fifo_readout.data), filter_func=is_data_record, converter_func=get_tot_array_from_data_record_array) mean_tot = np.mean(tots) if np.isnan(mean_tot): logging.error( "No hits, ToT calculation not possible, tuning will fail") if abs(mean_tot - self.target_tot) < abs(tot_mean_best - self.target_tot): tot_mean_best = mean_tot feedback_best = self.register.get_global_register_value( "PrmpVbpf") logging.info('Mean ToT = %f' % mean_tot) self.tot_array, _ = np.histogram(a=tots, range=(0, 16), bins=16) if self.plot_intermediate_steps: plot_tot(hist=self.tot_array, title='ToT distribution (PrmpVbpf ' + str(scan_parameter_value) + ')', filename=self.plots_filename) if abs( mean_tot - self.target_tot ) < self.max_delta_tot and feedback_bit > 0: # abort if good value already found to save time logging.info( 'Good result already achieved, skipping missing bits') break if feedback_bit > 0 and mean_tot < self.target_tot: self.set_prmp_vbpf_bit(feedback_bit, bit_value=0) logging.info('Mean ToT = %f < %d ToT, set bit %d = 0' % (mean_tot, self.target_tot, feedback_bit)) if feedback_bit == 0: if additional_scan: # scan bit = 0 with the correct value again additional_scan = False last_bit_result = mean_tot self.feedback_tune_bits.append( 0) # bit 0 has to be scanned twice else: logging.info( 'Scanned bit 0 = 0 with %f instead of %f for scanned bit 0 = 1' % (mean_tot, last_bit_result)) if (abs(mean_tot - self.target_tot) > abs(last_bit_result - self.target_tot) ): # if bit 0 = 0 is worse than bit 0 = 1, so go back self.set_prmp_vbpf_bit(feedback_bit, bit_value=1) mean_tot = last_bit_result logging.info('Set bit 0 = 1') else: logging.info('Set bit 0 = 0') if abs(mean_tot - self.target_tot) > abs(tot_mean_best - self.target_tot): logging.info( "Binary search converged to non optimal value, take best measured value instead" ) mean_tot = tot_mean_best self.register.set_global_register_value( "PrmpVbpf", feedback_best) if self.register.get_global_register_value( "PrmpVbpf") == 0 or self.register.get_global_register_value( "PrmpVbpf") == 254: logging.warning('PrmpVbpf reached minimum/maximum value') if abs(mean_tot - self.target_tot) > 2 * self.max_delta_tot: logging.warning( 'Global feedback tuning failed. Delta ToT = %f > %f. PrmpVbpf = %d' % (abs(mean_tot - self.target_tot), self.max_delta_tot, self.register.get_global_register_value("PrmpVbpf"))) else: logging.info('Tuned PrmpVbpf to %d' % self.register.get_global_register_value("PrmpVbpf")) self.feedback_best = self.register.get_global_register_value( "PrmpVbpf")
def scan(self): if not self.plots_filename: self.plots_filename = PdfPages(self.output_filename + '.pdf') self.close_plots = True else: self.close_plots = False cal_lvl1_command = self.register.get_commands( "CAL")[0] + self.register.get_commands( "zeros", length=40)[0] + self.register.get_commands("LV1")[0] self.write_target_threshold() for gdac_bit in self.gdac_tune_bits: # reset all GDAC bits self.set_gdac_bit(gdac_bit, bit_value=0, send_command=False) def bits_set(int_type): int_type = int(int_type) position = 0 bits_set = [] while (int_type): if (int_type & 1): bits_set.append(position) position += 1 int_type = int_type >> 1 return bits_set # calculate selected pixels from the mask and the disabled columns select_mask_array = np.zeros(shape=(80, 336), dtype=np.uint8) self.occ_array_sel_pixels_best = select_mask_array.copy() self.occ_array_desel_pixels_best = select_mask_array.copy() if not self.enable_mask_steps_gdac: self.enable_mask_steps_gdac = range(self.mask_steps) for mask_step in self.enable_mask_steps_gdac: select_mask_array += make_pixel_mask(steps=self.mask_steps, shift=mask_step) for column in bits_set( self.register.get_global_register_value("DisableColumnCnfg")): logging.info('Deselect double column %d' % column) select_mask_array[column, :] = 0 additional_scan = True additional_scan_ongoing = False occupancy_best = 0.0 last_good_gdac_bit = self.gdac_tune_bits[0] last_good_gdac_scan_step = 0 gdac_tune_bits_permutation = 0 gdac_best = self.register_utils.get_gdac() gdac_tune_bits = self.gdac_tune_bits[:] min_gdac_with_occupancy = None for gdac_scan_step, gdac_bit in enumerate(gdac_tune_bits): if additional_scan: self.set_gdac_bit(gdac_bit, bit_value=1, send_command=True) scan_parameter_value = ( self.register.get_global_register_value("Vthin_AltCoarse") << 8 ) + self.register.get_global_register_value("Vthin_AltFine") logging.info('GDAC setting: %d, set bit %d = 1', scan_parameter_value, gdac_bit) else: self.set_gdac_bit(gdac_bit, bit_value=0, send_command=True) scan_parameter_value = ( self.register.get_global_register_value("Vthin_AltCoarse") << 8 ) + self.register.get_global_register_value("Vthin_AltFine") logging.info('GDAC setting: %d, set bit %d = 0', scan_parameter_value, gdac_bit) with self.readout(GDAC=scan_parameter_value, reset_sram_fifo=True, fill_buffer=True, clear_buffer=True, callback=self.handle_data): scan_loop(self, command=cal_lvl1_command, repeat_command=self.n_injections_gdac, mask_steps=self.mask_steps, enable_mask_steps=self.enable_mask_steps_gdac, enable_double_columns=None, same_mask_for_all_dc=self.same_mask_for_all_dc, eol_function=None, digital_injection=False, enable_shift_masks=self.enable_shift_masks, disable_shift_masks=self.disable_shift_masks, restore_shift_masks=True, mask=None, double_column_correction=self.pulser_dac_correction) occupancy_array, _, _ = np.histogram2d(*convert_data_array( data_array_from_data_iterable(self.fifo_readout.data), filter_func=logical_and(is_fe_word, is_data_record), converter_func=get_col_row_array_from_data_record_array), bins=(80, 336), range=[[1, 80], [1, 336]]) occ_array_sel_pixels = np.ma.array( occupancy_array, mask=np.logical_not(np.ma.make_mask(select_mask_array)) ) # take only selected pixel into account by using the mask occ_array_desel_pixels = np.ma.array( occupancy_array, mask=np.ma.make_mask(select_mask_array) ) # take only de-selected pixel into account by using the inverted mask median_occupancy = np.ma.median(occ_array_sel_pixels) noise_occupancy = np.ma.median(occ_array_desel_pixels) occupancy_almost_zero = np.allclose(median_occupancy, 0) no_noise = np.allclose(noise_occupancy, 0) if abs(median_occupancy - self.n_injections_gdac / 2) < abs(occupancy_best - self.n_injections_gdac / 2): occupancy_best = median_occupancy gdac_best = self.register_utils.get_gdac() self.occ_array_sel_pixels_best = occ_array_sel_pixels.copy() self.occ_array_desel_pixels_best = occ_array_desel_pixels.copy( ) if self.plot_intermediate_steps: plot_three_way(self.occ_array_sel_pixel.transpose(), title="Occupancy (GDAC " + str(scan_parameter_value) + " with tuning bit " + str(gdac_bit) + ")", x_axis_title='Occupancy', filename=self.plots_filename, maximum=self.n_injections_gdac) if not occupancy_almost_zero and no_noise: if min_gdac_with_occupancy is None: min_gdac_with_occupancy = self.register_utils.get_gdac() else: min_gdac_with_occupancy = min( min_gdac_with_occupancy, self.register_utils.get_gdac()) if gdac_bit > 0: # GDAC too low, no hits if occupancy_almost_zero and no_noise and self.register_utils.get_gdac( ) < min_gdac_with_occupancy: logging.info( 'Median = %.2f > %.2f, GDAC possibly too low, keep bit %d = 1', median_occupancy, self.n_injections_gdac / 2, gdac_bit) # GDAC too high, less hits, decrease GDAC elif no_noise and median_occupancy < ( self.n_injections_gdac / 2 ): # set GDAC bit to 0 if the occupancy is too low, thus decrease threshold try: next_gdac_bit = gdac_tune_bits[gdac_scan_step + 1] except IndexError: next_gdac_bit = None # check if new value is below lower limit if self.gdac_lower_limit and ( next_gdac_bit is not None and self.register_utils.get_gdac() - 2**gdac_bit + 2**next_gdac_bit < self.gdac_lower_limit) or ( next_gdac_bit is None and self.register_utils.get_gdac() - 2**gdac_bit < self.gdac_lower_limit): logging.info( 'Median = %.2f < %.2f, reaching lower GDAC limit, keep bit %d = 1', median_occupancy, self.n_injections_gdac / 2, gdac_bit) else: logging.info('Median = %.2f < %.2f, set bit %d = 0', median_occupancy, self.n_injections_gdac / 2, gdac_bit) self.set_gdac_bit( gdac_bit, bit_value=0, send_command=False ) # do not write, might be too low, do this in next iteration # GDAC too low, more hits else: logging.info('Median = %.2f > %.2f, keep bit %d = 1', median_occupancy, self.n_injections_gdac / 2, gdac_bit) elif gdac_bit == 0: if not additional_scan_ongoing and ( (occupancy_almost_zero and no_noise) or not no_noise ) and len(self.gdac_tune_bits) > last_good_gdac_scan_step + 2: self.set_gdac_bit(0, bit_value=0, send_command=False) # turn off LSB if len( gdac_tune_bits ) == gdac_scan_step + 1 and gdac_tune_bits_permutation == 0: # min. 2 bits for bin search self.set_gdac_bit( last_good_gdac_bit, bit_value=1, send_command=False) # always enable highest bit gdac_tune_bits.extend( self.gdac_tune_bits[last_good_gdac_scan_step + 1:] ) # repeat all scan stept from last bit for gdac_clear_bit in self.gdac_tune_bits[: last_good_gdac_scan_step]: self.set_gdac_bit(gdac_clear_bit, bit_value=0, send_command=False) if 2**last_good_gdac_scan_step == 1: # last step, cleanup last_good_gdac_bit = self.gdac_tune_bits[ last_good_gdac_scan_step + 1] last_good_gdac_scan_step += 1 else: gdac_tune_bits_permutation += 1 else: gdac_tune_bits_permutation_header = map( int, bin(gdac_tune_bits_permutation)[2:].zfill( last_good_gdac_scan_step)) for gdac_permutation_bit, gdac_permutation_bit_value in enumerate( gdac_tune_bits_permutation_header): self.set_gdac_bit( self.gdac_tune_bits[gdac_permutation_bit], bit_value=gdac_permutation_bit_value, send_command=False) gdac_tune_bits.extend( self.gdac_tune_bits[last_good_gdac_scan_step + 1:]) if 2**last_good_gdac_scan_step > gdac_tune_bits_permutation + 1: gdac_tune_bits_permutation += 1 else: # last step, cleanup gdac_tune_bits_permutation = 0 last_good_gdac_bit = self.gdac_tune_bits[ last_good_gdac_scan_step + 1] last_good_gdac_scan_step += 1 elif additional_scan: # scan bit = 0 with the correct value again additional_scan = False additional_scan_ongoing = True last_occ_array_sel_pixels = occ_array_sel_pixels.copy() last_occ_array_desel_pixels = occ_array_desel_pixels.copy() gdac_tune_bits.append( 0) # the last tune bit has to be scanned twice else: additional_scan_ongoing = False last_median_occupancy = np.ma.median( last_occ_array_sel_pixels) logging.info( 'Measured %.2f with bit 0 = 0 with and %.2f with bit 0 = 1', median_occupancy, last_median_occupancy) if abs(median_occupancy - self.n_injections_gdac / 2) > abs( last_median_occupancy - self.n_injections_gdac / 2 ): # if bit 0 = 0 is worse than bit 0 = 1, so go back logging.info('Set bit 0 = 1') self.set_gdac_bit(0, bit_value=1, send_command=True) occ_array_sel_pixels = last_occ_array_sel_pixels.copy() occ_array_desel_pixels = last_occ_array_desel_pixels.copy( ) median_occupancy = last_median_occupancy else: logging.info('Keep bit 0 = 0') # select best GDAC value if abs(occupancy_best - self.n_injections_gdac / 2) < abs(median_occupancy - self.n_injections_gdac / 2): logging.info( "Binary search converged to non-optimal value, apply best GDAC value, change GDAC from %d to %d", self.register_utils.get_gdac(), gdac_best) median_occupancy = occupancy_best self.register_utils.set_gdac(gdac_best, send_command=False) self.gdac_best = self.register_utils.get_gdac() if abs(median_occupancy - self.n_injections_gdac / 2) > self.max_delta_threshold: if np.all((((self.gdac_best & (1 << np.arange( self.register.global_registers['Vthin_AltFine'] ['bitlength'] + self.register.global_registers['Vthin_AltFine'] ['bitlength'])))) > 0).astype(int)[self.gdac_tune_bits] == 1): if self.fail_on_warning: raise RuntimeWarning( 'Selected GDAC bits reached maximum value') else: logging.warning('Selected GDAC bits reached maximum value') elif np.all((((self.gdac_best & (1 << np.arange( self.register.global_registers['Vthin_AltFine'] ['bitlength'] + self.register.global_registers['Vthin_AltFine'] ['bitlength'])))) > 0).astype(int)[self.gdac_tune_bits] == 0): if self.fail_on_warning: raise RuntimeWarning( 'Selected GDAC bits reached minimum value') else: logging.warning('Selected GDAC bits reached minimum value') else: if self.fail_on_warning: raise RuntimeWarning( 'Global threshold tuning failed. Delta threshold = %.2f > %.2f. Vthin_AltCoarse / Vthin_AltFine = %d / %d' % (abs(median_occupancy - self.n_injections_gdac / 2), self.max_delta_threshold, self.register.get_global_register_value( "Vthin_AltCoarse"), self.register.get_global_register_value( "Vthin_AltFine"))) else: logging.warning( 'Global threshold tuning failed. Delta threshold = %.2f > %.2f. Vthin_AltCoarse / Vthin_AltFine = %d / %d', abs(median_occupancy - self.n_injections_gdac / 2), self.max_delta_threshold, self.register.get_global_register_value( "Vthin_AltCoarse"), self.register.get_global_register_value( "Vthin_AltFine")) else: logging.info( 'Tuned GDAC to Vthin_AltCoarse / Vthin_AltFine = %d / %d', self.register.get_global_register_value("Vthin_AltCoarse"), self.register.get_global_register_value("Vthin_AltFine"))
def scan(self): self.start_condition_triggered = False # set to true if the start condition is true once self.stop_condition_triggered = False # set to true if the stop condition is true once self.start_at = 0.01 # if more than start_at*activated_pixel see at least one hit the precise scanning is started self.stop_at = 0.95 # if more than stop_at*activated_pixel see the maximum numbers of injection, the scan is stopped self.record_data = False # set to true to activate data storage, so far not everything is recorded to ease data analysis scan_parameter_range = [ 0, (2**self.register.global_registers['PlsrDAC']['bitlength']) ] if self.scan_parameters.PlsrDAC[0]: scan_parameter_range[0] = self.scan_parameters.PlsrDAC[0] if self.scan_parameters.PlsrDAC[1]: scan_parameter_range[1] = self.scan_parameters.PlsrDAC[1] logging.info( "Scanning %s from %d to %d" % ('PlsrDAC', scan_parameter_range[0], scan_parameter_range[1])) self.scan_parameter_value = scan_parameter_range[ 0] # set to start value self.search_distance = self.search_distance self.data_points = 0 # counter variable to count the data points already recorded, have to be at least minimum_data_ponts # calculate DCs to scan from the columns to ignore enable_double_columns = range(0, 40) if 1 in self.ignore_columns: enable_double_columns.remove(0) if set((78, 79, 80)).issubset(self.ignore_columns): enable_double_columns.remove(39) for double_column in range(1, 39): if set((double_column * 2, (double_column * 2) + 1)).issubset(self.ignore_columns): enable_double_columns.remove(double_column) logging.info("Use DCs: %s" % str(enable_double_columns)) self.select_arr_columns = range(0, 80) for column in self.ignore_columns: self.select_arr_columns.remove(column - 1) while self.scan_parameter_value <= scan_parameter_range[ 1]: # scan as long as scan parameter is smaller than defined maximum if self.stop_run.is_set(): break if self.record_data: logging.info( "Scan step %d (%s %d)" % (self.data_points, 'PlsrDAC', self.scan_parameter_value)) commands = [] commands.extend(self.register.get_commands("ConfMode")) self.register.set_global_register_value('PlsrDAC', self.scan_parameter_value) commands.extend( self.register.get_commands("WrRegister", name=['PlsrDAC'])) self.register_utils.send_commands(commands) with self.readout(PlsrDAC=self.scan_parameter_value): cal_lvl1_command = self.register.get_commands( "CAL")[0] + self.register.get_commands( "zeros", length=40)[0] + self.register.get_commands("LV1")[0] scan_loop(self, cal_lvl1_command, repeat_command=self.n_injections, use_delay=True, mask_steps=self.mask_steps, enable_mask_steps=self.enable_mask_steps, enable_double_columns=enable_double_columns, same_mask_for_all_dc=True, eol_function=None, digital_injection=False, enable_shift_masks=self.enable_shift_masks, disable_shift_masks=self.disable_shift_masks, restore_shift_masks=False, mask=invert_pixel_mask( self.register.get_pixel_register_value('Enable')) if self.use_enable_mask else None, double_column_correction=self.pulser_dac_correction) if not self.start_condition_triggered or self.data_points > self.minimum_data_points: # speed up, only create histograms when needed. Python is much too slow here. if not self.start_condition_triggered and not self.record_data: logging.info('Testing for start condition: %s %d' % ('PlsrDAC', self.scan_parameter_value)) if not self.stop_condition_triggered and self.record_data: logging.info('Testing for stop condition: %s %d' % ('PlsrDAC', self.scan_parameter_value)) col, row = convert_data_array( data_array_from_data_iterable(self.fifo_readout.data), filter_func=is_data_record, converter_func=get_col_row_array_from_data_record_array) # using self written histogrammer in C++ occupancy_array = hist_2d_index(col - 1, row - 1, shape=(80, 336)) # using numpy # occupancy_array = np.histogram2d(col, row, bins=(80, 336), range=[[1, 80], [1, 336]])[0] self.scan_condition(occupancy_array) # start condition is met for the first time if self.start_condition_triggered and not self.record_data: self.scan_parameter_value = self.scan_parameter_value - self.search_distance + self.step_size if self.scan_parameter_value < 0: self.scan_parameter_value = 0 logging.info('Starting threshold scan at %s %d' % ('PlsrDAC', self.scan_parameter_value)) self.scan_parameter_start = self.scan_parameter_value self.record_data = True continue # saving data if self.record_data: self.data_points = self.data_points + 1 self.raw_data_file.append( self.fifo_readout.data, scan_parameters=self.scan_parameters._asdict()) # stop condition is met for the first time if self.stop_condition_triggered and self.record_data: logging.info('Stopping threshold scan at %s %d' % ('PlsrDAC', self.scan_parameter_value)) break # increase scan parameter value if not self.start_condition_triggered: self.scan_parameter_value = self.scan_parameter_value + self.search_distance else: self.scan_parameter_value = self.scan_parameter_value + self.step_size if self.scan_parameter_value >= scan_parameter_range[1]: logging.warning( "Reached maximum of PlsrDAC range... stopping scan")
def scan(self): enable_mask_steps = [] cal_lvl1_command = self.register.get_commands( "CAL")[0] + self.register.get_commands( "zeros", length=40)[0] + self.register.get_commands("LV1")[0] self.write_target_charge() additional_scan = True last_tot_mean_array = np.zeros( shape=self.register.get_pixel_register_value("FDAC").shape, dtype=self.register.get_pixel_register_value("FDAC").dtype) self.set_start_fdac() self.tot_mean_best = np.full( shape=(80, 336), fill_value=0 ) # array to store the best occupancy (closest to Ninjections/2) of the pixel self.fdac_mask_best = self.register.get_pixel_register_value("FDAC") fdac_tune_bits = self.fdac_tune_bits[:] for scan_parameter_value, fdac_bit in enumerate(fdac_tune_bits): if self.stop_run.is_set(): break if additional_scan: self.set_fdac_bit(fdac_bit, bit_value=1) logging.info('FDAC setting: bit %d = 1', fdac_bit) else: self.set_fdac_bit(fdac_bit, bit_value=0) logging.info('FDAC setting: bit %d = 0', fdac_bit) self.write_fdac_config() with self.readout(FDAC=scan_parameter_value, fill_buffer=True): scan_loop(self, command=cal_lvl1_command, repeat_command=self.n_injections_fdac, mask_steps=self.mask_steps, enable_mask_steps=enable_mask_steps, enable_double_columns=None, same_mask_for_all_dc=self.same_mask_for_all_dc, eol_function=None, digital_injection=False, enable_shift_masks=self.enable_shift_masks, disable_shift_masks=self.disable_shift_masks, restore_shift_masks=True, mask=None, double_column_correction=self.pulser_dac_correction) data = convert_data_array( array=self.read_data(), filter_func=is_data_record, converter_func=get_col_row_tot_array_from_data_record_array) col_row_tot = np.column_stack(data) tot_array = np.histogramdd(col_row_tot, bins=(80, 336, 16), range=[[1, 80], [1, 336], [0, 15]])[0] tot_mean_array = np.average( tot_array, axis=2, weights=range(0, 16)) * sum(range( 0, 16)) / self.n_injections_fdac select_better_pixel_mask = abs( tot_mean_array - self.target_tot) <= abs(self.tot_mean_best - self.target_tot) self.tot_mean_best[select_better_pixel_mask] = tot_mean_array[ select_better_pixel_mask] fdac_mask = self.register.get_pixel_register_value("FDAC") self.fdac_mask_best[select_better_pixel_mask] = fdac_mask[ select_better_pixel_mask] if fdac_bit > 0: pixel_with_too_small_mean_tot_mask = tot_mean_array < self.target_tot fdac_mask[pixel_with_too_small_mean_tot_mask] = fdac_mask[ pixel_with_too_small_mean_tot_mask] & ~( 1 << fdac_bit) # unset FDAC bit, increase ToT self.register.set_pixel_register_value("FDAC", fdac_mask) elif fdac_bit == 0: if additional_scan: # scan bit = 0 with the correct value again additional_scan = False fdac_tune_bits.append(0) # bit 0 has to be scanned twice else: pass if not self.stop_run.is_set(): self.register.set_pixel_register_value( "FDAC", self.fdac_mask_best) # set value for meta scan self.write_fdac_config()