Exemplo n.º 1
0
    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
        ]
Exemplo n.º 2
0
    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")
Exemplo n.º 3
0
    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
Exemplo n.º 4
0
    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_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 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,
                          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)

            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]])
            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()
Exemplo n.º 5
0
    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")
Exemplo n.º 6
0
    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):
        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
                self.histograming.reset()
                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, reset_sram_fifo=True, fill_buffer=True, clear_buffer=True, callback=self.handle_data):
                    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
                # Use fast C++ hit histograming to save time
                raw_data = np.ascontiguousarray(data_array_from_data_iterable(self.fifo_readout.data), dtype=np.uint32)
                self.interpreter.interpret_raw_data(raw_data)
                self.interpreter.store_event()  # force to create latest event
                self.histograming.add_hits(self.interpreter.get_hits())
                occ_hist = self.histograming.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 > self.occupancy_limit * self.n_triggers * self.consecutive_lvl1] = 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_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
                    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 %d noisy pixels... repeat tuning step for Vthin_AltFine %d', occ_mask.sum(), 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):
        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)

        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())
        disabled_pixels = 0
        self.last_reg_val = deque([None] * self.increase_threshold, maxlen=self.increase_threshold + 1)
        self.last_step = deque([None] * self.increase_threshold, maxlen=self.increase_threshold + 1)
        self.last_good_threshold = deque([None] * self.increase_threshold, maxlen=self.increase_threshold + 1)
        self.last_good_tdac = deque([None] * self.increase_threshold, maxlen=self.increase_threshold + 1)
        self.last_good_enable_mask = deque([None] * self.increase_threshold, maxlen=self.increase_threshold + 1)
        self.last_occupancy_hist = deque([None] * self.increase_threshold, maxlen=self.increase_threshold + 1)
        self.last_occupancy_mask = deque([None] * self.increase_threshold, maxlen=self.increase_threshold + 1)

        for reg_val in range(scan_parameter_range[0], scan_parameter_range[1] - 1, -1):
            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)  # 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
                self.histogram.reset()
                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, reset_sram_fifo=True, fill_buffer=True, clear_buffer=True, callback=self.handle_data):
                    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
                # Use fast C++ hit histogramming to save time
                raw_data = np.ascontiguousarray(data_array_from_data_iterable(self.fifo_readout.data), dtype=np.uint32)
                self.interpreter.interpret_raw_data(raw_data)
                self.interpreter.store_event()  # force to create latest event
                self.histogram.add_hits(self.interpreter.get_hits())
                occ_hist = self.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 > self.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_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))
                    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
                    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.last_reg_val.appendleft(reg_val)
                        self.last_step.appendleft(step)
                        self.last_good_threshold.appendleft(self.register.get_global_register_value("Vthin_AltFine"))
                        self.last_good_tdac.appendleft(self.register.get_pixel_register_value("TDAC"))
                        self.last_good_enable_mask.appendleft(self.register.get_pixel_register_value("Enable"))
                        self.last_occupancy_hist.appendleft(occ_hist.copy())
                        self.last_occupancy_mask.appendleft(occ_mask.copy())
                        break
                    else:
                        logging.info('Found %d noisy pixels... repeat tuning step for Vthin_AltFine %d', occ_mask.sum(), reg_val)

            if disabled_pixels > disabled_pixels_limit_cnt or scan_parameter_range[1] == reg_val:
                break
Exemplo n.º 9
0
    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()
Exemplo n.º 10
0
    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()
Exemplo n.º 11
0
    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()
Exemplo n.º 12
0
    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

        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 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,
                              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_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)

            col_row_tot_array = 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
                ))
            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:
            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"))
Exemplo n.º 13
0
    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"))
Exemplo n.º 14
0
    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()
Exemplo n.º 15
0
    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"))
Exemplo n.º 16
0
    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")
Exemplo n.º 17
0
    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")