def __init__(self):
        self.command_history = []
        self.biases = InstrumentBiases()

        with StripConnection() as conn:
            # We need to load the configuration from the server, as it
            # includes vital information about the board
            # configuration. This information is needed to properly
            # initialize the hardware
            self.conf = Config()
            self.conf.load(conn)

            self.command_emitter = JSONCommandEmitter(conn)

        conn.post_command = self.command_emitter
        self.conn = conn
Beispiel #2
0
    def __init__(
        self,
        config,
        post_command,
        board_calibration=None,
        instrument_biases=None,
        board_name="R",
        pol_list=None,
        bias_file_name: Optional[str] = None,
    ):

        self.post_command = post_command
        self.conf = config
        self.board = board_name
        self.pols = pol_list

        if board_calibration:
            self.bc = board_calibration
        else:
            self.bc = None
            log.info(
                f"Looking for an appropriate board configuration, there are {len(self.conf.boards)} choices"
            )
            log.info("The choices are: {0}".format(", ".join(
                ['"{0}"'.format(x["name"]) for x in self.conf.boards])))
            for cur_board in self.conf.boards:
                if cur_board["name"] == board_name:
                    id = cur_board["id"]
                    try:
                        filename = os.path.join(
                            os.path.dirname(__file__),
                            "..",
                            "data",
                            self.conf.get_board_bias_file(id),
                        )
                        log.info(
                            f'Using biases for board "{board_name}" from "{filename}"'
                        )
                        self.bc = read_board_xlsx(filename)
                        if self.pols is None:
                            self.pols = [
                                (x, i)
                                for (i, x) in enumerate(cur_board["pols"])
                            ]
                        break
                    except Exception as exc:
                        log.warning(
                            f'No suitable bias file for board "{board_name}" found: {exc}'
                        )
                        if self.pols is None:
                            self.pols = [
                                "{0}{1}".format(board_name, x)
                                for x in range(7)
                            ]

            if not self.bc:
                log.warning(
                    f'Using default calibration for board "{board_name}"')
                self.bc = BoardCalibration()

        if instrument_biases is not None:
            self.ib = instrument_biases
        else:
            assert bias_file_name
            log.info(f'Loading instrument biases from file "{bias_file_name}"')
            self.ib = InstrumentBiases(filename=bias_file_name)
Beispiel #3
0
class SetupBoard(object):
    def __init__(
        self,
        config,
        post_command,
        board_calibration=None,
        instrument_biases=None,
        board_name="R",
        pol_list=None,
        bias_file_name: Optional[str] = None,
    ):

        self.post_command = post_command
        self.conf = config
        self.board = board_name
        self.pols = pol_list

        if board_calibration:
            self.bc = board_calibration
        else:
            self.bc = None
            log.info(
                f"Looking for an appropriate board configuration, there are {len(self.conf.boards)} choices"
            )
            log.info("The choices are: {0}".format(", ".join(
                ['"{0}"'.format(x["name"]) for x in self.conf.boards])))
            for cur_board in self.conf.boards:
                if cur_board["name"] == board_name:
                    id = cur_board["id"]
                    try:
                        filename = os.path.join(
                            os.path.dirname(__file__),
                            "..",
                            "data",
                            self.conf.get_board_bias_file(id),
                        )
                        log.info(
                            f'Using biases for board "{board_name}" from "{filename}"'
                        )
                        self.bc = read_board_xlsx(filename)
                        if self.pols is None:
                            self.pols = [
                                (x, i)
                                for (i, x) in enumerate(cur_board["pols"])
                            ]
                        break
                    except Exception as exc:
                        log.warning(
                            f'No suitable bias file for board "{board_name}" found: {exc}'
                        )
                        if self.pols is None:
                            self.pols = [
                                "{0}{1}".format(board_name, x)
                                for x in range(7)
                            ]

            if not self.bc:
                log.warning(
                    f'Using default calibration for board "{board_name}"')
                self.bc = BoardCalibration()

        if instrument_biases is not None:
            self.ib = instrument_biases
        else:
            assert bias_file_name
            log.info(f'Loading instrument biases from file "{bias_file_name}"')
            self.ib = InstrumentBiases(filename=bias_file_name)

    def board_setup(self):
        url = self.conf.get_rest_base() + "/slo"

        cmd = {}
        cmd["board"] = self.board
        cmd["pol"] = "BOARD"
        cmd["type"] = "BIAS"
        cmd["method"] = "SET"
        cmd["timeout"] = 500

        for (addr, datum) in [("POL_RCL", [23295]), ("CAL_RCL", [23295])]:
            cmd["base_addr"] = addr
            cmd["data"] = datum

            if not self.post_command(url, cmd):
                log.warning(f"Unable to post command {addr}")
                return

    def enable_electronics(self, polarimeter, delay_sec=0.5, mode=5):
        url = self.conf.get_rest_base() + "/slo"

        {
            "board": "R",
            "type": "DAQ",
            "pol": "BOARD",
            "base_addr": "CLK_REF",
            "method": "GET",
            "size": 1,
            "timeout": 500,
        }

        cmd = {}
        cmd["board"] = self.board
        cmd["method"] = "SET"
        cmd["timeout"] = 500

        for c in [
            ("POL_PWR", 1, "BIAS", polarimeter),
            ("DAC_REF", 1, "BIAS", polarimeter),
            ("POL_MODE", mode, "BIAS", polarimeter),
            ("CLK_REF", 0, "DAQ", "BOARD"),
            ("PHASE_SRC", 0, "BIAS", "BOARD"),
        ]:
            base_addr, data, typeof, pol = c
            cmd["base_addr"] = base_addr
            cmd["data"] = [data]
            cmd["type"] = typeof
            cmd["pol"] = pol

            if not self.post_command(url, cmd):
                print(
                    f"WARNING: command {c[0]}={c[1]} gave an error",
                    file=sys.stderr,
                    flush=True,
                )
                break

        cmd["base_addr"] = "PRE_EN"
        cmd["pol"] = polarimeter
        cmd["type"] = "DAQ"
        cmd["data"] = [1]

        if not self.post_command(url, cmd):
            return

    def enable_all_electronics(self, mode=5):
        for (p, _) in self.pols:
            self.polarimeter_on(polarimeter=p, mode=mode)

    def disable_electronics(self, polarimeter, delay_sec=0.5):
        url = self.conf.get_rest_base() + "/slo"

        cmd = {}
        cmd["board"] = self.board
        cmd["type"] = "BIAS"
        cmd["method"] = "SET"
        cmd["timeout"] = 500

        cmd["pol"] = polarimeter

        cmd["base_addr"] = "PRE_EN"
        cmd["type"] = "DAQ"
        cmd["data"] = [0]

        if not self.post_command(url, cmd):
            return

        cmd["type"] = "BIAS"
        for c in [("POL_MODE", 0), ("DAC_REF", 0), ("POL_PWR", 0)]:
            cmd["base_addr"] = c[0]
            cmd["data"] = [c[1]]

            if not self.post_command(url, cmd):
                return

    def disable_all_electronics(self):
        for (p, _) in self.pols:
            self.polariemter_off(polarimeter=p)

    def turn_on_detector(self,
                         polarimeter,
                         detector_idx,
                         bias=0,
                         offset=0,
                         gain=0):
        assert detector_idx in [0, 1, 2, 3]

        url = self.conf.get_rest_base() + "/slo"

        cmd = {}
        cmd["board"] = self.board
        cmd["type"] = "DAQ"
        cmd["method"] = "SET"
        cmd["timeout"] = 500

        cmd["pol"] = polarimeter

        cmd["base_addr"] = f"DET{detector_idx}_BIAS"
        cmd["data"] = [bias]
        if not self.post_command(url, cmd):
            return

        cmd["base_addr"] = f"DET{detector_idx}_OFFS"
        cmd["data"] = [offset]
        # if not self.post_command(url, cmd):
        #    return

        cmd["base_addr"] = f"DET{detector_idx}_GAIN"
        cmd["data"] = [gain]
        # if not self.post_command(url, cmd):
        #    return

    def set_phsw_status(self, polarimeter, phsw_idx, status):
        assert phsw_idx in [0, 1, 2, 3]

        url = self.conf.get_rest_base() + "/slo"

        cmd = {}
        cmd["board"] = self.board
        cmd["type"] = "BIAS"
        cmd["method"] = "SET"
        cmd["timeout"] = 500

        cmd["pol"] = polarimeter

        cmd["base_addr"] = f"PIN{phsw_idx}_CON"
        cmd["data"] = [status]
        if not self.post_command(url, cmd):
            return

    def set_phsw_bias(self, polarimeter, index, vpin, ipin):
        url = self.conf.get_rest_base() + "/slo"

        cmd = {}
        cmd["board"] = self.board
        cmd["type"] = "BIAS"
        cmd["method"] = "SET"
        cmd["timeout"] = 500

        calib = self.bc[f"Pol{get_polarimeter_index(polarimeter) + 1}"]

        cmd["pol"] = polarimeter
        cmd["base_addr"] = f"VPIN{index}_SET"
        cmd["data"] = [
            physical_units_to_adu(vpin,
                                  calib["PIN DIODES"]["SET VOLTAGE"][index],
                                  1.0)
        ]

        if not self.post_command(url, cmd):
            return

        cmd["base_addr"] = f"IPIN{index}_SET"
        cmd["data"] = [
            physical_units_to_adu(ipin,
                                  calib["PIN DIODES"]["SET CURRENT"][index],
                                  1.0)
        ]

        if not self.post_command(url, cmd):
            return

    def setup_bias(self,
                   polarimeter,
                   index,
                   bias_dict,
                   param_name,
                   excel_entry,
                   value=None,
                   step=1):
        """Set the value of a bias to some calibrated value (e.g., μA, mV)

        Args:
            polarimeter (str): Name of the polarimeter, e.g., `I0`

            index (int): Zero-based index of the bias to set. For
                `VD0`, the index is 0.

            bias_dict (dict): Dictionary associating `index` with the
                bias name used in the Excel file containing the
                calibration parameters. It is needed only if you pass
                ``None`` to `value`.

            param_name (str): Base name of the parameter to set. If
                you want to set up ``ID0``, you must pass here ``ID``;
                the index will be appended automatically.

            excel_entry (2-tuple): Pair of strings identifying the
                name of the sheet and the row containing the
                calibration factors for this bias parameter. For
                instance, for drain currents you must pass the tuple
                ``("DRAIN", "SET CURRENT")``.

            value (float or None): Calibrated value (i.e., in physical
                units) to set. If `value` is ``None``, the default
                nominal value of the bias (read from Excel files) will
                be used.

            step (float): Multiplication factor used with `value`.
                This value is multiplied by the parameter `step`
                before the application, so ``value=None, step=0.5`
                will set the bias to 50% of its nominal value.

        """
        url = self.conf.get_rest_base() + "/slo"

        pol_index = get_polarimeter_index(polarimeter)

        bc = self.ib.get_biases(module_name=polarimeter)
        calib = self.bc[f"Pol{pol_index + 1}"]
        if not value:
            value = bc.__getattribute__(bias_dict[index])

        title1, title2 = excel_entry

        cmd = {
            "board":
            self.board,
            "type":
            "BIAS",
            "method":
            "SET",
            "timeout":
            500,
            "pol":
            polarimeter,
            "base_addr":
            f"{param_name}{index}_SET",
            "data":
            [physical_units_to_adu(value, calib[title1][title2][index], step)],
        }

        if not self.post_command(url, cmd):
            return

    def setup_lna_bias(self,
                       polarimeter,
                       lna,
                       bias_dict,
                       param_name,
                       excel_entry,
                       value=None,
                       step=1):
        self.setup_bias(
            polarimeter=polarimeter,
            index=get_lna_num(lna),
            bias_dict=bias_dict,
            param_name=param_name,
            excel_entry=excel_entry,
            value=value,
            step=step,
        )

    def setup_VD(self, polarimeter, lna, value=None, step=1):
        vd = {0: "vd0", 1: "vd1", 2: "vd2", 3: "vd3", 4: "vd4", 5: "vd5"}

        self.setup_lna_bias(
            polarimeter=polarimeter,
            lna=lna,
            bias_dict=vd,
            param_name="VD",
            excel_entry=("DRAIN", "SET VOLTAGE"),
            value=None,
            step=step,
        )

    def setup_VG(self, polarimeter, lna, value=None, step=1):
        vg = {
            0: "vg0",
            1: "vg1",
            2: "vg2",
            3: "vg3",
            4: "vg4",
            5: "vg5",
            "4A": "vg4a",
            "5A": "vg5a",
        }

        self.setup_lna_bias(
            polarimeter=polarimeter,
            lna=lna,
            bias_dict=vg,
            param_name="VG",
            excel_entry=("GATE", "SET VOLTAGE"),
            value=value,
            step=step,
        )

    def setup_ID(self, polarimeter, lna, value=None, step=1):
        id = {0: "id0", 1: "id1", 2: "id2", 3: "id3", 4: "id4", 5: "id5"}

        self.setup_lna_bias(
            polarimeter=polarimeter,
            lna=lna,
            bias_dict=id,
            param_name="ID",
            excel_entry=("DRAIN", "SET CURRENT"),
            value=value,
            step=step,
        )

    def setup_all_VDs(self, step=1):
        for pol, _ in self.pols:
            self.setup_VD(polarimeter=pol, step=step)

    def setup_all_VGs(self, step=1):
        for pol, _ in self.pols:
            self.setup_VG(polarimeter=pol, step=step)

    def setup_all_IDs(self, step=1):
        for pol, _ in self.pols:
            self.setup_ID(polarimeter=pol, step=step)

    def change_file(self):
        url = self.conf.get_rest_base() + "/command"

        cmd = {"command": "round_hdf5_files"}

        if not self.post_command(url, cmd):
            return

    def log(self, msg, level="INFO"):
        url = self.conf.get_rest_base() + "/log"
        cmd = {"level": level, "message": str(msg)}

        if not self.post_command(url, cmd):
            return
    def run(self):
        # Turn on the polarimeter(s)
        for cur_board in STRIP_BOARD_NAMES:
            # Append the sequence of commands to turnon this board to
            # the JSON object
            # self.command_emitter.command_list += self.turn_on_board(cur_board)
            pass

        # Verification step
        with StripTag(
                conn=self.command_emitter,
                name="IVTEST_VERIFICATION_TURNON",
        ):
            # Wait a while after having turned on all the boards
            self.wait(seconds=10)

        # Load the matrices of the unit-test measurements done in
        # Bicocca and save them in "self.bicocca_data"
        self.bicocca_test = get_unit_test(args.bicocca_test_id)
        module_name = InstrumentBiases().polarimeter_to_module_name(
            self.bicocca_test.polarimeter_name)

        log.info(
            "Test %d for %s (%s) loaded from %s, is_cryogenic=%s",
            args.bicocca_test_id,
            self.bicocca_test.polarimeter_name,
            module_name,
            self.bicocca_test.url,
            str(self.bicocca_test.is_cryogenic),
        )

        self.bicocca_data = load_unit_test_data(self.bicocca_test)
        assert isinstance(self.bicocca_data, UnitTestDC)

        log.info(
            " The polarimeter %s corresponds to module %s",
            self.bicocca_test.polarimeter_name,
            module_name,
        )

        calibr = CalibrationTables()
        defaultBias = InstrumentBiases()
        lna_list = get_lna_list(pol_name=self.bicocca_test.polarimeter_name)

        #--> First test: ID vs VD --> For each VG, we used VD curves
        self.conn.tag_start(name=f"IVTEST_IDVD_{module_name}")

        for lna in lna_list:
            lna_number = get_lna_num(lna)
            #Read default configuration
            with StripTag(
                    conn=self.command_emitter,
                    name=f"{module_name}_{lna}_READDEFAULT_VGVD",
            ):
                # read bias in mV
                default_vg_adu = calibr.physical_units_to_adu(
                    polarimeter=module_name,
                    hk="vgate",
                    component=lna,
                    value=defaultBias.get_biases(module_name,
                                                 param_hk=f"VG{lna_number}"),
                )

                # read bias in mV
                default_vd_adu = calibr.physical_units_to_adu(
                    polarimeter=module_name,
                    hk="vdrain",
                    component=lna,
                    value=defaultBias.get_biases(module_name,
                                                 param_hk=f"VD{lna_number}"),
                )

            #Get the data matrix and the Gate Voltage vector.
            matrixIDVD = self.bicocca_data.components[lna].curves["IDVD"]

            #from V to mV
            vgate = np.mean(matrixIDVD["GateV"], axis=0) * 1000
            selvg = vgate >= -360
            vgate = vgate[selvg]

            # For each Vg, we have several curves varing Vd
            for vg_idx, vg in enumerate(vgate):
                vg_adu = calibr.physical_units_to_adu(
                    polarimeter=module_name,
                    hk="vgate",
                    component=lna,
                    value=vg,
                )
                self.conn.set_vg(
                    polarimeter=module_name,
                    lna=lna,
                    value_adu=vg_adu,
                )

                #from V to mV
                curve_vdrain = matrixIDVD["DrainV"][:, vg_idx] * 1000

                for vd_idx, vd in enumerate(curve_vdrain):
                    vd_adu = calibr.physical_units_to_adu(
                        polarimeter=module_name,
                        hk="vdrain",
                        component=lna,
                        value=vd,
                    )
                    self.conn.set_vd(
                        polarimeter=module_name,
                        lna=lna,
                        value_adu=vd_adu,
                    )

                    with StripTag(
                            conn=self.command_emitter,
                            name=
                            f"{module_name}_{lna}_SET_VGVD_{vg_idx}_{vd_idx}",
                            comment=f"VG_{vg:.2f}mV_VD_{vd:.2f}mV",
                    ):
                        self.conn.set_hk_scan(allboards=True)
                        self.conn.wait(self.waittime_perconf_s)

            # Back to the default values of vd and vg (for each LNA)
            with StripTag(
                    conn=self.command_emitter,
                    name=f"{module_name}_{lna}_BACK2DEFAULT_VGVD",
            ):
                self.conn.set_vg(
                    polarimeter=module_name,
                    lna=lna,
                    value_adu=default_vg_adu,
                )
                self.conn.set_vd(
                    polarimeter=module_name,
                    lna=lna,
                    value_adu=default_vd_adu,
                )
                self.conn.wait(self.waittime_perconf_s)

        self.conn.tag_stop(name=f"IVTEST_IDVD_{module_name}")

        #
        #--> Second test: ID vs VG --> For each VD, we used VG curves

        self.conn.tag_start(name=f"IVTEST_IDVG_{module_name}")

        for lna in lna_list:
            lna_number = get_lna_num(lna)
            #Read default configuration
            with StripTag(
                    conn=self.command_emitter,
                    name=f"{module_name}_{lna}_READDEFAULT_VDVG",
            ):
                # read bias in mV
                default_vg_adu = calibr.physical_units_to_adu(
                    polarimeter=module_name,
                    hk="vgate",
                    component=lna,
                    value=defaultBias.get_biases(module_name,
                                                 param_hk=f"VG{lna_number}"),
                )

                # read bias in mV
                default_vd_adu = calibr.physical_units_to_adu(
                    polarimeter=module_name,
                    hk="vdrain",
                    component=lna,
                    value=defaultBias.get_biases(module_name,
                                                 param_hk=f"VD{lna_number}"),
                )
            #Get the data matrix and the Gate Voltage vector.
            matrixIDVG = self.bicocca_data.components[lna].curves["IDVG"]

            #from V to mV
            vdrain = np.mean(matrixIDVG["DrainV"], axis=0) * 1000

            # For each Vd, we have several curves varing Vg
            for vd_idx, vd in enumerate(vdrain):
                vd_adu = calibr.physical_units_to_adu(
                    polarimeter=module_name,
                    hk="vdrain",
                    component=lna,
                    value=vd,
                )
                self.conn.set_vg(
                    polarimeter=module_name,
                    lna=lna,
                    value_adu=vd_adu,
                )

                #from V to mV
                curve_vgate = matrixIDVG["GateV"][:, vd_idx] * 1000.
                selcurvg = curve_vgate >= -360
                curve_vgate = vgate[selvg]

                for vg_idx, vg in enumerate(curve_vgate):
                    vg_adu = calibr.physical_units_to_adu(
                        polarimeter=module_name,
                        hk="vgate",
                        component=lna,
                        value=vg,
                    )
                    self.conn.set_vd(
                        polarimeter=module_name,
                        lna=lna,
                        value_adu=vg_adu,
                    )

                    with StripTag(
                            conn=self.command_emitter,
                            name=f"{module_name}_{lna}_VDVG_{vd_idx}_{vg_idx}",
                            comment=f"VD_{vd:0.2f}mV_VG_{vg:.2f}mV",
                    ):
                        #
                        self.conn.set_hk_scan(allboards=True)
                        self.conn.wait(self.waittime_perconf_s)
            # Back to the default values of vd and vg (for each LNA)
            with StripTag(
                    conn=self.command_emitter,
                    name=f"IVTEST_IDVG_{module_name}_{lna}_BACK2DEFAULT_VDVG",
            ):
                self.conn.set_vg(
                    polarimeter=module_name,
                    lna=lna,
                    value_adu=default_vg_adu,
                )
                self.conn.set_vd(
                    polarimeter=module_name,
                    lna=lna,
                    value_adu=default_vd_adu,
                )

                self.conn.wait(self.waittime_perconf_s)

        self.conn.tag_stop(name=f"IVTEST_IDVG_{module_name}")
            f"""Usage: python {sys.argv[0]} BOARD_CAL COMMAND CHANNEL CONF POL_NAME

BOARD_CAL: name of the Excel file containing the Biases
COMMAND: either "turn_on" or "turn_off"
CHANNEL: name of the channel (e.g., "G0")
CONF: channel configuration (e.g., "Pol1")
POL_NAME: name of the polarimeter (e.g., "STRIP15")
""")
        sys.exit(-1)

    command, pol_chan, pol_chan_conf, pol_name = sys.argv[2:]

    d = read_board_xlsx(sys.argv[1])
    calib = d[pol_chan_conf]

    pol_biases = InstrumentBiases()
    bc = pol_biases.get_biases(polarimeter_name=pol_name)

    con = Connection()
    con.login()

    conf = Config()
    conf.load(con)
    time.sleep(0.5)

    if command == "turnon":
        turn_on_board(con, conf)
        turn_on(con, conf, pol_chan)

        setup_VD(con, conf, bc, calib, pol_chan, 1.0)
        setup_VG(con, conf, bc, calib, pol_chan, 1.0)
Beispiel #6
0
    def run(self):
        # Turn on the polarimeter(s)
        for cur_board in STRIP_BOARD_NAMES:
            # Append the sequence of commands to turnon this board to
            # the JSON object
            # self.command_emitter.command_list += self.turn_on_board(cur_board)
            pass

        # Verification step
        with StripTag(conn=self.command_emitter,
                      name="IVTEST_VERIFICATION_TURNON"):
            # Wait a while after having turned on all the boards
            self.wait(seconds=10)

        # Load the matriix with the min, max and step for
        # each LNA for each polarimeter
        count_conf = 0
        for pol_name in self.polarimeters:
            module_name = self.inputBiasIV["Module"][pol_name]
            log.info("-->Polarimeter %s (%s)", pol_name, module_name)
            calibr = CalibrationTables()
            defaultBias = InstrumentBiases()
            lna_list = get_lna_list(pol_name=pol_name)

            # --> First test: ID vs VD --> For each VG, we used VD curves
            self.conn.tag_start(name=f"IVTEST_{module_name}")

            for lna in lna_list:
                lna_number = get_lna_num(lna)
                # Read default configuration
                with StripTag(
                        conn=self.command_emitter,
                        name=f"{module_name}_{lna}_READDEFAULT_VGVD",
                ):
                    # read bias in mV
                    default_vg_adu = calibr.physical_units_to_adu(
                        polarimeter=module_name,
                        hk="vgate",
                        component=lna,
                        value=getattr(defaultBias.get_biases(module_name),
                                      f"vg{lna_number}"),
                    )

                    # read bias in mV
                    default_vd_adu = calibr.physical_units_to_adu(
                        polarimeter=module_name,
                        hk="vdrain",
                        component=lna,
                        value=getattr(defaultBias.get_biases(module_name),
                                      f"vd{lna_number}"),
                    )

                # Get the data matrix and the Gate Voltage vector.
                # in mV
                vgate = self.get_bias_curve(pol_name, lna)
                vdrain = np.arange(0, 900, 50)
                count_conf += len(vgate) * len(vdrain)

                # For each Vg, we have several curves varing Vd
                for vg_idx, vg in enumerate(vgate):
                    vg_adu = calibr.physical_units_to_adu(
                        polarimeter=module_name,
                        hk="vgate",
                        component=lna,
                        value=vg)
                    self.conn.set_vg(polarimeter=module_name,
                                     lna=lna,
                                     value_adu=vg_adu)

                    for vd_idx, vd in enumerate(vdrain):
                        vd_adu = calibr.physical_units_to_adu(
                            polarimeter=module_name,
                            hk="vdrain",
                            component=lna,
                            value=vd,
                        )
                        self.conn.set_vd(polarimeter=module_name,
                                         lna=lna,
                                         value_adu=vd_adu)

                        with StripTag(
                                conn=self.command_emitter,
                                name=
                                f"{module_name}_{lna}_SET_VGVD_{vg_idx}_{vd_idx}",
                                comment=f"VG_{vg:.2f}mV_VD_{vd:.2f}mV",
                        ):
                            if self.hk_scan == "True":
                                # print(f"hk_scan is {self.hk_scan}")
                                self.conn.set_hk_scan(allboards=True)
                            self.conn.wait(self.waittime_perconf_s)

                # Back to the default values of vd and vg (for each LNA)
                with StripTag(
                        conn=self.command_emitter,
                        name=f"{module_name}_{lna}_BACK2DEFAULT_VGVD",
                ):
                    self.conn.set_vg(polarimeter=module_name,
                                     lna=lna,
                                     value_adu=default_vg_adu)
                    self.conn.set_vd(polarimeter=module_name,
                                     lna=lna,
                                     value_adu=default_vd_adu)
                    self.conn.wait(self.waittime_perconf_s)
                    count_conf += 1

            self.conn.tag_stop(name=f"IVTEST_IDVD_{module_name}")
            log.info(
                "Number of configuration and time [hrs, days]: %s  [%s, %s]\n",
                int(count_conf),
                np.around(count_conf * self.waittime_perconf_s / 3600.0, 1),
                np.around(count_conf * self.waittime_perconf_s / 3600 / 24, 3),
            )