Exemple #1
0
    def scan(self):
        delay_parameter_name = self.scan_parameters._fields[1]
        logging.info("Scanning PlsrDAC = %s and %s = %s", str(self.scan_parameters[0]), delay_parameter_name, str(self.scan_parameters[1]))

        plsr_dac_values = self.scan_parameters.PlsrDAC[:]  # create deep copy of scan_parameters, they are overwritten in self.readout
        delay_parameter_values = self.scan_parameters.PlsrDelay[:]  # create deep copy of scan_parameters, they are overwritten in self.readout

        for plsr_dac_value in plsr_dac_values:
            # Change the Plsr DAC parameter
            commands = []
            commands.extend(self.register.get_commands("ConfMode"))
            self.register.set_global_register_value('PlsrDAC', plsr_dac_value)
            commands.extend(self.register.get_commands("WrRegister", name=['PlsrDAC']))
            self.register_utils.send_commands(commands)
            for delay_parameter_value in delay_parameter_values:  # Loop over the Plsr delay parameter
                if self.stop_run.is_set():
                    break

                # Change the Plsr delay parameter
                commands = []
                commands.extend(self.register.get_commands("ConfMode"))
                self.register.set_global_register_value(delay_parameter_name, delay_parameter_value)
                commands.extend(self.register.get_commands("WrRegister", name=[delay_parameter_name]))
                self.register_utils.send_commands(commands)

                cal_lvl1_command = self.register.get_commands("CAL")[0] + self.register.get_commands("zeros", length=40)[0] + self.register.get_commands("LV1")[0]

                with self.readout(plsr_dac_value, delay_parameter_value):
                    scan_loop(self, cal_lvl1_command, repeat_command=self.n_injections, use_delay=True, mask_steps=self.mask_steps, enable_mask_steps=None, enable_double_columns=None, same_mask_for_all_dc=True, eol_function=None, digital_injection=False, enable_shift_masks=self.enable_shift_masks, disable_shift_masks=self.disable_shift_masks, restore_shift_masks=False, mask=invert_pixel_mask(self.register.get_pixel_register_value('Enable')) if self.use_enable_mask else None, double_column_correction=self.pulser_dac_correction)
Exemple #2
0
    def scan(self):
        delay_parameter_name = self.scan_parameters._fields[1]
        logging.info("Scanning PlsrDAC = %s and %s = %s" %
                     (str(self.scan_parameters[0]), delay_parameter_name,
                      str(self.scan_parameters[1])))

        plsr_dac_values = self.scan_parameters.PlsrDAC[:]  # create deep copy of scan_parameters, they are overwritten in self.readout
        delay_parameter_values = self.scan_parameters.PlsrDelay[:]  # create deep copy of scan_parameters, they are overwritten in self.readout

        for plsr_dac_value in plsr_dac_values:
            # Change the Plsr DAC parameter
            commands = []
            commands.extend(self.register.get_commands("ConfMode"))
            self.register.set_global_register_value('PlsrDAC', plsr_dac_value)
            commands.extend(
                self.register.get_commands("WrRegister", name=['PlsrDAC']))
            self.register_utils.send_commands(commands)
            for delay_parameter_value in delay_parameter_values:  # Loop over the Plsr delay parameter
                if self.stop_run.is_set():
                    break
                logging.info('Scan step: PlsrDAC %s, %s %d' %
                             (plsr_dac_value, delay_parameter_name,
                              delay_parameter_value))

                # Change the Plsr delay parameter
                commands = []
                commands.extend(self.register.get_commands("ConfMode"))
                self.register.set_global_register_value(
                    delay_parameter_name, delay_parameter_value)
                commands.extend(
                    self.register.get_commands("WrRegister",
                                               name=[delay_parameter_name]))
                self.register_utils.send_commands(commands)

                with self.readout(plsr_dac_value, delay_parameter_value):
                    cal_lvl1_command = self.register.get_commands(
                        "CAL")[0] + self.register.get_commands(
                            "zeros", length=40
                        )[0] + self.register.get_commands("LV1")[0]
                    scan_loop(
                        self,
                        cal_lvl1_command,
                        repeat_command=self.n_injections,
                        use_delay=True,
                        mask_steps=self.mask_steps,
                        enable_mask_steps=None,
                        enable_double_columns=None,
                        same_mask_for_all_dc=True,
                        eol_function=None,
                        digital_injection=False,
                        enable_shift_masks=self.enable_shift_masks,
                        disable_shift_masks=self.disable_shift_masks,
                        restore_shift_masks=False,
                        mask=invert_pixel_mask(
                            self.register.get_pixel_register_value('Enable'))
                        if self.use_enable_mask else None,
                        double_column_correction=self.pulser_dac_correction)
Exemple #3
0
    def scan(self):
        with self.readout():
            cal_lvl1_command = self.register.get_commands("CAL")[0] + self.register.get_commands("zeros", length=40)[0] + self.register.get_commands("LV1")[0]

            if self.enable_tdc:
                # activate TDC arming
                self.dut['TDC']['EN_ARMING'] = True
                scan_loop(self, cal_lvl1_command, repeat_command=self.n_injections, use_delay=True, mask_steps=self.mask_steps, enable_mask_steps=None, enable_double_columns=None, same_mask_for_all_dc=self.same_mask_for_all_dc, bol_function=self.activate_tdc, eol_function=self.deactivate_tdc, digital_injection=False, enable_shift_masks=self.enable_shift_masks, disable_shift_masks=self.disable_shift_masks, restore_shift_masks=False, mask=invert_pixel_mask(self.register.get_pixel_register_value('Enable')) if self.use_enable_mask else None, double_column_correction=self.pulser_dac_correction)
            else:
                scan_loop(self, cal_lvl1_command, repeat_command=self.n_injections, use_delay=True, mask_steps=self.mask_steps, enable_mask_steps=None, enable_double_columns=None, same_mask_for_all_dc=self.same_mask_for_all_dc, digital_injection=False, enable_shift_masks=self.enable_shift_masks, disable_shift_masks=self.disable_shift_masks, restore_shift_masks=False, mask=invert_pixel_mask(self.register.get_pixel_register_value('Enable')) if self.use_enable_mask else None, double_column_correction=self.pulser_dac_correction)
    def scan(self):
        with self.readout():
            cal_lvl1_command = self.register.get_commands("CAL")[0] + self.register.get_commands("zeros", length=40)[0] + self.register.get_commands("LV1")[0]

            if self.enable_tdc:
                # activate TDC arming
                self.dut['TDC']['EN_ARMING'] = True
                scan_loop(self, cal_lvl1_command, repeat_command=self.n_injections, use_delay=True, mask_steps=self.mask_steps, enable_mask_steps=self.enable_mask_steps, enable_double_columns=self.enable_double_columns, same_mask_for_all_dc=self.same_mask_for_all_dc, bol_function=self.activate_tdc, eol_function=self.deactivate_tdc, digital_injection=False, enable_shift_masks=self.enable_shift_masks, disable_shift_masks=self.disable_shift_masks, restore_shift_masks=False, mask=invert_pixel_mask(self.register.get_pixel_register_value('Enable')) if self.use_enable_mask else None, double_column_correction=self.pulser_dac_correction)
            else:
                scan_loop(self, cal_lvl1_command, repeat_command=self.n_injections, use_delay=True, mask_steps=self.mask_steps, enable_mask_steps=self.enable_mask_steps, enable_double_columns=self.enable_double_columns, same_mask_for_all_dc=self.same_mask_for_all_dc, digital_injection=False, enable_shift_masks=self.enable_shift_masks, disable_shift_masks=self.disable_shift_masks, restore_shift_masks=False, mask=invert_pixel_mask(self.register.get_pixel_register_value('Enable')) if self.use_enable_mask else None, double_column_correction=self.pulser_dac_correction)
Exemple #5
0
    def scan(self):
        scan_parameter_range = [
            0, (2**self.register.global_registers['PlsrDAC']['bitlength'])
        ]
        if self.scan_parameters.PlsrDAC[0]:
            scan_parameter_range[0] = self.scan_parameters.PlsrDAC[0]
        if self.scan_parameters.PlsrDAC[1]:
            scan_parameter_range[1] = self.scan_parameters.PlsrDAC[1]
        scan_parameter_range = range(scan_parameter_range[0],
                                     scan_parameter_range[1] + 1,
                                     self.step_size)
        logging.info(
            "Scanning %s from %d to %d" %
            ('PlsrDAC', scan_parameter_range[0], scan_parameter_range[-1]))

        for scan_parameter_value in scan_parameter_range:
            if self.stop_run.is_set():
                break
            logging.info('Scan step: %s %d' %
                         ('PlsrDAC', scan_parameter_value))

            commands = []
            commands.extend(self.register.get_commands("ConfMode"))
            self.register.set_global_register_value('PlsrDAC',
                                                    scan_parameter_value)
            commands.extend(
                self.register.get_commands("WrRegister", name=['PlsrDAC']))
            self.register_utils.send_commands(commands)

            with self.readout(PlsrDAC=scan_parameter_value):
                cal_lvl1_command = self.register.get_commands(
                    "CAL")[0] + self.register.get_commands(
                        "zeros",
                        length=40)[0] + self.register.get_commands("LV1")[0]
                scan_loop(self,
                          cal_lvl1_command,
                          repeat_command=self.n_injections,
                          use_delay=True,
                          mask_steps=self.mask_steps,
                          enable_mask_steps=None,
                          enable_double_columns=None,
                          same_mask_for_all_dc=True,
                          eol_function=None,
                          digital_injection=False,
                          enable_shift_masks=self.enable_shift_masks,
                          disable_shift_masks=self.disable_shift_masks,
                          restore_shift_masks=False,
                          mask=invert_pixel_mask(
                              self.register.get_pixel_register_value('Enable'))
                          if self.use_enable_mask else None,
                          double_column_correction=self.pulser_dac_correction)
Exemple #6
0
    def scan(self):
        scan_parameter_name = self.scan_parameters._fields[
            -1]  # scan parameter is in inner loop
        scan_parameters_values = self.scan_parameters[
            -1][:]  # create deep copy of scan_parameters, they are overwritten in self.readout
        logging.info("Scanning %s from %d to %d", scan_parameter_name,
                     scan_parameters_values[0], scan_parameters_values[-1])

        for scan_parameter_value in scan_parameters_values:
            if self.stop_run.is_set():
                break

            commands = []
            commands.extend(self.register.get_commands("ConfMode"))
            self.register.set_global_register_value(scan_parameter_name,
                                                    scan_parameter_value)
            commands.extend(
                self.register.get_commands("WrRegister",
                                           name=[scan_parameter_name]))
            self.register_utils.send_commands(commands)

            with self.readout(**{scan_parameter_name: scan_parameter_value}):
                cal_lvl1_command = self.register.get_commands(
                    "CAL")[0] + self.register.get_commands(
                        "zeros",
                        length=40)[0] + self.register.get_commands("LV1")[0]
                scan_loop(self,
                          cal_lvl1_command,
                          repeat_command=self.n_injections,
                          use_delay=True,
                          mask_steps=self.mask_steps,
                          enable_mask_steps=None,
                          enable_double_columns=None,
                          same_mask_for_all_dc=True,
                          fast_dc_loop=True,
                          bol_function=None,
                          eol_function=None,
                          digital_injection=False,
                          enable_shift_masks=self.enable_shift_masks,
                          disable_shift_masks=self.disable_shift_masks,
                          restore_shift_masks=False,
                          mask=invert_pixel_mask(
                              self.register.get_pixel_register_value('Enable'))
                          if self.use_enable_mask else None,
                          double_column_correction=self.pulser_dac_correction)
Exemple #7
0
 def scan(self):
     with self.readout():
         cal_lvl1_command = self.register.get_commands(
             "CAL")[0] + self.register.get_commands(
                 "zeros",
                 length=40)[0] + self.register.get_commands("LV1")[0]
         scan_loop(self,
                   cal_lvl1_command,
                   repeat_command=self.n_injections,
                   use_delay=True,
                   mask_steps=self.mask_steps,
                   enable_mask_steps=None,
                   enable_double_columns=None,
                   same_mask_for_all_dc=True,
                   eol_function=None,
                   digital_injection=True,
                   enable_shift_masks=["Enable", "EnableDigInj"],
                   restore_shift_masks=False,
                   mask=invert_pixel_mask(
                       self.register.get_pixel_register_value('Enable'))
                   if self.use_enable_mask else None)
    def scan(self):
        scan_parameter_range = [0, (2 ** self.register.global_registers['PlsrDAC']['bitlength'])]
        if self.scan_parameters.PlsrDAC[0]:
            scan_parameter_range[0] = self.scan_parameters.PlsrDAC[0]
        if self.scan_parameters.PlsrDAC[1]:
            scan_parameter_range[1] = self.scan_parameters.PlsrDAC[1]
        scan_parameter_range = range(scan_parameter_range[0], scan_parameter_range[1] + 1, self.step_size)
        logging.info("Scanning %s from %d to %d", 'PlsrDAC', scan_parameter_range[0], scan_parameter_range[-1])

        for scan_parameter_value in scan_parameter_range:
            if self.stop_run.is_set():
                break

            commands = []
            commands.extend(self.register.get_commands("ConfMode"))
            self.register.set_global_register_value('PlsrDAC', scan_parameter_value)
            commands.extend(self.register.get_commands("WrRegister", name=['PlsrDAC']))
            self.register_utils.send_commands(commands)

            with self.readout(PlsrDAC=scan_parameter_value):
                cal_lvl1_command = self.register.get_commands("CAL")[0] + self.register.get_commands("zeros", length=40)[0] + self.register.get_commands("LV1")[0]
                scan_loop(self, cal_lvl1_command, repeat_command=self.n_injections, use_delay=True, mask_steps=self.mask_steps, enable_mask_steps=None, enable_double_columns=None, same_mask_for_all_dc=True, fast_dc_loop=True, bol_function=None, eol_function=None, digital_injection=False, enable_shift_masks=self.enable_shift_masks, disable_shift_masks=self.disable_shift_masks, restore_shift_masks=False, mask=invert_pixel_mask(self.register.get_pixel_register_value('Enable')) if self.use_enable_mask else None, double_column_correction=self.pulser_dac_correction)
Exemple #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()
Exemple #10
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")
Exemple #11
0
    def scan(self):
        scan_parameter_range = [
            0, (2**self.register.global_registers['PlsrDAC']['bitlength'])
        ]
        if self.scan_parameters.PlsrDAC[0]:
            scan_parameter_range[0] = self.scan_parameters.PlsrDAC[0]
        if self.scan_parameters.PlsrDAC[1]:
            scan_parameter_range[1] = self.scan_parameters.PlsrDAC[1]
        scan_parameter_range = range(scan_parameter_range[0],
                                     scan_parameter_range[1] + 1,
                                     self.step_size)
        logging.info("Scanning %s from %d to %d", 'PlsrDAC',
                     scan_parameter_range[0], scan_parameter_range[-1])

        def set_xtalk_mask():
            frame = inspect.currentframe()
            if frame.f_back.f_locals['index'] == 0:
                mask = make_pixel_mask(
                    steps=self.mask_steps,
                    shift=frame.f_back.f_locals['mask_step'])
                mask = make_xtalk_mask(mask)
                map(
                    lambda mask_name: self.register.set_pixel_register_value(
                        mask_name, mask), self.disable_shift_masks)
                commands = []
                commands.append(self.register.get_commands("ConfMode")[0])
                commands.extend(
                    self.register.get_commands("WrFrontEnd",
                                               same_mask_for_all_dc=True,
                                               name=self.xtalk_shift_mask,
                                               joint_write=True))
                commands.append(self.register.get_commands("RunMode")[0])
                self.register_utils.send_commands(commands, concatenate=True)

        for scan_parameter_value in scan_parameter_range:
            if self.stop_run.is_set():
                break

            commands = []
            commands.extend(self.register.get_commands("ConfMode"))
            self.register.set_global_register_value('PlsrDAC',
                                                    scan_parameter_value)
            commands.extend(
                self.register.get_commands("WrRegister", name=['PlsrDAC']))
            self.register_utils.send_commands(commands)

            with self.readout(PlsrDAC=scan_parameter_value):
                cal_lvl1_command = self.register.get_commands(
                    "CAL")[0] + self.register.get_commands(
                        "zeros",
                        length=40)[0] + self.register.get_commands("LV1")[0]
                scan_loop(self,
                          cal_lvl1_command,
                          repeat_command=self.n_injections,
                          use_delay=True,
                          mask_steps=self.mask_steps,
                          enable_mask_steps=None,
                          enable_double_columns=None,
                          same_mask_for_all_dc=False,
                          fast_dc_loop=False,
                          bol_function=set_xtalk_mask,
                          eol_function=None,
                          digital_injection=False,
                          enable_shift_masks=self.enable_shift_masks,
                          disable_shift_masks=self.disable_shift_masks,
                          restore_shift_masks=False,
                          mask=invert_pixel_mask(
                              self.register.get_pixel_register_value('Enable'))
                          if self.use_enable_mask else None,
                          double_column_correction=self.pulser_dac_correction)
Exemple #12
0
 def scan(self):
     with self.readout():
         cal_lvl1_command = self.register.get_commands("CAL")[0] + self.register.get_commands("zeros", length=40)[0] + self.register.get_commands("LV1")[0]
         scan_loop(self, cal_lvl1_command, repeat_command=self.n_injections, use_delay=True, mask_steps=self.mask_steps, enable_mask_steps=None, enable_double_columns=None, same_mask_for_all_dc=True, eol_function=None, digital_injection=True, enable_shift_masks=["Enable", "EnableDigInj"], restore_shift_masks=False, mask=invert_pixel_mask(self.register.get_pixel_register_value('Enable')) if self.use_enable_mask else None)
Exemple #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

        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()
Exemple #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()
Exemple #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

        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")
Exemple #16
0
    def scan(self):
        cal_lvl1_command = self.register.get_commands(
            "CAL")[0] + self.register.get_commands(
                "zeros", length=40)[0] + self.register.get_commands("LV1")[0]

        self.write_target_threshold()

        scan_parameter_range = [
            (2**self.register.global_registers['Vthin_AltFine']['bitlength']),
            0
        ]  # high to low
        if self.start_gdac:
            scan_parameter_range[0] = self.start_gdac
        if self.gdac_lower_limit:
            scan_parameter_range[1] = self.gdac_lower_limit

        scan_parameter_range = np.arange(scan_parameter_range[0],
                                         scan_parameter_range[1] - 1,
                                         self.step_size)

        logging.info("Scanning %s from %d to %d", 'GDAC',
                     scan_parameter_range[0], scan_parameter_range[-1])

        def bits_set(int_type):
            int_type = int(int_type)
            position = 0
            bits_set = []
            while (int_type):
                if (int_type & 1):
                    bits_set.append(position)
                position += 1
                int_type = int_type >> 1
            return bits_set

        # calculate selected pixels from the mask and the disabled columns
        select_mask_array = np.zeros(shape=(80, 336), dtype=np.uint8)
        self.occ_array_sel_pixels_best = select_mask_array.copy()
        self.occ_array_desel_pixels_best = select_mask_array.copy()
        if not self.enable_mask_steps_gdac:
            self.enable_mask_steps_gdac = range(self.mask_steps)
        for mask_step in self.enable_mask_steps_gdac:
            select_mask_array += make_pixel_mask(steps=self.mask_steps,
                                                 shift=mask_step)
        for column in bits_set(
                self.register.get_global_register_value("DisableColumnCnfg")):
            logging.info('Deselect double column %d' % column)
            select_mask_array[column, :] = 0

        gdac_values = []
        gdac_occupancies = []
        gdac_occ_array_sel_pixels = []
        gdac_occ_array_desel_pixels = []
        median_occupancy_last_step = None
        for scan_parameter_value in scan_parameter_range:
            if self.stop_run.is_set():
                break
            self.register_utils.set_gdac(scan_parameter_value)
            with self.readout(GDAC=scan_parameter_value, fill_buffer=True):
                scan_loop(self,
                          command=cal_lvl1_command,
                          repeat_command=self.n_injections_gdac,
                          mask_steps=self.mask_steps,
                          enable_mask_steps=self.enable_mask_steps_gdac,
                          enable_double_columns=None,
                          same_mask_for_all_dc=self.same_mask_for_all_dc,
                          eol_function=None,
                          digital_injection=False,
                          enable_shift_masks=self.enable_shift_masks,
                          disable_shift_masks=self.disable_shift_masks,
                          restore_shift_masks=True,
                          mask=None,
                          double_column_correction=self.pulser_dac_correction)

            data = convert_data_array(
                array=self.read_data(),
                filter_func=is_data_record,
                converter_func=get_col_row_array_from_data_record_array)
            occupancy_array, _, _ = np.histogram2d(*data,
                                                   bins=(80, 336),
                                                   range=[[1, 80], [1, 336]])
            occ_array_sel_pixels = np.ma.array(
                occupancy_array,
                mask=np.logical_not(np.ma.make_mask(select_mask_array))
            )  # take only selected pixel into account by using the mask
            occ_array_desel_pixels = np.ma.array(
                occupancy_array, mask=np.ma.make_mask(select_mask_array)
            )  # take only de-selected pixel into account by using the inverted mask
            median_occupancy = np.ma.median(occ_array_sel_pixels)
            percentile_noise_occupancy = np.percentile(
                occ_array_desel_pixels.compressed(), 99.0)
            occupancy_almost_zero = np.allclose(median_occupancy, 0)
            no_noise = np.allclose(percentile_noise_occupancy, 0)
            gdac_values.append(self.register_utils.get_gdac())
            gdac_occupancies.append(median_occupancy)
            gdac_occ_array_sel_pixels.append(occ_array_sel_pixels.copy())
            gdac_occ_array_desel_pixels.append(occ_array_desel_pixels.copy())
            self.occ_array_sel_pixels_best = occ_array_sel_pixels.copy()
            self.occ_array_desel_pixels_best = occ_array_desel_pixels.copy()

            # abort early if threshold is found
            if no_noise and not occupancy_almost_zero and (
                    median_occupancy_last_step is not None
                    and median_occupancy >= median_occupancy_last_step
            ) and median_occupancy >= self.n_injections_gdac / 2.0:
                break

            if no_noise and not occupancy_almost_zero:
                median_occupancy_last_step = median_occupancy
            else:
                median_occupancy_last_step = 0.0

        if not self.stop_run.is_set():
            # select best GDAC value
            sorted_indices = np.argsort(np.array(gdac_values))
            occupancy_sorted = np.array(gdac_occupancies)[sorted_indices]
            gdac_sorted = np.sort(gdac_values)
            gdac_min_idx = np.where(
                occupancy_sorted >= self.n_injections_gdac / 2.0)[0][-1]
            occupancy_sorted_sel = occupancy_sorted[gdac_min_idx:]
            gdac_sorted_sel = gdac_sorted[gdac_min_idx:]
            best_index_sel = np.abs(
                np.array(occupancy_sorted_sel) -
                self.n_injections_gdac / 2.0).argmin()
            best_index = sorted_indices[gdac_min_idx:][::-1][best_index_sel]
            gdac_best = gdac_values[best_index]
            median_occupancy = gdac_occupancies[best_index]
            self.register_utils.set_gdac(gdac_best, send_command=False)
            # for plotting
            self.occ_array_sel_pixels_best = gdac_occ_array_sel_pixels[
                best_index]
            self.occ_array_desel_pixels_best = gdac_occ_array_desel_pixels[
                best_index]
            self.gdac_best = self.register_utils.get_gdac()

            if abs(median_occupancy - self.n_injections_gdac / 2.0
                   ) > self.max_delta_threshold and not self.stop_run.is_set():
                if np.all((((self.gdac_best & (1 << np.arange(
                        self.register.global_registers['Vthin_AltFine']
                    ['bitlength'] + self.register.
                        global_registers['Vthin_AltFine']['bitlength'])))) > 0
                           ).astype(int) == 0):
                    if self.fail_on_warning:
                        raise RuntimeWarning(
                            'Selected GDAC bits reached minimum value')
                    else:
                        logging.warning(
                            'Selected GDAC bits reached minimum value')
                else:
                    if self.fail_on_warning:
                        raise RuntimeWarning(
                            'Global threshold tuning failed. Delta threshold = %.2f > %.2f. Vthin_AltCoarse / Vthin_AltFine = %d / %d'
                            % (abs(median_occupancy - self.n_injections_gdac /
                                   2.0), self.max_delta_threshold,
                               self.register.get_global_register_value(
                                   "Vthin_AltCoarse"),
                               self.register.get_global_register_value(
                                   "Vthin_AltFine")))
                    else:
                        logging.warning(
                            'Global threshold tuning failed. Delta threshold = %.2f > %.2f. Vthin_AltCoarse / Vthin_AltFine = %d / %d',
                            abs(median_occupancy -
                                self.n_injections_gdac / 2.0),
                            self.max_delta_threshold,
                            self.register.get_global_register_value(
                                "Vthin_AltCoarse"),
                            self.register.get_global_register_value(
                                "Vthin_AltFine"))
            else:
                logging.info(
                    'Tuned GDAC to Vthin_AltCoarse / Vthin_AltFine = %d / %d',
                    self.register.get_global_register_value("Vthin_AltCoarse"),
                    self.register.get_global_register_value("Vthin_AltFine"))
Exemple #17
0
    def scan(self):
        enable_mask_steps = []
        cal_lvl1_command = self.register.get_commands(
            "CAL")[0] + self.register.get_commands(
                "zeros", length=40)[0] + self.register.get_commands("LV1")[0]

        self.write_target_threshold()
        additional_scan = True
        lastBitResult = np.zeros(
            shape=self.register.get_pixel_register_value("TDAC").shape,
            dtype=self.register.get_pixel_register_value("TDAC").dtype)

        self.set_start_tdac()

        self.occupancy_best = np.full(
            shape=(80, 336), fill_value=self.n_injections_tdac
        )  # array to store the best occupancy (closest to Ninjections/2) of the pixel
        self.tdac_mask_best = self.register.get_pixel_register_value("TDAC")
        tdac_tune_bits = self.tdac_tune_bits[:]
        for scan_parameter_value, tdac_bit in enumerate(tdac_tune_bits):
            if self.stop_run.is_set():
                break
            if additional_scan:
                self.set_tdac_bit(tdac_bit)
                logging.info('TDAC setting: bit %d = 1', tdac_bit)
            else:
                self.set_tdac_bit(tdac_bit, bit_value=0)
                logging.info('TDAC setting: bit %d = 0', tdac_bit)

            self.write_tdac_config()

            with self.readout(TDAC=scan_parameter_value, fill_buffer=True):
                scan_loop(self,
                          command=cal_lvl1_command,
                          repeat_command=self.n_injections_tdac,
                          mask_steps=self.mask_steps,
                          enable_mask_steps=enable_mask_steps,
                          enable_double_columns=None,
                          same_mask_for_all_dc=self.same_mask_for_all_dc,
                          eol_function=None,
                          digital_injection=False,
                          enable_shift_masks=self.enable_shift_masks,
                          disable_shift_masks=self.disable_shift_masks,
                          restore_shift_masks=True,
                          mask=None,
                          double_column_correction=self.pulser_dac_correction)

            data = convert_data_array(
                array=self.read_data(),
                filter_func=is_data_record,
                converter_func=get_col_row_array_from_data_record_array)
            occupancy_array, _, _ = np.histogram2d(*data,
                                                   bins=(80, 336),
                                                   range=[[1, 80], [1, 336]])
            select_better_pixel_mask = abs(occupancy_array -
                                           self.n_injections_tdac / 2) <= abs(
                                               self.occupancy_best -
                                               self.n_injections_tdac / 2)
            pixel_with_too_high_occupancy_mask = occupancy_array > self.n_injections_tdac / 2
            self.occupancy_best[select_better_pixel_mask] = occupancy_array[
                select_better_pixel_mask]

            if self.plot_intermediate_steps:
                plot_three_way(occupancy_array.transpose(),
                               title="Occupancy (TDAC tuning bit " +
                               str(tdac_bit) + ")",
                               x_axis_title='Occupancy',
                               filename=self.plots_filename,
                               maximum=self.n_injections_tdac)

            tdac_mask = self.register.get_pixel_register_value("TDAC")
            self.tdac_mask_best[select_better_pixel_mask] = tdac_mask[
                select_better_pixel_mask]

            if tdac_bit > 0:
                tdac_mask[pixel_with_too_high_occupancy_mask] = tdac_mask[
                    pixel_with_too_high_occupancy_mask] & ~(1 << tdac_bit)
                self.register.set_pixel_register_value("TDAC", tdac_mask)

            if tdac_bit == 0:
                if additional_scan:  # scan bit = 0 with the correct value again
                    additional_scan = False
                    lastBitResult = occupancy_array.copy()
                    tdac_tune_bits.append(0)  # bit 0 has to be scanned twice
                else:
                    tdac_mask[
                        abs(occupancy_array - self.n_injections_tdac / 2) >
                        abs(lastBitResult -
                            self.n_injections_tdac / 2)] = tdac_mask[
                                abs(occupancy_array - self.n_injections_tdac /
                                    2) > abs(lastBitResult -
                                             self.n_injections_tdac / 2)] | (
                                                 1 << tdac_bit)
                    occupancy_array[
                        abs(occupancy_array - self.n_injections_tdac / 2) >
                        abs(lastBitResult -
                            self.n_injections_tdac / 2)] = lastBitResult[
                                abs(occupancy_array - self.n_injections_tdac /
                                    2) > abs(lastBitResult -
                                             self.n_injections_tdac / 2)]
                    self.occupancy_best[
                        abs(occupancy_array - self.n_injections_tdac / 2) <=
                        abs(self.occupancy_best -
                            self.n_injections_tdac / 2)] = occupancy_array[
                                abs(occupancy_array - self.n_injections_tdac /
                                    2) <= abs(self.occupancy_best -
                                              self.n_injections_tdac / 2)]
                    self.tdac_mask_best[
                        abs(occupancy_array - self.n_injections_tdac / 2) <=
                        abs(self.occupancy_best -
                            self.n_injections_tdac / 2)] = tdac_mask[
                                abs(occupancy_array - self.n_injections_tdac /
                                    2) <= abs(self.occupancy_best -
                                              self.n_injections_tdac / 2)]

        self.register.set_pixel_register_value(
            "TDAC", self.tdac_mask_best)  # set value for meta scan
        self.write_tdac_config()
Exemple #18
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()
Exemple #19
0
    def scan(self):
        cal_lvl1_command = self.register.get_commands(
            "CAL")[0] + self.register.get_commands(
                "zeros", length=40)[0] + self.register.get_commands("LV1")[0]

        self.write_target_threshold()

        def bits_set(int_type):
            int_type = int(int_type)
            position = 0
            bits_set = []
            while (int_type):
                if (int_type & 1):
                    bits_set.append(position)
                position += 1
                int_type = int_type >> 1
            return bits_set

        # calculate selected pixels from the mask and the disabled columns
        select_mask_array = np.zeros(shape=(80, 336), dtype=np.uint8)
        if not self.enable_mask_steps_gdac:
            self.enable_mask_steps_gdac = range(self.mask_steps)
        for mask_step in self.enable_mask_steps_gdac:
            select_mask_array += make_pixel_mask(steps=self.mask_steps,
                                                 shift=mask_step)
        for column in bits_set(
                self.register.get_global_register_value("DisableColumnCnfg")):
            logging.info('Deselect double column %d' % column)
            select_mask_array[column, :] = 0

        gdacs_above_threshold = []
        additional_scan_ongoing = False
        last_good_gdac_bit = self.gdac_tune_bits[0]
        last_good_gdac_scan_step = 0
        gdac_tune_bits_permutation = 0
        gdac_values = []
        gdac_occupancies = []
        gdac_occ_array_sel_pixels = []
        gdac_occ_array_desel_pixels = []
        gdac_tune_bits = self.gdac_tune_bits[:]
        min_gdac_with_occupancy = None
        for gdac_scan_step, gdac_bit in enumerate(gdac_tune_bits):
            if self.stop_run.is_set():
                break
            # set all higher GDAC bits
            gdac_tune_bits_permutation_header = map(
                int,
                bin(2**last_good_gdac_scan_step - 1 -
                    gdac_tune_bits_permutation)[2:].zfill(
                        last_good_gdac_scan_step))[-last_good_gdac_scan_step:]
            for gdac_permutation_bit, gdac_permutation_bit_value in enumerate(
                    gdac_tune_bits_permutation_header):
                self.set_gdac_bit(self.gdac_tune_bits[gdac_permutation_bit],
                                  bit_value=gdac_permutation_bit_value,
                                  send_command=False)
            # clear all lower GDAC bits
            for clear_gdac_bit in self.gdac_tune_bits:
                if clear_gdac_bit < gdac_bit:
                    self.set_gdac_bit(clear_gdac_bit,
                                      bit_value=0,
                                      send_command=False)
            if additional_scan_ongoing:
                self.set_gdac_bit(gdac_bit, bit_value=0, send_command=True)
                scan_parameter_value = (
                    self.register.get_global_register_value("Vthin_AltCoarse")
                    << 8
                ) + self.register.get_global_register_value("Vthin_AltFine")
                logging.info('GDAC setting: %d, set bit %d = 0',
                             scan_parameter_value, gdac_bit)
            else:  # default
                self.set_gdac_bit(gdac_bit, bit_value=1, send_command=False)
                scan_parameter_value = (
                    self.register.get_global_register_value("Vthin_AltCoarse")
                    << 8
                ) + self.register.get_global_register_value("Vthin_AltFine")
                logging.info('GDAC setting: %d, set bit %d = 1',
                             scan_parameter_value, gdac_bit)
            # check if GDAC values are too low or were already scanned
            if not additional_scan_ongoing and (
                (self.register_utils.get_gdac() in gdac_values) or
                (self.gdac_lower_limit
                 and self.register_utils.get_gdac() < self.gdac_lower_limit) or
                (min_gdac_with_occupancy and
                 self.register_utils.get_gdac() <= min_gdac_with_occupancy)):
                if gdac_tune_bits_permutation + 1 == 2**last_good_gdac_scan_step:  # next permutation step
                    gdac_tune_bits_permutation = 0
                    last_good_gdac_scan_step += 1
                else:
                    gdac_tune_bits_permutation += 1
                for i in range(len(gdac_tune_bits) - (gdac_scan_step + 1)):
                    gdac_tune_bits.pop()
                gdac_tune_bits.extend(
                    self.gdac_tune_bits[last_good_gdac_scan_step:]
                )  # repeat all scan steps from last bit
                continue
            # write GDAC
            self.register_utils.set_gdac(self.register_utils.get_gdac(),
                                         send_command=True)
            # start scan loop
            with self.readout(GDAC=scan_parameter_value, fill_buffer=True):
                scan_loop(self,
                          command=cal_lvl1_command,
                          repeat_command=self.n_injections_gdac,
                          mask_steps=self.mask_steps,
                          enable_mask_steps=self.enable_mask_steps_gdac,
                          enable_double_columns=None,
                          same_mask_for_all_dc=self.same_mask_for_all_dc,
                          eol_function=None,
                          digital_injection=False,
                          enable_shift_masks=self.enable_shift_masks,
                          disable_shift_masks=self.disable_shift_masks,
                          restore_shift_masks=True,
                          mask=None,
                          double_column_correction=self.pulser_dac_correction)
            # calculate arrays from data
            data = convert_data_array(
                array=self.read_data(),
                filter_func=is_data_record,
                converter_func=get_col_row_array_from_data_record_array)
            occupancy_array, _, _ = np.histogram2d(*data,
                                                   bins=(80, 336),
                                                   range=[[1, 80], [1, 336]])
            occ_array_sel_pixels = np.ma.array(
                occupancy_array,
                mask=np.logical_not(np.ma.make_mask(select_mask_array))
            )  # take only selected pixel into account by using the mask
            occ_array_desel_pixels = np.ma.array(
                occupancy_array, mask=np.ma.make_mask(select_mask_array)
            )  # take only de-selected pixel into account by using the inverted mask
            median_occupancy = np.ma.median(occ_array_sel_pixels)
            percentile_noise_occupancy = np.percentile(
                occ_array_desel_pixels.compressed(), 99.0)
            occupancy_almost_zero = np.allclose(median_occupancy, 0)
            no_noise = np.allclose(percentile_noise_occupancy, 0)
            gdac_values.append(self.register_utils.get_gdac())
            gdac_occupancies.append(median_occupancy)
            gdac_occ_array_sel_pixels.append(occ_array_sel_pixels.copy())
            gdac_occ_array_desel_pixels.append(occ_array_desel_pixels.copy())
            self.occ_array_sel_pixels_best = occ_array_sel_pixels.copy()
            self.occ_array_desel_pixels_best = occ_array_desel_pixels.copy()

            if len(gdac_values) >= 2:
                for index, scanned_gdac in enumerate(gdac_values[:-1]):
                    if (self.register_utils.get_gdac() < scanned_gdac
                            and median_occupancy <= gdac_occupancies[index]
                            and gdac_occupancies[index] != 0):
                        if min_gdac_with_occupancy is None:
                            min_gdac_with_occupancy = self.register_utils.get_gdac(
                            )
                        else:
                            min_gdac_with_occupancy = max(
                                min_gdac_with_occupancy,
                                self.register_utils.get_gdac())
                    if (scanned_gdac < self.register_utils.get_gdac()
                            and gdac_occupancies[index] <= median_occupancy
                            and median_occupancy != 0):
                        if min_gdac_with_occupancy is None:
                            min_gdac_with_occupancy = scanned_gdac
                        else:
                            min_gdac_with_occupancy = max(
                                min_gdac_with_occupancy, scanned_gdac)
                    for gdac_above_threshold in gdacs_above_threshold:
                        if gdac_above_threshold <= min_gdac_with_occupancy:  # check for valid values
                            gdacs_above_threshold.remove(gdac_above_threshold)

            if gdac_scan_step + 1 == len(
                    gdac_tune_bits):  # last GDAC scan step
                if not additional_scan_ongoing and (
                    (occupancy_almost_zero and no_noise)
                        or not gdacs_above_threshold or
                    (self.gdac_lower_limit and
                     self.register_utils.get_gdac() < self.gdac_lower_limit) or
                    (min_gdac_with_occupancy and
                     self.register_utils.get_gdac() <= min_gdac_with_occupancy)
                        or not no_noise
                ) and len(
                        self.gdac_tune_bits
                ) >= last_good_gdac_scan_step + 2:  # min. 2 bits for bin search
                    self.set_gdac_bit(
                        gdac_bit, bit_value=0,
                        send_command=False)  # clear current tuning bit
                    if gdac_tune_bits_permutation + 1 == 2**last_good_gdac_scan_step:  # next permutation step
                        gdac_tune_bits_permutation = 0
                        last_good_gdac_scan_step += 1
                    else:
                        gdac_tune_bits_permutation += 1
                    gdac_tune_bits.extend(
                        self.gdac_tune_bits[last_good_gdac_scan_step:]
                    )  # repeat all scan steps from last bit
                elif gdac_bit == 0 and not additional_scan_ongoing:  # scan bit 0 = 1
                    additional_scan_ongoing = True
                    last_occ_array_sel_pixels = occ_array_sel_pixels.copy()
                    last_occ_array_desel_pixels = occ_array_desel_pixels.copy()
                    last_median_occupancy = median_occupancy
                    gdac_tune_bits.append(
                        0)  # the last tune bit has to be scanned twice
                elif gdac_bit == 0 and additional_scan_ongoing:  # scan bit 0 = 0
                    additional_scan_ongoing = False
                    logging.info(
                        'Measured %.2f with bit 0 = 0 with and %.2f with bit 0 = 1',
                        median_occupancy, last_median_occupancy)
                    if (abs(median_occupancy - self.n_injections_gdac / 2.0) >=
                            abs(last_median_occupancy -
                                self.n_injections_gdac / 2.0)
                        ) or (
                            last_median_occupancy >=
                            self.n_injections_gdac / 2.0
                        ):  # if bit 0 = 0 is worse than bit 0 = 1, so go back
                        logging.info('Set bit 0 = 1')
                        self.set_gdac_bit(
                            0, bit_value=1,
                            send_command=True)  # write GDAC value
                        occ_array_sel_pixels = last_occ_array_sel_pixels.copy()
                        occ_array_desel_pixels = last_occ_array_desel_pixels.copy(
                        )
                        median_occupancy = last_median_occupancy
                    else:
                        logging.info('Keep bit 0 = 0')
            else:  # regular GDAC scan step
                # GDAC too low, no hits
                if (self.gdac_lower_limit and
                        self.register_utils.get_gdac() < self.gdac_lower_limit
                    ) or (min_gdac_with_occupancy
                          and self.register_utils.get_gdac() <=
                          min_gdac_with_occupancy) or not no_noise:
                    logging.info(
                        'Median = %.2f > %.2f, GDAC possibly too low, keep bit %d = 1',
                        median_occupancy, self.n_injections_gdac / 2.0,
                        gdac_bit)
                # GDAC too high, less hits, decrease GDAC
                elif median_occupancy < self.n_injections_gdac / 2.0:  # set GDAC bit to 0 if the occupancy is too low, thus decrease threshold
                    logging.info('Median = %.2f < %.2f, set bit %d = 0',
                                 median_occupancy,
                                 self.n_injections_gdac / 2.0, gdac_bit)
                    self.set_gdac_bit(
                        gdac_bit, bit_value=0, send_command=False
                    )  # do not write, might be too low, do this in next iteration
                # GDAC too low, more hits, increase GDAC
                else:
                    gdacs_above_threshold.append(
                        self.register_utils.get_gdac())
                    logging.info('Median = %.2f > %.2f, keep bit %d = 1',
                                 median_occupancy,
                                 self.n_injections_gdac / 2.0, gdac_bit)

        if not self.stop_run.is_set():
            # select best GDAC value
            sorted_indices = np.argsort(np.array(gdac_values))
            occupancy_sorted = np.array(gdac_occupancies)[sorted_indices]
            gdac_sorted = np.sort(gdac_values)
            try:
                diff_occupancy = occupancy_sorted[1:] - occupancy_sorted[:-1]
                gdac_min_idx = np.where(diff_occupancy > 0)[0][-1] + 1
            except IndexError:
                gdac_min_idx = None
            occupancy_sorted_sel = occupancy_sorted[gdac_min_idx:]
            best_index_sel = np.abs(
                np.array(occupancy_sorted_sel[::-1]) -
                self.n_injections_gdac / 2.0).argmin()
            best_index = sorted_indices[gdac_min_idx:][::-1][best_index_sel]
            gdac_best = gdac_values[best_index]
            median_occupancy = gdac_occupancies[best_index]
            # for plotting
            self.occ_array_sel_pixels_best = gdac_occ_array_sel_pixels[
                best_index]
            self.occ_array_desel_pixels_best = gdac_occ_array_desel_pixels[
                best_index]
            if gdac_best != self.register_utils.get_gdac():
                logging.info(
                    "Binary search converged to non-optimal value, apply best GDAC value, change GDAC from %d to %d",
                    self.register_utils.get_gdac(), gdac_best)
                self.register_utils.set_gdac(gdac_best, send_command=False)
            self.gdac_best = self.register_utils.get_gdac()

            if abs(median_occupancy - self.n_injections_gdac / 2.0) > abs(
                    self.n_injections_gdac * 0.01 *
                    self.max_delta_threshold) and not self.stop_run.is_set():
                if np.all((((self.gdac_best & (1 << np.arange(
                        self.register.global_registers['Vthin_AltFine']
                    ['bitlength'] + self.register.
                        global_registers['Vthin_AltFine']['bitlength'])))) > 0
                           ).astype(int)[self.gdac_tune_bits] == 1):
                    if self.fail_on_warning:
                        raise RuntimeWarning(
                            'Selected GDAC bits reached maximum value')
                    else:
                        logging.warning(
                            'Selected GDAC bits reached maximum value')
                elif np.all((((self.gdac_best & (1 << np.arange(
                        self.register.global_registers['Vthin_AltFine']
                    ['bitlength'] + self.register.
                        global_registers['Vthin_AltFine']['bitlength'])))) > 0
                             ).astype(int)[self.gdac_tune_bits] == 0):
                    if self.fail_on_warning:
                        raise RuntimeWarning(
                            'Selected GDAC bits reached minimum value')
                    else:
                        logging.warning(
                            'Selected GDAC bits reached minimum value')
                else:
                    if self.fail_on_warning:
                        raise RuntimeWarning(
                            'Global threshold tuning failed. Delta threshold = %.2f > %.2f. Vthin_AltCoarse / Vthin_AltFine = %d / %d'
                            % (abs(median_occupancy -
                                   self.n_injections_gdac / 2.0),
                               abs(self.n_injections_gdac * 0.01 *
                                   self.max_delta_threshold),
                               self.register.get_global_register_value(
                                   "Vthin_AltCoarse"),
                               self.register.get_global_register_value(
                                   "Vthin_AltFine")))
                    else:
                        logging.warning(
                            'Global threshold tuning failed. Delta threshold = %.2f > %.2f. Vthin_AltCoarse / Vthin_AltFine = %d / %d',
                            abs(median_occupancy -
                                self.n_injections_gdac / 2.0),
                            abs(self.n_injections_gdac * 0.01 *
                                self.max_delta_threshold),
                            self.register.get_global_register_value(
                                "Vthin_AltCoarse"),
                            self.register.get_global_register_value(
                                "Vthin_AltFine"))
            else:
                logging.info(
                    'Tuned GDAC to Vthin_AltCoarse / Vthin_AltFine = %d / %d',
                    self.register.get_global_register_value("Vthin_AltCoarse"),
                    self.register.get_global_register_value("Vthin_AltFine"))
    def scan(self):
        if not self.plots_filename:
            self.plots_filename = PdfPages(self.output_filename + '.pdf')
            self.close_plots = True
        else:
            self.close_plots = False

        cal_lvl1_command = self.register.get_commands(
            "CAL")[0] + self.register.get_commands(
                "zeros", length=40)[0] + self.register.get_commands("LV1")[0]

        self.write_target_threshold()

        scan_parameter_range = [
            (2**self.register.global_registers['Vthin_AltFine']['bitlength']),
            0
        ]  # high to low
        if self.scan_parameters.GDAC[0]:
            scan_parameter_range[0] = self.scan_parameters.GDAC[0]
        if self.scan_parameters.GDAC[1]:
            scan_parameter_range[1] = self.scan_parameters.GDAC[1]
        scan_parameter_range = range(scan_parameter_range[0],
                                     scan_parameter_range[1] - 1,
                                     self.step_size)
        logging.info("Scanning %s from %d to %d", 'GDAC',
                     scan_parameter_range[0], scan_parameter_range[-1])

        def bits_set(int_type):
            int_type = int(int_type)
            position = 0
            bits_set = []
            while (int_type):
                if (int_type & 1):
                    bits_set.append(position)
                position += 1
                int_type = int_type >> 1
            return bits_set

        # calculate selected pixels from the mask and the disabled columns
        select_mask_array = np.zeros(shape=(80, 336), dtype=np.uint8)
        self.occ_array_sel_pixels_best = select_mask_array.copy()
        self.occ_array_desel_pixels_best = select_mask_array.copy()
        if not self.enable_mask_steps_gdac:
            self.enable_mask_steps_gdac = range(self.mask_steps)
        for mask_step in self.enable_mask_steps_gdac:
            select_mask_array += make_pixel_mask(steps=self.mask_steps,
                                                 shift=mask_step)
        for column in bits_set(
                self.register.get_global_register_value("DisableColumnCnfg")):
            logging.info('Deselect double column %d' % column)
            select_mask_array[column, :] = 0

        occupancy_best = 0.0
        median_occupancy_last_step = 0.0
        gdac_best = self.register_utils.get_gdac()
        for gdac_scan_step, scan_parameter_value in enumerate(
                scan_parameter_range):
            self.register_utils.set_gdac(scan_parameter_value)
            with self.readout(GDAC=scan_parameter_value,
                              reset_sram_fifo=True,
                              fill_buffer=True,
                              clear_buffer=True,
                              callback=self.handle_data):
                scan_loop(self,
                          command=cal_lvl1_command,
                          repeat_command=self.n_injections_gdac,
                          mask_steps=self.mask_steps,
                          enable_mask_steps=self.enable_mask_steps_gdac,
                          enable_double_columns=None,
                          same_mask_for_all_dc=self.same_mask_for_all_dc,
                          eol_function=None,
                          digital_injection=False,
                          enable_shift_masks=self.enable_shift_masks,
                          disable_shift_masks=self.disable_shift_masks,
                          restore_shift_masks=True,
                          mask=None,
                          double_column_correction=self.pulser_dac_correction)

            occupancy_array, _, _ = np.histogram2d(*convert_data_array(
                data_array_from_data_iterable(self.fifo_readout.data),
                filter_func=logical_and(is_fe_word, is_data_record),
                converter_func=get_col_row_array_from_data_record_array),
                                                   bins=(80, 336),
                                                   range=[[1, 80], [1, 336]])
            occ_array_sel_pixels = np.ma.array(
                occupancy_array,
                mask=np.logical_not(np.ma.make_mask(select_mask_array))
            )  # take only selected pixel into account by using the mask
            occ_array_desel_pixels = np.ma.array(
                occupancy_array, mask=np.ma.make_mask(select_mask_array)
            )  # take only de-selected pixel into account by using the inverted mask
            median_occupancy = np.ma.median(occ_array_sel_pixels)
            noise_occupancy = np.ma.median(occ_array_desel_pixels)
            occupancy_almost_zero = np.allclose(median_occupancy, 0)
            no_noise = np.allclose(noise_occupancy, 0)
            if no_noise and not occupancy_almost_zero and abs(
                    median_occupancy - self.n_injections_gdac /
                    2) < abs(occupancy_best - self.n_injections_gdac / 2):
                occupancy_best = median_occupancy
                gdac_best = self.register_utils.get_gdac()
                self.occ_array_sel_pixels_best = occ_array_sel_pixels.copy()
                self.occ_array_desel_pixels_best = occ_array_desel_pixels.copy(
                )

            if self.plot_intermediate_steps:
                plot_three_way(self.occ_array_sel_pixel.transpose(),
                               title="Occupancy (GDAC " +
                               str(scan_parameter_value) + ")",
                               x_axis_title='Occupancy',
                               filename=self.plots_filename,
                               maximum=self.n_injections_gdac)

            if no_noise and not occupancy_almost_zero and median_occupancy >= median_occupancy_last_step and median_occupancy >= self.n_injections_gdac / 2:
                break
            if no_noise and not occupancy_almost_zero:
                median_occupancy_last_step = median_occupancy
            else:
                median_occupancy_last_step = 0.0

        self.register_utils.set_gdac(gdac_best, send_command=False)
        median_occupancy = occupancy_best
        self.gdac_best = self.register_utils.get_gdac()

        if abs(median_occupancy -
               self.n_injections_gdac / 2) > self.max_delta_threshold:
            if np.all((((self.gdac_best & (1 << np.arange(
                    self.register.global_registers['Vthin_AltFine']
                ['bitlength'] + self.register.global_registers['Vthin_AltFine']
                ['bitlength'])))) > 0).astype(int) == 0):
                if self.fail_on_warning:
                    raise RuntimeWarning(
                        'Selected GDAC bits reached minimum value')
                else:
                    logging.warning('Selected GDAC bits reached minimum value')
            else:
                if self.fail_on_warning:
                    raise RuntimeWarning(
                        'Global threshold tuning failed. Delta threshold = %.2f > %.2f. Vthin_AltCoarse / Vthin_AltFine = %d / %d'
                        % (abs(median_occupancy - self.n_injections_gdac / 2),
                           self.max_delta_threshold,
                           self.register.get_global_register_value(
                               "Vthin_AltCoarse"),
                           self.register.get_global_register_value(
                               "Vthin_AltFine")))
                else:
                    logging.warning(
                        'Global threshold tuning failed. Delta threshold = %.2f > %.2f. Vthin_AltCoarse / Vthin_AltFine = %d / %d',
                        abs(median_occupancy - self.n_injections_gdac / 2),
                        self.max_delta_threshold,
                        self.register.get_global_register_value(
                            "Vthin_AltCoarse"),
                        self.register.get_global_register_value(
                            "Vthin_AltFine"))
        else:
            logging.info(
                'Tuned GDAC to Vthin_AltCoarse / Vthin_AltFine = %d / %d',
                self.register.get_global_register_value("Vthin_AltCoarse"),
                self.register.get_global_register_value("Vthin_AltFine"))
Exemple #21
0
    def scan(self):
        def bits_set(int_type):
            int_type = int(int_type)
            position = 0
            bits_set = []
            while(int_type):
                if(int_type & 1):
                    bits_set.append(position)
                position += 1
                int_type = int_type >> 1
            return bits_set

        # calculate selected pixels from the mask and the disabled columns
        select_mask_array = np.zeros(shape=(80, 336), dtype=np.uint8)
        if not self.enable_mask_steps_feedback:
            self.enable_mask_steps_feedback = range(self.mask_steps)
        for mask_step in self.enable_mask_steps_feedback:
            select_mask_array += make_pixel_mask(steps=self.mask_steps, shift=mask_step)
        for column in bits_set(self.register.get_global_register_value("DisableColumnCnfg")):
            logging.info('Deselect double column %d' % column)
            select_mask_array[column, :] = 0

        cal_lvl1_command = self.register.get_commands("CAL")[0] + self.register.get_commands("zeros", length=40)[0] + self.register.get_commands("LV1")[0]

        self.write_target_charge()

        for feedback_bit in self.feedback_tune_bits:  # reset all feedback bits
            self.set_prmp_vbpf_bit(feedback_bit, bit_value=0)

        additional_scan = True
        tot_mean_best = 0.0
        feedback_best = self.register.get_global_register_value("PrmpVbpf")
        feedback_tune_bits = self.feedback_tune_bits[:]
        for feedback_bit in feedback_tune_bits:
            if self.stop_run.is_set():
                break
            if additional_scan:
                self.set_prmp_vbpf_bit(feedback_bit, bit_value=1)
                logging.info('PrmpVbpf setting: %d, set bit %d = 1', self.register.get_global_register_value("PrmpVbpf"), feedback_bit)
            else:
                self.set_prmp_vbpf_bit(feedback_bit, bit_value=0)
                logging.info('PrmpVbpf setting: %d, set bit %d = 0', self.register.get_global_register_value("PrmpVbpf"), feedback_bit)

            scan_parameter_value = self.register.get_global_register_value("PrmpVbpf")

            with self.readout(PrmpVbpf=scan_parameter_value, fill_buffer=True):
                scan_loop(self,
                          command=cal_lvl1_command,
                          repeat_command=self.n_injections_feedback,
                          mask_steps=self.mask_steps,
                          enable_mask_steps=self.enable_mask_steps_feedback,
                          enable_double_columns=None,
                          same_mask_for_all_dc=self.same_mask_for_all_dc,
                          eol_function=None,
                          digital_injection=False,
                          enable_shift_masks=self.enable_shift_masks,
                          disable_shift_masks=self.disable_shift_masks,
                          restore_shift_masks=True,
                          mask=None,
                          double_column_correction=self.pulser_dac_correction)

            data = convert_data_array(array=self.read_data(), filter_func=is_data_record, converter_func=get_col_row_tot_array_from_data_record_array)
            col_row_tot_array = np.column_stack(data)
            occupancy_array, _, _ = np.histogram2d(col_row_tot_array[:, 0], col_row_tot_array[:, 1], bins=(80, 336), range=[[1, 80], [1, 336]])
            occupancy_array = np.ma.array(occupancy_array, mask=np.logical_not(np.ma.make_mask(select_mask_array)))  # take only selected pixel into account by creating a mask
            occupancy_array = np.ma.masked_where(occupancy_array > self.n_injections_feedback, occupancy_array)
            col_row_tot_hist = np.histogramdd(col_row_tot_array, bins=(80, 336, 16), range=[[1, 80], [1, 336], [0, 15]])[0]
            tot_mean_array = np.average(col_row_tot_hist, axis=2, weights=range(0, 16)) * sum(range(0, 16)) / self.n_injections_feedback
            tot_mean_array = np.ma.array(tot_mean_array, mask=occupancy_array.mask)
            # keep noisy pixels out
            mean_tot = np.ma.mean(tot_mean_array)

            if abs(mean_tot - self.target_tot) < abs(tot_mean_best - self.target_tot):
                tot_mean_best = mean_tot
                feedback_best = self.register.get_global_register_value("PrmpVbpf")

            logging.info('Mean ToT = %.2f', mean_tot)
            tot_array = col_row_tot_array[:, 2]
            self.tot_hist, _ = np.histogram(a=tot_array, range=(0, 16), bins=16)
            if self.plot_intermediate_steps:
                plot_tot(hist=self.tot_hist, title='ToT distribution (PrmpVbpf ' + str(scan_parameter_value) + ')', filename=self.plots_filename)

#             if abs(mean_tot - self.target_tot) < self.max_delta_tot and feedback_bit > 0:  # abort if good value already found to save time
#                 logging.info('Good result already achieved, skipping missing bits')
#                 break

            if feedback_bit > 0:
                # TODO: if feedback is to high, no hits
                if mean_tot < self.target_tot:
                    self.set_prmp_vbpf_bit(feedback_bit, bit_value=0)
                    logging.info('Mean ToT = %.2f < %.2f ToT, set bit %d = 0', mean_tot, self.target_tot, feedback_bit)
                else:
                    logging.info('Mean ToT = %.2f > %.2f ToT, keep bit %d = 1', mean_tot, self.target_tot, feedback_bit)
            elif feedback_bit == 0:
                if additional_scan:  # scan bit = 0 with the correct value again
                    additional_scan = False
                    last_mean_tot = mean_tot
                    last_tot_hist = self.tot_hist.copy()
                    feedback_tune_bits.append(0)  # bit 0 has to be scanned twice
                else:
                    logging.info('Measured %.2f with bit 0 = 0 and %.2f with bit 0 = 1', mean_tot, last_mean_tot)
                    if(abs(mean_tot - self.target_tot) > abs(last_mean_tot - self.target_tot)):  # if bit 0 = 0 is worse than bit 0 = 1, so go back
                        logging.info('Set bit 0 = 1')
                        self.set_prmp_vbpf_bit(0, bit_value=1)
                        self.tot_hist = last_tot_hist.copy()
                        mean_tot = last_mean_tot
                    else:
                        logging.info('Keep bit 0 = 0')

        # select best Feedback value
        if abs(mean_tot - self.target_tot) > abs(tot_mean_best - self.target_tot):
            logging.info("Binary search converged to non-optimal value, apply best Feedback value, change PrmpVbpf from %d to %d", self.register.get_global_register_value("PrmpVbpf"), feedback_best)
            mean_tot = tot_mean_best
            self.register.set_global_register_value("PrmpVbpf", feedback_best)

        self.feedback_best = self.register.get_global_register_value("PrmpVbpf")

        if abs(mean_tot - self.target_tot) > 2 * self.max_delta_tot and not self.stop_run.is_set():
            if np.all((((self.feedback_best & (1 << np.arange(self.register.global_registers['PrmpVbpf']['bitlength'])))) > 0).astype(int)[self.feedback_tune_bits] == 1):
                if self.fail_on_warning:
                    raise RuntimeWarning('Selected Feedback bits reached maximum value')
                else:
                    logging.warning('Selected Feedback bits reached maximum value')
            elif np.all((((self.feedback_best & (1 << np.arange(self.register.global_registers['PrmpVbpf']['bitlength'])))) > 0).astype(int)[self.feedback_tune_bits] == 0):
                if self.fail_on_warning:
                    raise RuntimeWarning('Selected Feedback bits reached minimum value')
                else:
                    logging.warning('Selected Feedback bits reached minimum value')
            else:
                if self.fail_on_warning:
                    raise RuntimeWarning('Global feedback tuning failed. Delta ToT = %.2f > %.2f. PrmpVbpf = %d' % (abs(mean_tot - self.target_tot), self.max_delta_tot, self.register.get_global_register_value("PrmpVbpf")))
                else:
                    logging.warning('Global feedback tuning failed. Delta ToT = %.2f > %.2f. PrmpVbpf = %d', abs(mean_tot - self.target_tot), self.max_delta_tot, self.register.get_global_register_value("PrmpVbpf"))
        else:
            logging.info('Tuned PrmpVbpf to %d', self.register.get_global_register_value("PrmpVbpf"))
Exemple #22
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()
Exemple #23
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")
Exemple #24
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"))
    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")
Exemple #26
0
    def scan(self):
        enable_mask_steps = []

        cal_lvl1_command = self.register.get_commands(
            "CAL")[0] + self.register.get_commands(
                "zeros", length=40)[0] + self.register.get_commands("LV1")[0]

        self.write_target_charge()
        additional_scan = True
        last_tot_mean_array = np.zeros(
            shape=self.register.get_pixel_register_value("FDAC").shape,
            dtype=self.register.get_pixel_register_value("FDAC").dtype)

        self.set_start_fdac()

        self.tot_mean_best = np.full(
            shape=(80, 336), fill_value=0
        )  # array to store the best occupancy (closest to Ninjections/2) of the pixel
        self.fdac_mask_best = self.register.get_pixel_register_value("FDAC")
        fdac_tune_bits = self.fdac_tune_bits[:]
        for scan_parameter_value, fdac_bit in enumerate(fdac_tune_bits):
            if self.stop_run.is_set():
                break
            if additional_scan:
                self.set_fdac_bit(fdac_bit, bit_value=1)
                logging.info('FDAC setting: bit %d = 1', fdac_bit)
            else:
                self.set_fdac_bit(fdac_bit, bit_value=0)
                logging.info('FDAC setting: bit %d = 0', fdac_bit)

            self.write_fdac_config()

            with self.readout(FDAC=scan_parameter_value, fill_buffer=True):
                scan_loop(self,
                          command=cal_lvl1_command,
                          repeat_command=self.n_injections_fdac,
                          mask_steps=self.mask_steps,
                          enable_mask_steps=enable_mask_steps,
                          enable_double_columns=None,
                          same_mask_for_all_dc=self.same_mask_for_all_dc,
                          eol_function=None,
                          digital_injection=False,
                          enable_shift_masks=self.enable_shift_masks,
                          disable_shift_masks=self.disable_shift_masks,
                          restore_shift_masks=True,
                          mask=None,
                          double_column_correction=self.pulser_dac_correction)

            data = convert_data_array(
                array=self.read_data(),
                filter_func=is_data_record,
                converter_func=get_col_row_tot_array_from_data_record_array)
            col_row_tot = np.column_stack(data)
            tot_array = np.histogramdd(col_row_tot,
                                       bins=(80, 336, 16),
                                       range=[[1, 80], [1, 336], [0, 15]])[0]
            tot_mean_array = np.average(
                tot_array, axis=2, weights=range(0, 16)) * sum(range(
                    0, 16)) / self.n_injections_fdac
            select_better_pixel_mask = abs(
                tot_mean_array - self.target_tot) <= abs(self.tot_mean_best -
                                                         self.target_tot)
            self.tot_mean_best[select_better_pixel_mask] = tot_mean_array[
                select_better_pixel_mask]
            fdac_mask = self.register.get_pixel_register_value("FDAC")
            self.fdac_mask_best[select_better_pixel_mask] = fdac_mask[
                select_better_pixel_mask]

            if fdac_bit > 0:
                pixel_with_too_small_mean_tot_mask = tot_mean_array < self.target_tot
                fdac_mask[pixel_with_too_small_mean_tot_mask] = fdac_mask[
                    pixel_with_too_small_mean_tot_mask] & ~(
                        1 << fdac_bit)  # unset FDAC bit, increase ToT
                self.register.set_pixel_register_value("FDAC", fdac_mask)
            elif fdac_bit == 0:
                if additional_scan:  # scan bit = 0 with the correct value again
                    additional_scan = False
                    fdac_tune_bits.append(0)  # bit 0 has to be scanned twice
                else:
                    pass

        if not self.stop_run.is_set():
            self.register.set_pixel_register_value(
                "FDAC", self.fdac_mask_best)  # set value for meta scan
            self.write_fdac_config()