def __init__(self, **kwargs):
        self.__channel_1 = IT6432Connection(1)
        self.__channel_2 = IT6432Connection(2)
        self.__channel_3 = IT6432Connection(3)

        self.power_supplies = (self.__channel_1, self.__channel_2,
                               self.__channel_3)

        self.__set_currents = [0, 0, 0]

        if 'num_steps' in kwargs.keys():
            self.__ramp_num_steps = kwargs['num_steps']
        else:
            self.__ramp_num_steps = 5
Esempio n. 2
0
def closeConnection(channel_1: IT6432Connection,
                    channel_2=None,
                    channel_3=None):
    """Close the connection with the current sources."""
    channel_1._write("system:local")
    channel_1.close()

    if channel_2 is not None:
        channel_2._write("system:local")
        channel_2.close()

    if channel_3 is not None:
        channel_3._write("system:local")
        channel_3.close()
Esempio n. 3
0
def openConnection(channel_1: IT6432Connection,
                   channel_2=None,
                   channel_3=None):
    """
    Open a connection to a IT6432 current source.

    Returns:
        IT6432Connection: Instances of connection objects representing each channel.
    """
    channel_1.connect()
    channel_1._write("system:remote")

    if channel_2 is not None:
        channel_2.connect()
        channel_2._write("system:remote")

    if channel_3 is not None:
        channel_3.connect()
        channel_3._write("system:remote")
Esempio n. 4
0
def rampVoltageSimple(connection: IT6432Connection,
                      set_voltage,
                      new_voltage,
                      step_size=0.01):
    """
    Helper function to take care of setting the voltage.

    Args:
        connection (IT6432Connection):
        set_voltage (float): Voltage that is set right now.
        new_voltage (float): Target voltage.
        step_size (float, optional): Defaults to 0.01.
        threshold (float, optional): Defaults to 0.02.
    """
    if connection.channel != 2:
        postfix_v = "V"
    else:
        postfix_v = ""
    threshold = 2 * step_size
    connection._write(f"voltage {set_voltage}" + postfix_v)
    diff_v = new_voltage - set_voltage
    sign = np.sign(diff_v)
    while abs(diff_v) >= threshold:
        set_voltage = set_voltage + sign * step_size
        connection._write(f"voltage {set_voltage}" + postfix_v)
        diff_v = new_voltage - set_voltage
        sign = np.sign(diff_v)

    connection._write(f"voltage {new_voltage}" + postfix_v)
def rampVoltageSimple(connection: IT6432Connection,
                      set_voltage: float = 0,
                      new_voltage: float = 0.3,
                      steps: int = 5):
    """
    Helper function to take care of ramping the voltage.

    Args:
        connection (IT6432Connection):
        set_voltage (float): Voltage that is set right now.
        new_voltage (float): Target voltage.
        steps (int, optional): Defaults to 5.
    """
    if connection.channel != 2:
        postfix_v = "V"
    else:
        postfix_v = ""

    connection._write(f"voltage {set_voltage}" + postfix_v)
    diff_v = new_voltage - set_voltage
    step_size = diff_v / steps

    for _ in range(steps):
        set_voltage = set_voltage + step_size
        connection._write(f"voltage {set_voltage}" + postfix_v)
        diff_v = new_voltage - set_voltage

    # threshold = 0.05
    # while abs(diff_v) >= threshold:
    #     set_voltage = set_voltage + step_size
    #     connection._write(f"voltage {set_voltage}" + postfix_v)
    #     diff_v = new_voltage - set_voltage
    #     step_size = 0.05 * diff_v

    connection._write(f"voltage {new_voltage}" + postfix_v)
Esempio n. 6
0
def demagnetizeCoils(
    channel_1: IT6432Connection,
    channel_2: IT6432Connection,
    channel_3: IT6432Connection,
    current_config=[1, 1, 1],
    # factor=0.5
):
    """
    Try to eliminate any hysteresis effects by applying a slowly oscillating and decaying
    voltage to the coils.

    Args:
        factor (float): A factor 0<factor<1 to reduce the applied field by.
    """
    # if factor >= 1:
    #     factor = 0.99
    steps = np.array([0, 1, 2, 3, 4])
    bounds = 0.475 * np.outer(current_config, np.exp(-steps))

    channel_1._write('current 5.01A')
    channel_2._write('current 5.01')
    channel_3._write('current 5.01A')

    thread_pool = [None, None, None]
    sign = -1

    for i in range(bounds.shape[1]):
        voltages = getMeasurement(channel_1,
                                  channel_2,
                                  channel_3,
                                  meas_quantity='voltage')
        thread_pool[0] = threading.Thread(
            target=rampVoltageSimple,
            name='currentController_1',
            args=[channel_1, voltages[0], sign * bounds[0, i]],
            kwargs={'step_size': 0.06})

        thread_pool[1] = threading.Thread(
            target=rampVoltageSimple,
            name='currentController_2',
            args=[channel_2, voltages[1], sign * bounds[1, i]],
            kwargs={'step_size': 0.06})

        thread_pool[2] = threading.Thread(
            target=rampVoltageSimple,
            name='currentController_3',
            args=[channel_3, voltages[2], sign * bounds[2, i]],
            kwargs={'step_size': 0.06})
        for thread in thread_pool:
            thread.start()

        for thread in thread_pool:
            thread.join()
        sign *= -1
        sleep(0.1)

    disableCurrents(channel_1, channel_2, channel_3)
Esempio n. 7
0
def getMeasurement(channel_1: IT6432Connection,
                   channel_2=None,
                   channel_3=None,
                   meas_type=[""],
                   meas_quantity=["current"]):
    """
    Get DC current/power/voltage values from each channel

    Returns: a list of all the currents (or an error code)
    """
    command = "measure:"
    quantities = ["current", "voltage", "power"]
    types = ["", "acdc", "max", "min"]
    if meas_quantity not in quantities:
        meas_quantity = "current"
    if meas_type not in types:
        meas_type = ""

        command += meas_quantity
        if meas_type != "":
            command += ":" + meas_type[0]
        command += "?"

    measured = []
    res = channel_1.query(command)
    if isinstance(res, list):
        res = res[0]
    measured.append(float(res))

    if channel_2 is not None:
        res = channel_2.query(command)
        if isinstance(res, list):
            res = res[0]
        measured.append(float(res))

    if channel_3 is not None:
        res = channel_3.query(command)
        if isinstance(res, list):
            res = res[0]
        measured.append(float(res))

    return measured
Esempio n. 8
0
def rampVoltage(connection: IT6432Connection,
                new_voltage,
                new_current,
                step_size=0.01):
    """
    Ramp voltage to a new specified value. The current should not be directly set, due
    to the load inductance instead it is a limit for the voltage increase. Like this, it
    is possible to ensure that the current takes the exact desired value without causing
    the voltage protection to trip.

    Args:
        connection (IT6432Connection):
        new_voltage (float): Target voltage
        new_current (float): Target current
        step_size (float, optional): Voltage increment. Defaults to 0.01.
    """
    logging.basicConfig(filename="voltage_ramp.log",
                        level=logging.DEBUG,
                        force=True)
    logging.info("now ramping current in channel %s", connection.channel)

    if connection.channel != 2:
        postfix_v = "V"
        postfix_i = "A"
    else:
        postfix_v = ""
        postfix_i = ""

    connection.clrOutputProt()

    if connection.query("output?") == "0":
        connection._write("voltage 0" + postfix_v)
        connection._write("output 1")

    if new_current > connection.current_lim:
        new_current = connection.current_lim
    if new_current < 0.002 or abs(new_voltage) < 0.001:
        new_current = 0.002
        new_voltage = 0
    if abs(new_voltage) > connection.voltage_lim:
        new_voltage = connection.voltage_lim

    meas_voltage = getMeasurement(connection, meas_quantity="voltage")[0]
    meas_current = getMeasurement(connection, meas_quantity="current")[0]

    logging.debug(
        f"actual voltage: {meas_voltage}V, actual current: {meas_current}A")
    logging.debug(
        f"target voltage: {new_voltage}V, desired current: {new_current}A")

    if new_current - abs(meas_current) < 0:
        intermediate_step = 0.4 * new_current if new_current > 0.01 else 0
        rampVoltageSimple(connection, meas_voltage, intermediate_step,
                          step_size)

    repeat_count = 0
    meas_current_queue = [meas_current, 0]
    while not (abs(meas_current) < new_current or repeat_count >= 5):
        meas_current_queue.insert(
            0,
            getMeasurement(connection, meas_quantity="current")[0])
        meas_current_queue.pop(2)
        repeat = abs(meas_current_queue[0] - meas_current_queue[1]) < 0.002
        if repeat:
            repeat_count += 1
        else:
            repeat_count = 0

    connection._write(f"current {new_current}" + postfix_i)

    if new_current < 0.002 or abs(new_voltage) < 0.001:
        connection._write("output 0")
    else:
        meas_voltage = getMeasurement(connection, meas_quantity="voltage")[0]
        rampVoltageSimple(connection, meas_voltage, new_voltage, step_size)

    messages = connection.getStatus()
    if "QER0" in messages.keys():
        logging.info(messages["QER0"] + ", channel: %s", connection.channel)
    if "QER4" in messages.keys():
        logging.info(messages["QER4"] + ", channel: %s", connection.channel)
    if "OSR1" in messages.keys():
        logging.info(messages["OSR1"] + ", channel: %s", connection.channel)
Esempio n. 9
0
            args=[channel_3, voltages[2], sign * bounds[2, i]],
            kwargs={'step_size': 0.06})
        for thread in thread_pool:
            thread.start()

        for thread in thread_pool:
            thread.join()
        sign *= -1
        sleep(0.1)

    disableCurrents(channel_1, channel_2, channel_3)


########## test stuff out ##########
if __name__ == "__main__":
    channel_1 = IT6432Connection(1)
    channel_2 = IT6432Connection(2)
    channel_3 = IT6432Connection(3)
    openConnection(channel_1, channel_2, channel_3)

    # setCurrents(channel_1, channel_2, channel_3, np.array([1, 1, 1]))
    # sleep(15)

    # channel_2._write('voltage:prot 9.05')
    # channel_2._write('curr 1')
    # rampVoltage(channel_2, 1.7, 3.4, 0.05)
    # print(channel_1.outputInfo())
    # channel_2.saveSetup(0)
    # channel_3.saveSetup(0)

    # print(channel_3.outputInfo())
def rampVoltage(connection: IT6432Connection, new_voltage: float,
                new_current: float, steps: int):
    """
    Ramp voltage to a new specified value. The current should not be directly set due
    to the load inductance, instead it is a limiter for the voltage increase. Like this, it
    is possible to ensure that the current takes the exact desired value without causing
    the voltage protection to trip.

    Args:
        channel (1,2 or 3): channel on which to change the voltage.
        new_voltage (float): Target voltage
        new_current (float): Target current
        steps (int): Voltage increment.
    """
    connection.clrOutputProt()

    if connection.channel != 2:
        postfix_v = "V"
        postfix_i = "A"
    else:
        postfix_v = ""
        postfix_i = ""

    if connection.query("output?") == "0":
        connection._write("voltage 0" + postfix_v + ";:output 1")

    if new_current > connection.current_lim:
        new_current = connection.current_lim
    if new_current < 0.002 or abs(new_voltage) < 0.001:
        new_current = 0.002
        new_voltage = 0
    if abs(new_voltage) > connection.voltage_lim:
        new_voltage = connection.voltage_lim

    meas_voltage = connection.getMeasurement(meas_quantity="voltage")
    meas_current = connection.getMeasurement(meas_quantity="current")

    if new_current - abs(meas_current) < 0:
        intermediate_step = 0.4 * new_current if new_current > 0.02 else 0
        rampVoltageSimple(connection, meas_voltage, intermediate_step, steps)

    repeat_count = 0
    meas_current_queue = [meas_current, 0]
    while not (abs(meas_current) < new_current or repeat_count >= 5):
        meas_current_queue.insert(
            0, connection.getMeasurement(meas_quantity="current"))
        meas_current_queue.pop(2)
        repeat = abs(meas_current_queue[0] - meas_current_queue[1]) < 0.002
        if repeat:
            repeat_count += 1
        else:
            repeat_count = 0

    connection._write(f"current {new_current}" + postfix_i)

    if new_current < 0.002 or abs(new_voltage) < 0.001:
        connection._write("output 0")
    else:
        meas_voltage = connection.getMeasurement(meas_quantity="voltage")
        rampVoltageSimple(connection, meas_voltage, new_voltage, steps)
def runCurrents(config_list, t=[], subdir='default_location', demagnetize=False, temp_meas=False):
    """
    Set arbitrary currents on each channel. Includes timed mode, magnetic field and temperature measurements
    and setting new currents.

    Args:
        config_list (list of (np.array() size 3)): list of current configs in [A]. Make sure not to give more than 3!
        t (int): timer duration list. multiple timers -> different currents will be set for different
                           amounts of time. If zero, user can decide whether to change the current or deactivate it. Defaults to [].
        subdir (str, optional): Default location where measurements are stored. Defaults to 'default_location'.
        demagnetize (bool, optional): if true, demagnetization will run every time the field is deactivated.
        temp_meas (bool, optional): if true, temperature will be measured.
    """
    global desCurrents

    channel_1 = IT6432Connection(1)
    channel_2 = IT6432Connection(2)
    channel_3 = IT6432Connection(3)
    openConnection(channel_1, channel_2, channel_3)

    # on until interrupted by user
    if len(t) == 0 or t[0] == 0:
        channels = config_list[0]
        for i in range(len(channels)):
            desCurrents[i] = round(channels[i], 3)

        setCurrents(channel_1, channel_2, channel_3, desCurrents)
        # wait until user presses enter
        c1 = '0'
        while c1 != 'q':
            c1 = input(
                '[q] to disable currents\n[c]: get currents\n[r]: Set new currents\n[s]: monitor magnetic field\n')
            if c1 == 'c':
                currentsList = getMeasurement(channel_1, channel_2, channel_3)
                print(
                    f'current 1: {currentsList[0]:.3f}, current 2: {currentsList[1]:.3f}, current 3: {currentsList[2]:.3f}')
            elif c1 == 'r':
                channels[0] = input('Channel 1 current: ')
                channels[1] = input('Channel 2 current: ')
                channels[2] = input('Channel 3 current: ')
                # handle new inputs
                for i in range(len(channels)):
                    try:
                        desCurrents[i] = round(channels[i], 3)
                    except BaseException:
                        print(
                            "non-integer value entered, setting channel {} to 0".format(i + 1))
                        desCurrents[i] = 0

                setCurrents(channel_1, channel_2, channel_3, desCurrents)
########################### ONLY WITH METROLAB SENSOR ###########################
##########################################################################
            elif c1 == 's':
                with MetrolabTHM1176Node(period=0.05, range='0.3 T', average=20) as node:
                    test_thread = p.inputThread(1)
                    test_thread.start()
                    sleep(0.1)
                    while p.flags[0]:
                        newBMeasurement = sensor_to_magnet_coordinates(
                            np.array(node.measureFieldmT()))
                        # newBMeasurement = np.random.randn((3)) * 10
                        B_magnitude = np.linalg.norm(newBMeasurement)
                        theta = np.degrees(
                            np.arccos(newBMeasurement[2] / B_magnitude))
                        phi = np.degrees(np.arctan2(
                            newBMeasurement[1], newBMeasurement[0]))
                        if p.flags[0]:
                            print(
                                f'\rMeasured B field: ({newBMeasurement[0]:.2f}, {newBMeasurement[1]:.2f}, '
                                f'{newBMeasurement[2]:.2f}) / In polar coordinates: ({B_magnitude:.2f}, '
                                f'{theta:.2f}°, {phi:.2f}°)    ', sep='', end='', flush=True)
                        sleep(0.5)

                p.threadLock.acquire()
                p.flags.insert(0, 1)
                p.threadLock.release()
##########################################################################
    else:
        # initialize temperature sensor and measurement routine and start measuring
        if temp_meas:
            arduino = ArduinoUno('COM7')
            measure_temp = threading.Thread(
                target=arduino.getTemperatureMeasurements, kwargs={
                    'print_meas': False})
            measure_temp.start()

        # use only with Metrolab sensor
        try:
            duration = int(input('Duration of measurement (default is 10s): '))
        except BaseException:
            duration = 10
        try:
            period = float(input('Measurement trigger period (default is 0.5s, 0.01-2.2s): '))
        except BaseException:
            period = 0.5

        if period < 0.1:
            block_size = 10
        elif period < 0.05:
            block_size = 30
        elif period >= 0.5:
            block_size = 1

        # print(duration, period)
        params = {
            'name': 'BFieldMeasurement',
            'block_size': block_size,
            'period': period,
            'duration': duration,
            'averaging': 3}
        faden = p.myMeasThread(10, **params)

        gotoPosition()
        savedir = input('Name of directory where this measurement will be saved: ')

        faden.start()

        for index, timer in enumerate(t):
            channels = config_list[index]
            for i in range(len(channels)):
                desCurrents[i] = round(channels[i], 3)
            # print(desCurrents)
            setCurrents(channel_1, channel_2, channel_3, desCurrents)
            if timer < 500:
                countdown = p.timerThread(11, timer)
                countdown.start()
                sleep(timer)
                countdown.join()
            else:
                countdown = p.timerThread(11, timer)
                countdown.start()
                starttime = time()
                while time() - starttime < timer:
                    pause = min(500, timer - (time() - starttime))
                    sleep(pause)
                    getMeasurement(channel_1, channel_2, channel_3)
                countdown.join()

        faden.join()

        if temp_meas:
            arduino.stop = True
            measure_temp.join()
            saveTempData(
                arduino.data_stack,
                directory=r'C:\Users\Magnebotix\Desktop\Qzabre_Vector_Magnet\1_Version_2_Vector_Magnet\1_data_analysis_interpolation\Data_Analysis_For_VM\temperature_measurements',
                filename_suffix='temp_meas_repeatability')

        saveLoc = rf'C:\Users\Magnebotix\Desktop\Qzabre_Vector_Magnet\1_Version_2_Vector_Magnet\1_data_analysis_interpolation\Data_Analysis_For_VM\data_sets\{savedir}'
        strm(p.return_dict(), saveLoc, now=True)

    if demagnetize:
        demagnetizeCoils(channel_1, channel_2, channel_3, config_list[-1])
    disableCurrents(channel_1, channel_2, channel_3)
    closeConnection(channel_1, channel_2, channel_3)