def analyse(): global global_vars if threshold_vars["integration_time"] < 0.05: threshold_vars["integration_time"] = 0.05 rep = Replay() for i, ro in enumerate(tqdm(rep.get_data(r"/home/rasmus/Documents/Rasmus/110_mimosa_telescope_testbeam_14122016_fei4_self_trigger_scan.h5", real_time=True))): raw_data = ro[0] data_record = ru.convert_data_array(raw_data, filter_func=is_record) # if np.any(is_trigger_word(data_record)): # raise #dr = is_data_record(raw_data) global_vars["timestamp_start"].append(ro[1]) timestamp_stop = ro[2] global_vars["hits"].append(len(data_record)) # print "{0:b}".format(ro[0][0]), FEI4Record(ro[0][0], chip_flavor="fei4b"), is_data_record(ro[0][0]) if np.any(data_record): col, row = get_col_row_array_from_data_record_array(data_record) global_vars["coloumn"].append(np.median(col)) global_vars["row"].append(np.median(row)) if not np.any(global_vars["hist_occ"]): global_vars["hist_occ"] = fast_analysis_utils.hist_2d_index(col, row, shape=(81, 337)) # global_vars["hist_occ"] = fast_analysis_utils.hist_2d_index(np.mean(col), np.mean(row), shape=(81, 337)) else: global_vars["hist_occ"] += fast_analysis_utils.hist_2d_index(col, row, shape=(81, 337)) # global_vars["hist_occ"] += fast_analysis_utils.hist_2d_index(np.mean(col), np.mean(row), shape=(81, 337)) if len(global_vars["time"]) == 0: global_vars["time"].append(0) if timestamp_stop - global_vars["timestamp_start"][0] > threshold_vars["integration_time"]: global_vars["time"].append(global_vars["time"][-1] + timestamp_stop - global_vars["timestamp_start"][0]) global_vars["c"].append(np.var(global_vars["coloumn"])) global_vars["r"].append(np.var(global_vars["row"])) global_vars["hitrate"].append(np.sum(global_vars["hits"]) / (timestamp_stop - global_vars["timestamp_start"][0])) if global_vars["analyse"]: global_vars["beam"] = analyse_beam(global_vars["beam"]) p_hist = pickle.dumps(global_vars["hist_occ"], -1) zlib_hist = zlib.compress(p_hist) socket2.send(zlib_hist) # # free memory of global variables del global_vars["hits"][:] del global_vars["timestamp_start"][:] global_vars["hist_occ"] = None if len(global_vars["coloumn"])>threshold_vars["reset_coloumn_row_arrays"]: del global_vars["coloumn"][:] del global_vars["row"][:]
def draw_hit_map_from_raw_data(raw_data_file, front_ends): with PdfPages(os.path.splitext(raw_data_file)[0] + '.pdf') as output_pdf: with tb.open_file(raw_data_file, 'r') as in_file_h5: raw_data = in_file_h5.root.raw_data[:] for front_end in range(front_ends): print 'Create occupancy hist of front end %d' % front_end occupancy_array, _, _ = np.histogram2d(*readout_utils.convert_data_array(raw_data, filter_func=readout_utils.logical_and(readout_utils.is_data_record, readout_utils.is_data_from_channel(4 - front_end)), converter_func=readout_utils.get_col_row_array_from_data_record_array), bins=(80, 336), range=[[1, 80], [1, 336]]) plotting.plot_three_way(hist=occupancy_array.T, title="Occupancy of chip %d" % front_end, x_axis_title="Occupancy", filename=output_pdf)
def draw_hit_map_from_raw_data(raw_data_file, front_ends): with PdfPages(raw_data_file[:-3] + '.pdf') as output_pdf: with tb.open_file(raw_data_file, 'r') as in_file_h5: raw_data = in_file_h5.root.raw_data[:] for front_end in range(front_ends): print 'Create occupancy hist of front end %d' % front_end occupancy_array, _, _ = np.histogram2d(*readout_utils.convert_data_array(raw_data, filter_func=readout_utils.logical_and(readout_utils.is_data_record, readout_utils.is_data_from_channel(4 - front_end)), converter_func=readout_utils.get_col_row_array_from_data_record_array), bins=(80, 336), range=[[1, 80], [1, 336]]) plotting.plotThreeWay(hist=occupancy_array.T, title="Occupancy of chip %d" % front_end, x_axis_title="Occupancy", filename=output_pdf)
def read_raw_data_from_fifo(self, fifo, filter_func=None, converter_func=None): '''Reads FIFO data and returns raw data array. Returns ------- data : np.array An array containing FIFO data words. ''' return convert_data_array(self.dut[fifo].get_data(), filter_func=filter_func, converter_func=converter_func)
def analyse(data_array): global global_vars if threshold_vars["integration_time"] < 0.05: threshold_vars["integration_time"] = 0.05 for ro in data_array[0]: raw_data = ro[0] data_record = ru.convert_data_array(raw_data, filter_func=is_record) global_vars["timestamp_start"].append(ro[1]) timestamp_stop = ro[2] global_vars["hits"].append(len(data_record)) if np.any(data_record): col, row = get_col_row_array_from_data_record_array(data_record) global_vars["coloumn"].append(np.median(col)) global_vars["row"].append(np.median(row)) if not np.any(global_vars["hist_occ"]): global_vars["hist_occ"] = fast_analysis_utils.hist_2d_index( col, row, shape=(81, 337)) else: global_vars["hist_occ"] += fast_analysis_utils.hist_2d_index( col, row, shape=(81, 337)) if timestamp_stop - global_vars["timestamp_start"][0] > threshold_vars[ "integration_time"]: global_vars["hitrate"].append( np.sum(global_vars["hits"]) / (timestamp_stop - global_vars["timestamp_start"][0])) if (runmngr.current_run.run_id == "fei4_self_trigger_scan" or runmngr.current_run.run_id == "ext_trigger_scan") and global_vars["analyse"]: global_vars["beam"] = analyse_beam(global_vars["beam"]) p_hist = pickle.dumps(global_vars["hist_occ"], -1) zlib_hist = zlib.compress(p_hist) socket2.send(zlib_hist) # free memory of global variables del global_vars["hits"][:] del global_vars["timestamp_start"][:] global_vars["hist_occ"] = None #single variance gets diminished for long mesurements, this resets the variables after some time #diminishing the number leads to more sensitivity if len(global_vars["coloumn"] ) > threshold_vars["reset_coloumn_row_arrays"]: del global_vars["coloumn"][:] del global_vars["row"][:]
def test_hit_histograming(self): raw_data = np.array([67307647, 67645759, 67660079, 67541711, 67718111, 67913663, 67914223, 67847647, 67978655, 68081199, 68219119, 68219487, 68425615, 68311343, 68490719, 68373295, 68553519, 68693039, 68573503, 68709951, 68717058, 68734735, 68604719, 68753999, 68761151, 68847327, 69014799, 69079791, 69211359, 69221055, 69279567, 69499247, 69773183, 69788527, 69998559, 69868559, 69872655, 70003599, 69902527, 70274575, 70321471, 70429983, 70563295, 70574959, 70447631, 70584591, 70783023, 71091999, 70972687, 70985087, 71214815, 71382623, 71609135, 71643519, 71720527, 71897695, 72167199, 72040047, 72264927, 72423983, 77471983, 77602863, 77604383, 77485295, 77616415, 77618927, 77619231, 77639983, 77655871, 77544159, 77548303, 77338399, 77345567, 77346287, 77360399, 77255407, 77386211, 77268287, 77279215, 77409599, 77075983, 76951903, 76980527, 77117023, 76991055, 77011007, 77148127, 77148815, 76827167, 76700031, 76868895, 76758575, 76889567, 76558303, 76429599, 76584783, 76468191, 76610943, 76613743, 76620879, 76629375, 76285999, 76321908, 76194319, 76205599, 76233759, 76065391, 76075839, 76093759, 75801311, 75826319, 75829215, 75699231, 75403887, 75565039, 75439135, 75111711, 75115151, 75251487, 75258399, 75138015, 75303471, 74974111, 74868559, 75030047, 75050079, 74714591, 74722847, 74595103, 74649935, 74656815, 74796511, 74455519, 74391519, 74402607, 74534383, 74189695, 74064911, 74246271, 74116063, 74248719, 74133119, 73935183, 73941087, 73811295, 73663583, 73743423, 73449647, 73453391, 73323743, 73343471, 73474159, 73345087, 73206751, 72899295, 72958559, 72828447, 72542623, 82383232, 67374687, 67503967, 67766575, 68179999, 68052847, 68198239, 68104495, 68235759, 68238223, 68472415, 68490463, 68501279, 68621071, 68623903, 68821791, 68988639, 68864047, 69003183, 68876015, 69007423, 68891407, 69267743, 69272367, 69159567, 69666911, 69684447, 70003247, 70018895, 69898927, 69938543, 69942031, 70198863, 70339919, 70587455, 70462783, 70597679, 70796399, 70800015, 70703887, 71121183, 71323151, 71243535, 71578703, 71467695, 71622879, 71629359, 71831264, 71836511, 71710319, 71992943, 72353855, 72355039, 77606628, 77608287, 77622047, 77510223, 77653263, 77664319, 77546223, 77677471, 77549375, 77213519, 77219551, 77232207, 77234991, 77366511, 77373791, 77389647, 77404383, 77070655, 77087199, 76956975, 76996431, 77009183, 77015327, 76683567, 76840351, 76862255, 76888804, 76548975, 76554767, 76427087, 76560159, 76451967, 76456847, 76468015, 76627295, 76352831, 76354863, 76365887, 75923999, 76074175, 75955439, 76086063, 75774239, 75781535, 75792671, 75662111, 75793647, 75797167, 75827023, 75696543, 75390527, 75522031, 75533663, 75541775, 75432255, 75571535, 75115535, 75247999, 75145197, 75151391, 75160799, 74974991, 74852831, 74871839, 74882783, 75023199, 74896943, 75028767, 75046431, 74922463, 74725711, 74621199, 74658623, 74663183, 74336383, 74484559, 74364526, 74370287, 74370639, 74517983, 74393615, 74205471, 74217359, 74227263, 74231727, 74102559, 74237999, 74248735, 73953599, 73868591, 74000703, 74002975, 73877295, 73664910, 73695967, 73704751, 73579583, 73582639, 73719055, 73405998, 73448207, 73481951, 73008831, 73175087, 73044495, 73058863, 73194895, 73197919, 73093151, 72895567, 72918543, 72947039, 72957919, 82383481, 67392015, 67303135, 67312799, 67318303, 67453727, 67454767, 67634719, 67645887, 67717391, 67914111, 67947919, 67818463, 68052959, 68097215, 68500543, 68711909, 68584735, 68726975, 68741679, 68615471, 68750559, 68755487, 68629311, 68764687, 68765648, 68990175, 69022959, 69023727, 69217327, 69547327, 69665839, 69809983, 69814815, 70006831, 70037807, 70055951, 70068511, 70184031, 70323999, 70334687, 70566095, 70588751, 70723935, 71049695, 70952031, 71084831, 71376863, 71256287, 71611039, 71487727, 71618591, 71623999, 71514239, 71891231, 71897327, 71897663, 72036783, 72391487, 77604975, 77608163, 77621327, 77501983, 77635039, 77646559, 77654671, 77655695, 77546543, 77678383, 77345471, 77224735, 77375519, 77385519, 77393967, 76944399, 76975663, 77114628, 77115231, 77127525, 77142959, 76677423, 76699967, 76722287, 76857647, 76739039, 76883567, 76891615, 76453343, 76584335, 76590623, 76594607, 76600031, 76611167, 76617743, 76622303, 76285999, 76329231, 76335839, 76348175, 76350351, 76356783, 75910383, 75639343, 75787615, 75660079, 75796895, 75797615, 75692559, 75827999, 75833487, 75836479, 75518943, 75568143, 75278943, 75290271, 75297903, 75309391, 75312479, 75315119, 74852223, 74987055, 74858047, 74992943, 74875439, 75008031, 74885407, 75027743, 75055583, 74927839, 74738719, 74629087, 74767391, 74779295, 74789343, 74791247, 74323183, 74454239, 74349455, 74364751, 74516047, 74528559, 74192207, 74201535, 74084367, 74220511, 74109039, 74263263, 74133215, 73807119, 73945313, 73868148, 74001631, 73536815, 73684815, 73711439, 73275407, 73408799, 73052767, 73190975, 73209823, 72788271, 72960607, 72487647, 82383730, 67407151, 67415583, 67322127, 67523871, 67700959, 67583039, 67905375, 67793199, 68159583, 68237791, 68306479, 68492399], np.uint32) interpreter = PyDataInterpreter() histograming = PyDataHistograming() interpreter.set_trig_count(1) interpreter.set_warning_output(False) histograming.set_no_scan_parameter() histograming.create_occupancy_hist(True) interpreter.interpret_raw_data(raw_data) interpreter.store_event() histograming.add_hits(interpreter.get_hits()) occ_hist_cpp = histograming.get_occupancy()[:, :, 0] col_arr, row_arr = convert_data_array(raw_data, filter_func=is_data_record, converter_func=get_col_row_array_from_data_record_array) occ_hist_python, _, _ = np.histogram2d(col_arr, row_arr, bins=(80, 336), range=[[1, 80], [1, 336]]) self.assertTrue(np.all(occ_hist_cpp == occ_hist_python))
def get_raw_data_from_buffer(self, filter_func=None, converter_func=None): '''Reads local data buffer and returns raw data array. Returns ------- data : np.array An array containing data words from the local data buffer. ''' if self._is_running: raise RuntimeError('Readout thread running') if not self.fill_buffer: logging.warning('Data buffer is not activated') return [ convert_data_array(data_array_from_data_iterable(data_iterable), filter_func=filter_func, converter_func=converter_func) for data_iterable in self._data_buffer ]
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): 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): 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_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()
def scan(self): scan_parameter_range = [ self.register.get_global_register_value("Vthin_AltFine"), 0 ] if self.scan_parameters.Vthin_AltFine[0]: scan_parameter_range[0] = self.scan_parameters.Vthin_AltFine[0] if self.scan_parameters.Vthin_AltFine[1]: scan_parameter_range[1] = self.scan_parameters.Vthin_AltFine[1] steps = 1 if self.scan_parameters.Step: steps = self.scan_parameters.Step lvl1_command = self.register.get_commands( "LV1")[0] + self.register.get_commands( "zeros", length=self.trigger_rate_limit)[0] self.total_scan_time = int(lvl1_command.length() * 25 * (10**-9) * self.n_triggers) disabled_pixels_limit_cnt = int(self.disabled_pixels_limit * 336 * 80) preselected_pixels = invert_pixel_mask( self.register.get_pixel_register_value('Enable')).sum() disabled_pixels = 0 for reg_val in range(scan_parameter_range[0], scan_parameter_range[1] - 1, -1): if self.stop_run.is_set(): break self.register.create_restore_point(name=str(reg_val)) logging.info('Scanning Vthin_AltFine %d' % reg_val) commands = [] commands.extend(self.register.get_commands("ConfMode")) self.register.set_global_register_value( "Vthin_AltFine", reg_val) # set number of consecutive triggers commands.extend( self.register.get_commands("WrRegister", name=["Vthin_AltFine"])) # setting FE into RunMode commands.extend(self.register.get_commands("RunMode")) self.register_utils.send_commands(commands) step = 0 while True: if self.stop_run.is_set(): break step += 1 logging.info('Step %d / %d at Vthin_AltFine %d' % (step, steps, reg_val)) logging.info('Estimated scan time: %ds' % self.total_scan_time) with self.readout(Vthin_AltFine=reg_val, Step=step): got_data = False start = time() self.register_utils.send_command(lvl1_command, repeat=self.n_triggers, wait_for_finish=False, set_length=True, clear_memory=False) while not self.stop_run.wait(0.1): if self.register_utils.is_ready: if got_data: self.progressbar.finish() logging.info('Finished sending %d triggers' % self.n_triggers) break if not got_data: if self.fifo_readout.data_words_per_second() > 0: got_data = True logging.info('Taking data...') self.progressbar = progressbar.ProgressBar( widgets=[ '', progressbar.Percentage(), ' ', progressbar.Bar(marker='*', left='|', right='|'), ' ', progressbar.Timer() ], maxval=self.total_scan_time, poll=10, term_width=80).start() else: try: self.progressbar.update(time() - start) except ValueError: pass self.raw_data_file.append( self.fifo_readout.data, scan_parameters=self.scan_parameters._asdict()) col_arr, row_arr = 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) occ_hist, _, _ = np.histogram2d(col_arr, row_arr, bins=(80, 336), range=[[1, 80], [1, 336]]) occ_mask = np.zeros(shape=occ_hist.shape, dtype=np.dtype('>u1')) # noisy pixels are set to 1 occ_mask[occ_hist > self.occupancy_limit * self.n_triggers * self.consecutive_lvl1] = 1 # plot_occupancy(occ_hist.T, title='Occupancy', filename=self.scan_data_filename + '_noise_occ_' + str(reg_val) + '_' + str(step) + '.pdf') tdac_reg = self.register.get_pixel_register_value('TDAC') decrease_pixel_mask = np.logical_and(occ_mask > 0, tdac_reg > 0) disable_pixel_mask = np.logical_and(occ_mask > 0, tdac_reg == 0) enable_reg = self.register.get_pixel_register_value('Enable') enable_mask = np.logical_and( enable_reg, invert_pixel_mask(disable_pixel_mask)) if np.logical_and(occ_mask > 0, enable_reg == 0).sum(): logging.warning('Received data from disabled pixels') # disabled_pixels += disable_pixel_mask.sum() # can lead to wrong values if the enable reg is corrupted disabled_pixels = invert_pixel_mask( enable_mask).sum() - preselected_pixels if disabled_pixels > disabled_pixels_limit_cnt: logging.info( 'Limit of disabled pixels reached: %d (limit %d)... stopping scan' % (disabled_pixels, disabled_pixels_limit_cnt)) self.register.restore(name=str(reg_val)) break else: logging.info('Increasing threshold of %d pixel(s)' % (decrease_pixel_mask.sum(), )) logging.info( 'Disabling %d pixel(s), total number of disabled pixel(s): %d' % (disable_pixel_mask.sum(), disabled_pixels)) tdac_reg[decrease_pixel_mask] -= 1 # TODO self.register.set_pixel_register_value('TDAC', tdac_reg) self.register.set_pixel_register_value( 'Enable', enable_mask) commands = [] commands.extend(self.register.get_commands("ConfMode")) commands.extend( self.register.get_commands("WrFrontEnd", same_mask_for_all_dc=False, name='TDAC')) commands.extend( self.register.get_commands("WrFrontEnd", same_mask_for_all_dc=False, name='Enable')) commands.extend(self.register.get_commands("RunMode")) self.register_utils.send_commands(commands) if occ_mask.sum( ) == 0 or step == steps or decrease_pixel_mask.sum( ) < disabled_pixels_limit_cnt: self.register.clear_restore_points(name=str(reg_val)) self.last_tdac_distribution = self.register.get_pixel_register_value( 'TDAC') self.last_occupancy_hist = occ_hist.copy() self.last_occupancy_mask = occ_mask.copy() self.last_reg_val = reg_val self.last_step = step break else: logging.info( 'Found noisy pixels... repeat tuning step for Vthin_AltFine %d' % (reg_val, )) if disabled_pixels > disabled_pixels_limit_cnt: self.last_good_threshold = self.register.get_global_register_value( "Vthin_AltFine") self.last_good_tdac = self.register.get_pixel_register_value( 'TDAC') self.last_good_enable_mask = self.register.get_pixel_register_value( 'Enable') break
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): 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.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 self.trig_count == 0: self.consecutive_lvl1 = 2 ** self.register.global_registers['Trig_Count']['bitlength'] else: self.consecutive_lvl1 = self.trig_count enabled_pixels = self.register.get_pixel_register_value('Enable').sum() preselected_pixels = invert_pixel_mask(self.register.get_pixel_register_value('Enable')).sum() disabled_pixels_limit_cnt = int(self.disabled_pixels_limit * self.register.get_pixel_register_value('Enable').sum()) abs_occ_limit = stats.poisson.ppf(0.5, mu=self.occupancy_limit * self.n_triggers * self.consecutive_lvl1) logging.info('The pixel threshold will be increased when occpancy >%d' % abs_occ_limit) total_occ_limit = int(self.occupancy_limit * self.n_triggers * self.consecutive_lvl1 * enabled_pixels) # Sum of PMF of Poisson distribution (k>0) n_expected_pixel_hits = int((1.0 - stats.poisson.pmf(k=0, mu=self.occupancy_limit * self.n_triggers * self.consecutive_lvl1)) * enabled_pixels) logging.info('The global threshold will be decreased when total occupancy is <=%d and pixel with hits <=%d' % (total_occ_limit, n_expected_pixel_hits)) max_tdac_steps = max(1, int(np.ceil((1 / self.occupancy_limit) / (self.n_triggers * self.consecutive_lvl1) * (1 / (1 - 0.5))))) tdac_center = 2 ** self.register.pixel_registers['TDAC']['bitlength'] / 2 lvl1_command = self.register.get_commands("LV1")[0] + self.register.get_commands("zeros", length=self.trigger_rate_limit)[0] total_scan_time = int(lvl1_command.length() * 25 * (10 ** -9) * self.n_triggers) self.threshold = deque([None] * (self.plot_n_steps + 2), maxlen=self.plot_n_steps + 2) self.tdac_step = deque([None] * (self.plot_n_steps + 2), maxlen=self.plot_n_steps + 2) self.tdac = deque([None] * (self.plot_n_steps + 2), maxlen=self.plot_n_steps + 2) self.new_tdac = deque([None] * (self.plot_n_steps + 2), maxlen=self.plot_n_steps + 2) self.enable_mask = deque([None] * (self.plot_n_steps + 2), maxlen=self.plot_n_steps + 2) self.new_enable_mask = deque([None] * (self.plot_n_steps + 2), maxlen=self.plot_n_steps + 2) self.occupancy_hist = deque([None] * (self.plot_n_steps + 2), maxlen=self.plot_n_steps + 2) self.occupancy_mask = deque([None] * (self.plot_n_steps + 2), maxlen=self.plot_n_steps + 2) # interpreter = PyDataInterpreter() # histogram = PyDataHistograming() # interpreter.set_trig_count(self.trig_count) # interpreter.set_warning_output(False) # histogram.set_no_scan_parameter() # histogram.create_occupancy_hist(True) coarse_threshold = [self.gdac_range[0]] reached_pixels_limit_cnt = False reached_tdac_center = False reached_gdac_lower_limit = False do_refine_tuning = False for reg_val in coarse_threshold: # outer loop, coarse tuning threshold if self.stop_run.is_set(): break logging.info('Scanning Vthin_AltFine %d', reg_val) commands = [] commands.extend(self.register.get_commands("ConfMode")) self.register.set_global_register_value("Vthin_AltFine", reg_val) commands.extend(self.register.get_commands("WrRegister", name=["Vthin_AltFine"])) # setting FE into RunMode commands.extend(self.register.get_commands("RunMode")) self.register_utils.send_commands(commands) tdac_step = 1 while True: # inner loop if self.stop_run.is_set(): break # histogram.reset() logging.info('TDAC step %d at Vthin_AltFine %d', tdac_step, reg_val) # logging.info('Estimated scan time: %ds', total_scan_time) with self.readout(Vthin_AltFine=reg_val, TDAC_step=tdac_step, fill_buffer=True): got_data = False start = time() self.register_utils.send_command(lvl1_command, repeat=self.n_triggers, wait_for_finish=False, set_length=True, clear_memory=False) while not self.stop_run.wait(0.1): if self.register_utils.is_ready: if got_data: self.progressbar.finish() logging.info('Finished sending %d triggers', self.n_triggers) break if not got_data: if self.data_words_per_second() > 0: got_data = True logging.info('Taking data...') self.progressbar = progressbar.ProgressBar(widgets=['', progressbar.Percentage(), ' ', progressbar.Bar(marker='*', left='|', right='|'), ' ', progressbar.Timer()], maxval=total_scan_time, poll=10, term_width=80).start() else: try: self.progressbar.update(time() - start) except ValueError: pass # use Numpy for analysis and histogramming col_arr, row_arr = convert_data_array(array=self.read_data(), filter_func=is_data_record, converter_func=get_col_row_array_from_data_record_array) occ_hist, _, _ = np.histogram2d(col_arr, row_arr, bins=(80, 336), range=[[1, 80], [1, 336]]) occ_mask = np.zeros(shape=occ_hist.shape, dtype=np.dtype('>u1')) # use FEI4 interpreter for analysis and histogramming # from pybar.daq.readout_utils import data_array_from_data_iterable # raw_data = np.ascontiguousarray(data_array_from_data_iterable(self.read_data()), dtype=np.uint32) # interpreter.interpret_raw_data(raw_data) # interpreter.store_event() # force to create latest event # histogram.add_hits(interpreter.get_hits()) # occ_hist = histogram.get_occupancy()[:, :, 0] # # noisy pixels are set to 1 # occ_mask = np.zeros(shape=occ_hist.shape, dtype=np.dtype('>u1')) occ_mask[occ_hist > abs_occ_limit] = 1 tdac_reg = self.register.get_pixel_register_value('TDAC') decrease_pixel_mask = np.logical_and(occ_mask > 0, tdac_reg > 0) disable_pixel_mask = np.logical_and(occ_mask > 0, tdac_reg == 0) enable_mask = self.register.get_pixel_register_value('Enable') new_enable_mask = np.logical_and(enable_mask, invert_pixel_mask(disable_pixel_mask)) if np.logical_and(occ_mask > 0, enable_mask == 0).sum(): logging.warning('Received data from disabled pixels') # disabled_pixels += disable_pixel_mask.sum() # can lead to wrong values if the enable reg is corrupted disabled_pixels = invert_pixel_mask(new_enable_mask).sum() - preselected_pixels logging.info('Found %d noisy pixels', occ_mask.sum()) logging.info('Increasing threshold of %d pixel(s)', decrease_pixel_mask.sum()) logging.info('Disabling %d pixel(s), total number of disabled pixel(s): %d', disable_pixel_mask.sum(), disabled_pixels) # increasing threshold before writing TDACs to avoid FE becoming noisy self.register.set_global_register_value("Vthin_AltFine", self.gdac_range[0]) commands = [] commands.extend(self.register.get_commands("ConfMode")) commands.extend(self.register.get_commands("WrRegister", name=["Vthin_AltFine"])) self.register_utils.send_commands(commands) # writing TDAC new_tdac_reg = tdac_reg.copy() new_tdac_reg[decrease_pixel_mask] -= 1 # smaller TDAC translates to higher threshold self.register.set_pixel_register_value('TDAC', new_tdac_reg) self.register.set_pixel_register_value('Enable', new_enable_mask) commands = [] commands.extend(self.register.get_commands("WrFrontEnd", same_mask_for_all_dc=False, name='TDAC')) commands.extend(self.register.get_commands("WrFrontEnd", same_mask_for_all_dc=False, name='Enable')) self.register_utils.send_commands(commands) # writing threshold value after writing TDACs self.register.set_global_register_value("Vthin_AltFine", reg_val) commands = [] commands.extend(self.register.get_commands("WrRegister", name=["Vthin_AltFine"])) commands.extend(self.register.get_commands("RunMode")) self.register_utils.send_commands(commands) if (not do_refine_tuning and occ_hist.sum() <= total_occ_limit and occ_mask.sum() <= n_expected_pixel_hits) or (tdac_step >= max_tdac_steps): logging.info('Stop tuning TDACs at Vthin_AltFine %d', reg_val) self.threshold.appendleft(self.register.get_global_register_value("Vthin_AltFine")) self.tdac_step.appendleft(tdac_step) self.tdac.appendleft(tdac_reg) self.new_tdac.appendleft(new_tdac_reg) self.enable_mask.appendleft(enable_mask) self.new_enable_mask.appendleft(new_enable_mask) self.occupancy_hist.appendleft(occ_hist.copy()) self.occupancy_mask.appendleft(occ_mask.copy()) if not do_refine_tuning and np.mean(new_tdac_reg[new_enable_mask]) <= tdac_center + (1 if self.refine_tuning else 0): reached_tdac_center = True if not do_refine_tuning and disabled_pixels > disabled_pixels_limit_cnt: reached_pixels_limit_cnt = True logging.info('Limit of disabled pixels reached: %d (limit %d).' % (disabled_pixels, disabled_pixels_limit_cnt)) if not do_refine_tuning and reg_val <= self.gdac_range[1]: reached_gdac_lower_limit = True break else: logging.info('Continue tuning TDACs at Vthin_AltFine %d', reg_val) # increase scan parameter counter tdac_step += 1 if not self.refine_tuning and (reached_pixels_limit_cnt or reached_tdac_center or reached_gdac_lower_limit): pass # will exit loop elif do_refine_tuning: logging.info("Finished TDAC refine tuning.") elif reached_pixels_limit_cnt or reached_tdac_center or reached_gdac_lower_limit: do_refine_tuning = True logging.info("Starting TDAC refine tuning...") coarse_threshold.append(reg_val - 1) abs_occ_limit = stats.poisson.ppf(0.99, mu=self.occupancy_limit * self.n_triggers * self.consecutive_lvl1) logging.info('The pixel threshold will be increased when occpancy >%d' % abs_occ_limit) max_tdac_steps = max(1, int(np.ceil((1 / self.occupancy_limit) / (self.n_triggers * self.consecutive_lvl1) * (1 / (1 - 0.99))))) else: coarse_threshold.append(reg_val - 1)
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 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): 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): 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 = [] 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): 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): 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): 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): 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"))