def save_as_netCDF4(self, filename, data):
        """ Saves the data from the polarimeter measurement into a netCDF4 file. """
        self.logger.info(f'Saving into netCDF4 file: {filename}')
        detectors = self.DATA_TYPES_NAME
        self.logger.debug(f'The detectors are {detectors}')

        DATA = []
        for index, unit_name in enumerate(self.DATA_TYPES_UNITS):
            unit = ur(unit_name)
            self.logger.debug(f'The unit for the detector {detectors[index]} is: {unit}')
            DATA.append( data[:,index] * unit )

        self.logger.debug(f'The data to save is: {DATA}')

        # create axes
        axis = np.array(range(np.shape(data)[0]))*ur('')
        extra = {'wavelength':self._wavelength}

        description = 'This is a description of the variables: \n'

        for index, s in enumerate(self.DATA_TYPES):

            to_add = f'{self.DATA_TYPES_NAME[index]} : {s} \n'
            description += to_add

        save_netCDF4(filename, detectors, DATA, axes=(axis, ) , axes_name=('Measurement index',), extra_dims=extra,
                     description = description)
Exemple #2
0
    def set_integration_time(self):
        """This method combines the integration time that the user puts in the spinbox with the unit in the combobox,
        and remembers the pint quantity in the init in self.integration_time.
        It compares it to a max (24 hours) and min (1 s) value.
        """
        self.logger.debug('setting the integration time')

        tijd = self.integration_time_spinbox.value()
        unit = self.time_unit_combobox.currentText()

        local_time = ur(str(tijd) + unit)

        self.logger.debug('local time value: ' + str(local_time))

        if local_time > self.max_time:
            self.logger.debug('time really too much')
            local_time = self.max_time.to(unit)
            self.logger.debug(str(local_time))
            self.integration_time_spinbox.setValue(local_time.m_as(unit))
        elif local_time < 1 * ur('s'):
            self.logger.debug('you need to integrate more time')
            local_time = 1 * ur('s')
            self.integration_time_spinbox.setValue(local_time.m_as('s'))

        self.integration_time = local_time
        self.logger.debug('time remembered is: ' + str(self.integration_time))
    def set_temperature_limits(self):
        """The maximum voltage to put on the piezo scanners depends on the temperature in the cryostat. The user has to give that.
        The maximum ranges from 60V at room temperature to 140V at 4K, and everything in between is linearly interpolated.
        """
        self.logger.debug('The given cryostat temperature is {}K'.format(
            self.temperature))

        a = (140 - 60) / (4 - 300)
        b = 140 - 4 * a

        # possible_temperatures = np.linspace(4,300,20)
        # limits = a*possible_temperatures + b
        # plt.figure()
        # plt.plot(possible_temperatures, limits)
        # plt.show()

        if self.temperature < 4:
            self.logger.warning('Trying to put a temperature below 4K')
        elif self.temperature < 301:
            self.max_dC_level = a * self.temperature + b
            self.max_dC_level = round(self.max_dC_level) * ur('V')
            self.logger.debug('max_dC_level interpolated to {}'.format(
                self.max_dC_level))
        else:
            self.max_dC_level = 60 * ur('V')

        self.logger.debug('Maximum voltage on scanner piezo: {}'.format(
            self.max_dC_level))
        self.max_dC_level_300K = 60 * ur('V')
 def zero_scanners(self):
     """Puts 0V on all three Piezo Scanners.
     """
     self.logger.debug('Putting 0V on every Scanner Piezo.')
     self.move_scanner('XPiezoScanner', 0 * ur('V'))
     self.move_scanner('YPiezoScanner', 0 * ur('V'))
     self.move_scanner('ZPiezoScanner', 0 * ur('V'))
Exemple #5
0
    def set_distance(self):
        """Works similar to set_value method, but now only for the distance spinBox and unit.
        Combines value of spinbox with unit to make pint quantity and checks against maximum value defined up.
        Either applies the dictionary value of the distance, or changes that dictionary value and than applies it.
        """
        distance = self.gui.doubleSpinBox_distance.value()
        unit = self.gui.comboBox_unit.currentText()

        local_distance = ur(str(distance) + unit)
        self.logger.debug('local distance value: ' + str(local_distance))

        if local_distance > self.max_distance:
            self.logger.debug('value too high')
            local_max = self.max_distance.to(unit)
            self.logger.debug(str(local_max))
            self.gui.doubleSpinBox_distance.setValue(local_max.m_as(unit))
            distance = self.gui.doubleSpinBox_distance.value()
        elif local_distance < 0:
            self.logger.debug('value too low')
            self.gui.doubleSpinBox_distance.setValue(0)
            distance = self.gui.doubleSpinBox_distance.value()

        local_distance = ur(str(distance) + unit)  #in case something changed
        self.distance = local_distance
        self.logger.debug('dictionary distance changed to: ' +
                          str(self.distance))
Exemple #6
0
    def __init__(self, thorlabs_instrument, also_close_output=False):
        super().__init__()
        self.logger = logging.getLogger(__name__)

        self.overall_layout = QHBoxLayout()
        self.setLayout(self.overall_layout)

        self.motor = thorlabs_instrument
        self.logger.debug('You are connected to a {}'.format(self.motor.kind_of_device))
        self.title = 'Thorlabs {} GUI'.format(self.motor._name)

        self.saved_position = None
        self.current_position = None

        self.distance = 1.0*ur('mm')

        self.min_distance = -12.0 * ur('mm')
        self.max_distance = 12.0 * ur('mm')

        self.stop = self.stop_moving

        self.initUI()

        self.timer = QTimer()
        self.timer.timeout.connect(self.set_current_motor_position_label)
        self.timer.start(100)       #time in ms

        self.moving_thread = WorkThread(self.motor.move_absolute, self.current_position, True)
    def test_freq(self):
        """ Test the freq command"""
        self.logger.debug('Starting unit_test on freq')
        for F in [10 * ur('Hz'), 10.50 * ur('Hz')]:
            self.inst.freq = F
            assert F == self.inst.freq
            self.logger.info('Freq assertion passed for freq: {}'.format(F))

        self.logger.info('Test Freq passed.')
    def wait_till_finished(self, integration_time, count_channel):
        """| This method should ask the device its status and keep asking until it's finished.
        | However, the remaining time is printed but not shown with the timer in the gui.
        | The loop breaks if self.stop is put to True, which could be done in a higher level with a thread.

        :param integration_time: integration time of histogram **(please don't use the word time)**
        :type integration_time: pint quantity

        :param count_channel: number of channel that is correlated with the sync channel, 1 or 2
        :type count_channel: int

        :return: remaining time in seconds
        :rtype: pint quantity

        """
        # ended = self.hist_ended
        #t = round(float(tijd.magnitude) / 20)

        t = 1  # in s
        total_time_passed = ur('0s')

        self.logger.debug('Ended?: ' + str(self.hist_ended))
        total_time_passed += t * ur('s')

        self.logger.debug('time passed: {}'.format(
            self.show_time_passed(integration_time, total_time_passed)))

        time.sleep(1)

        while self.hist_ended == False:
            self.hist_ended = self.controller.ctc_status
            self.logger.debug('Is the histogram finished? ' +
                              str(self.hist_ended))

            total_time_passed += t * ur('s')
            #this line returns a pint quantity which tells the user how much time the program needs before it can collect the histogram
            self.logger.debug('time passed ' + str(total_time_passed))

            self.show_time_passed(integration_time, total_time_passed)
            self.logger.debug('time_passed value: {}'.format(self.time_passed))

            self.hist = self.controller.histogram(
                int(count_channel),
                False)  #Dont let the histogram memory be cleared
            time.sleep(t)

            if self.stop:
                self.logger.info('Stopping the histogram')
                self.stop = False
                break

        self.logger.debug(
            'Time passed: ' +
            str(self.show_time_passed(integration_time, total_time_passed)))
        self.logger.debug('Ended? ' + str(self.hist_ended))
Exemple #9
0
    def __init__(self, hydra_instrument, draw=None, also_close_output=False):
        super().__init__()
        self.logger = logging.getLogger(__name__)
        self.title = 'Hydraharp400 correlator gui'
        self.left = 50
        self.top = 50
        self.width = 320
        self.height = 200
        self.histogram_number = 0
        self.grid_layout = QGridLayout()
        self.setLayout(self.grid_layout)

        self.hydra_instrument = hydra_instrument

        if type(draw) is dict:
            self.draw = list(draw.values())[0]
        else:
            self.draw = draw

        #default values, could be put in a yml file as well
        self.array_length = 65536
        self.resolution = "1ps"
        self.integration_time = 5 * ur('s')
        self.channel = '0'
        self.time_passed = 0 * ur(
            's')  #which also makes sure that the units are the same

        self.max_time = 24 * ur('hour')
        self.max_length = 65536

        self.endtime = []
        self.time_axis = []
        self.units = 's'

        self.hydra_instrument.configurate()
        self.initUI()

        #This one is to continuously (= every 100ms) show the remaining time
        self.timer = QTimer()
        self.timer.timeout.connect(self.show_time_passed)

        # timer to update
        self.timer_plot = QTimer()
        self.timer_plot.timeout.connect(self.update_plot)

        self.histogram_thread = WorkThread(
            self.hydra_instrument.make_histogram, self.integration_time,
            self.channel)

        self.stop = self.stop_histogram
    def get_position(self, axis):
        """ Asks the position from the controller level. This method is useful in higher levels where you want to display the position.

        :param axis: stepper axis, XPiezoStepper, YPiezoStepper, or XPiezoScanner, etc.
        :type axis: string
        """
        ax = self.attocube_piezo_dict[axis][
            'axis']  # otherwise you keep typing this
        if 'Stepper' in axis:
            self.current_positions[axis] = round(
                self.controller.getPosition(ax) * ur('nm').to('mm'), 6)
        elif 'Scanner' in axis:
            self.current_positions[axis] = round(
                self.controller.getDcLevel(ax) * ur('mV'), 6)
    def exposure_time(self):
        """
        attribute: Exposure Time.

        :getter: Returns the Exposure Time set in Winspec
        :setter: Attempts to updates the Exposure Time in Winspec if required. Gives warning if failed.
        :type: Pint Quantity of unit time
        """

        winspec_exposure_units = [ur('us'), ur('ms'), ur('s'), ur('min')]
        exp_pint_unit = winspec_exposure_units[ self.controller.exp_get('EXPOSURETIME_UNITS')[0] -1 ]
        exp_value = self.controller.exp_get('EXPOSURETIME')[0]
        self._exposure_time = exp_value * exp_pint_unit

        return self._exposure_time
Exemple #12
0
    def __init__(self, hydra_instrument):
        """Hydraharp aligning
        """

        super().__init__()
        self.logger = logging.getLogger(__name__)
        self.title = 'Hydraharp Aligning GUI'
        self.left = 50
        self.top = 50
        self.width = 500
        self.height = 250
        self.hydra_instrument = hydra_instrument

        self.exp_type = 'Finite'
        self.pausetime = 50*ur('ms')
        self.lengthaxis = 10*ur('s')
        self.sync = True
        self.chan1 = False
        self.chan2 = False

        self.sync_counts = 0.0
        self.counts1 = 0.0
        self.counts2 = 0.0

        self.running = False
        self.Sync_counts_array = []
        self.Counts1_array = []
        self.Counts2_array = []
        self.time_axis = []

        self.default_name = 'counts.txt'
        self.path = 'D:\\LabSoftware\\Data\\'

        self.something_selected = False

        self.pen = pg.mkPen(color=(0, 0, 0))  # makes the plotted lines black

        name = 'aligning.ui'
        gui_folder = os.path.dirname(os.path.abspath(__file__))
        gui_file = os.path.join(gui_folder, name)
        self.logger.info('Loading the GUI file: {}'.format(gui_file))
        self.gui = uic.loadUi(gui_file, self)

        self.initUI()

        self.timer = QTimer()
        self.timer.timeout.connect(self.ask_counts)
        self.timer.start(100)       #time in ms
Exemple #13
0
    def position(self):
        """| Asks the position to the controller and returns that.
        | Units depend on the kind of device; either mm or degrees.
        | Remembers the current_position as declared in the init.

        :return: position in mm or degrees
        :rtype: pint quantity
        """
        pos = self.controller.position
        if self.kind_of_device == 'waveplate':
            pos = pos * ur('degrees')
        elif self.kind_of_device == 'stage':
            pos = pos * ur('mm')

        self.current_position = pos
        return pos
Exemple #14
0
 def amplitude(self):
     """ Gets the amplitude value
     :return: voltage amplitude value
     :rtype: pint quantity
     """
     self.logger.debug('Getting the amplitude.')
     return self.controller.amplitude * ur('volts')
Exemple #15
0
    def set_distance(self):
        """| Reads the value that the user filled in the spinbox and combines it with the unit to make a pint quantity.
        | The pint quantity is saved in self.distance.
        | Also compares the wanted distance with the maximum and minimum values,
        | which are set in the init or changed to degrees in make_distance_spinbox.
        | If the user input is too high or low, the spinbox is changed to the maximum or minimum value.
        """
        value = self.distance_spinbox.value()
        unit = self.unit_combobox.currentText()

        local_distance = ur(str(value)+unit)
        self.logger.debug('local distance value {}'.format(self.distance))
        self.logger.debug("{}".format(value > self.max_distance.m_as(unit)))

        if value > self.max_distance.m_as(unit):
            self.logger.debug('value too high')
            local_max = self.max_distance.to(unit)
            self.logger.debug(str(local_max))
            self.distance_spinbox.setValue(local_max.m_as(unit))
        elif value < self.min_distance.m_as(unit):
            self.logger.debug('value too low')
            local_min = self.min_distance.to(unit)
            self.distance_spinbox.setValue(local_min.m_as(unit))

        self.distance = local_distance
        self.logger.debug('dictionary distance changed to: ' + str(self.distance))
Exemple #16
0
    def position(self):
        """| Asks the position to the controller and returns that.

        """
        pos = self.real_controller.qPOS()
        position=float(pos['A'])
        position=ur(str(position)+"mm")
        return position
    def sync_rate(self):
        """Asks the controller the rate of counts on the sync channel and adds units.

        :return: counts per second on the sync channel
        :rtype: pint quantity
        """
        self.sync = self.controller.sync_rate() * ur('cps')
        return self.sync
Exemple #18
0
    def delta_wav_changed(self):
        self.delta_wavelength = self.gui.doubleSpinBox_wavelength_delta.value(
        ) * ur('nm')

        self.gui.doubleSpinBox_wavelength.setSingleStep(
            self.delta_wavelength.m_as('nm'))

        self.logger.debug('Changed the wavelength step')
    def get_wavelength(self):
        """ asks the device the current wavelength.

        :return: current wavelength
        :rtype: pint quantity
        """
        ans = self.controller.get_wavelength()
        w = ans * ur('nm')
        return w
 def go_to_input(self):
     selected_motor = str(self.motor_combobox.currentText())
     try:
         go_to_input = self.input_textfield.text() * ur('micrometer')
         self.motor_bag[selected_motor].move_absolute(float(go_to_input.magnitude))
         self.set_current_motor_label()
     except ValueError:
         print("The input is not a float, change this")
         return
Exemple #21
0
    def __init__(self, anc350_instrument, also_close_output=False):
        """Attocube
        """
        super().__init__()
        self.logger = logging.getLogger(__name__)
        self.title = 'Attocube GUI'
        self.anc350_instrument = anc350_instrument

        name = 'attocube.ui'
        gui_folder = os.path.dirname(os.path.abspath(__file__))
        gui_file = os.path.join(gui_folder, name)
        self.logger.debug('Loading the GUI file: {}'.format(gui_file))
        self.gui = uic.loadUi(gui_file, self)

        self.max_amplitude_V = 60
        self.max_frequency = 2000
        self.max_dclevel_V = 60 * ur(
            'V')  #Pay attention: this max only goes for 4K,
        self.max_dcLevel_mV_300K = 60 * ur(
            'V')  #at room temperature use 60V as max
        self.max_distance = 5 * ur('mm')

        self.current_positions = {}

        self.current_axis = 'X,Y Piezo Stepper'
        self.current_move = 'step'
        self.direction = 'left'
        self.distance = 0 * ur('um')

        self.settings = {
            'amplitudeX': 30,
            'amplitudeY': 40,
            'amplitudeZ': 30,
            'frequencyX': 1000,
            'frequencyY': 1000,
            'frequencyZ': 1000
        }

        self.temperature = 300

        self.scanner_unitX = 'V'
        self.scanner_unitY = 'V'
        self.scanner_unitZ = 'V'

        self.dcX = 1 * ur(self.scanner_unitX)
        self.dcY = 1 * ur(self.scanner_unitY)
        self.dcZ = 0 * ur(self.scanner_unitZ)

        self.stop = self.stop_moving

        self.initUI()

        #This one is to continuously (= every 100ms) show the position of the axes
        self.timer = QTimer()
        self.timer.timeout.connect(self.show_position)
        self.timer.start(100)  #time in ms

        self.moving_thread = WorkThread(self.anc350_instrument.move_to,
                                        self.current_axis, self.distance)
    def capacitance(self, axis):
        """Measures the capacitance of the stepper or scanner; no idea why you would want to do that.

        :param axis: scanner axis to be set, XPiezoScanner, YPiezoScanner, XPiezoStepper, etc.
        :type axis: string
        """
        capacitance = self.controller.capMeasure(
            self.attocube_piezo_dict[axis]['axis']) * ur('mF')
        capacitance = round(capacitance.to('F'), 3)
        self.logger.debug(axis + ': ' + str(capacitance))
Exemple #23
0
    def __init__(self, settings):
        """
        Init of the class.

        It needs a settings dictionary that contains the following fields (mandatory)

            * port: COM port name where the LCC25 is connected
            * enable: logical to say if the initialize enables the output
            * dummy: logical to say if the connection is real or dummy (True means dummy)
            * controller: this should point to the controller to use and with / add the name of the class to use

        Note: When you set the setting 'dummy' = True, the controller to be loaded is the dummy one by default,
        i.e. the class will automatically overwrite the 'controller' with 'hyperion.controller.thorlabs.lcc25/LccDummy'

        Example:

            settings = {'port':'COM8', 'enable': None, 'dummy' : True,
                                   'controller': 'hyperion.controller.thorlabs.lcc25/Lcc'}


        """
        super().__init__(settings)
        self.logger = logging.getLogger(__name__)
        self._port = settings['port']

        # property
        self._output = settings['enable']
        self._mode = None
        self._freq = None
        self._wavelength = 532 * ur('nm')  # default wavelength
        self.MODES = ['Modulation', 'Voltage1', 'Voltage2', 'QWP']

        self.logger.info(
            'Initializing Variable Waveplate with settings: {}'.format(
                settings))
        # this is to load the calibration file
        self.calibration = {}
        self.logger.debug('Get the source path')
        cal_file = os.path.join(
            package_path, 'instrument', 'polarization',
            'lookup_table_qwp_voltage_calibration_2019-03-15.txt')
        self.logger.info(
            'Using Variable Waveplate QWP calibration file: {}'.format(
                cal_file))
        self.load_calibration(cal_file)

        # initialize
        self.initialize()  # mandatory!
        if self._output is None:
            self._output = self.output
        else:
            self.output = self._output

        # mode
        self._mode = self.mode
 def count_rate(self, channel):
     """ Asks the controller the rate of counts on the count channels and adds units.
     
     :param channel: count rate channel 0 or 1 (1 or 2 on device) connected to the photon counter
     :type channel: int
     
     :return: count rate that is read out in counts per second
     :rtype: pint quantity
     """
     self.count = self.controller.count_rate(channel) * ur('cps')
     return self.count
Exemple #25
0
    def load_calibration(self, cal_file):
        """ This method loads the calibration file cal_file

            :param cal_file: calibration file complete path, including extension (txt expected)
            :type cal_file: string
        """
        self.logger.debug(
            'Trying to load the calibration file: {}'.format(cal_file))
        cal = np.loadtxt(cal_file)
        self.logger.info('Loaded the calibration file: {}'.format(cal_file))
        self.calibration['file'] = cal_file
        self.calibration['original_data'] = cal
        aux = cal[:, 0]
        self.calibration['wavelength'] = cal[aux.argsort(), 0] * ur('nm')
        self.calibration['wavelength_limits'] = (
            np.min(self.calibration['wavelength']),
            np.max(self.calibration['wavelength']))
        self.calibration['qwp'] = cal[aux.argsort(), 1] * ur('volt')
        self.calibration['qwp error'] = cal[aux.argsort(), 2] * ur('volt')
        #self.logger.debug('Calibration dictionary: {}'.format(self.calibration))
        self.logger.info('Done loading calibration.')
Exemple #26
0
    def configure_stepper(self):
        """Configures the stepper, using the amplitude and frequency that had been set in set_frequency and set_amplitude.
        After configuration, the box with all the different moves is chosen
        and the get_move is run to set the layout fit for the current move.
        """
        self.logger.info('configurating stepper')
        if 'Z' in self.current_axis:
            self.anc350_instrument.configure_stepper(
                'ZPiezoStepper', self.settings['amplitudeZ'] * ur('V'),
                self.settings['frequencyZ'] * ur('Hz'))
        else:
            self.anc350_instrument.configure_stepper(
                'XPiezoStepper', self.settings['amplitudeX'] * ur('V'),
                self.settings['frequencyX'] * ur('Hz'))
            self.anc350_instrument.configure_stepper(
                'YPiezoStepper', self.settings['amplitudeY'] * ur('V'),
                self.settings['frequencyY'] * ur('Hz'))

        self.gui.groupBox_actions.setObjectName("Colored_actions")
        self.gui.groupBox_actions.setStyleSheet(
            "QGroupBox#Colored_actions {border: 1px solid blue; border-radius: 9px;}"
        )

        self.gui.stackedWidgetMoving.setEnabled(True)

        self.get_move()
    def given_step(self, axis, direction, amount):
        """| Moves by a number of steps that theoretically should be determined by the set amplitude and frequency; in practice it's different.
        | *You have to give it a lot of time, things break if you ask too much whether it is finished yet.*

        :param axis: stepper axis to be set, XPiezoStepper, YPiezoStepper or ZPiezoStepper
        :type axis: string

        :param direction: direction to move: forward = 0, backward = 1
        :type direction: integer

        :param amount: amount of steps that you want to take
        :type amount: integer
        """
        Steps = []
        self.logger.info(
            'moving ' + axis + ' by ' + str(amount) + ' steps of stepwidth ' +
            str(self.Stepwidth[self.attocube_piezo_dict[axis]['axis']]))

        if amount == 1:
            self.logger.debug('You are making 1 step')
            self.controller.moveSingleStep(
                self.attocube_piezo_dict[axis]['axis'], direction)
            self.get_position(axis)
        else:
            for ii in range(amount):
                self.controller.moveSingleStep(
                    self.attocube_piezo_dict[axis]['axis'], direction)
                time.sleep(0.5)
                position = self.controller.getPosition(
                    self.attocube_piezo_dict[axis]['axis']) * ur('nm')
                self.logger.debug('step ' + str(ii) + ': we are now at ' +
                                  str(round(position.to('mm'), 6)))
                Steps.append(position.m_as('nm'))
                self.get_position(axis)

            Steps = np.asarray(Steps)
            Stepsize = np.diff(Steps)
            av_steps = np.mean(Stepsize)
            self.logger.debug('average step size is ' +
                              str(round(av_steps) * ur('nm')))
Exemple #28
0
    def get_voltage_low(self, channel):
        """
        Gets the low voltage value of the channel.

        :param channel: Channel number. Range depends on device
        :type channel: int

        :return: current low voltage for the channel
        :rtype: pint quantity
        """
        value = self.controller.get_voltage_low(channel)
        value = value * ur('volt')
        return value
Exemple #29
0
    def get_frequency(self, channel):
        """ This functions gets the frequency output for the channel

        :param channel: number of channel. it can be 1 or 2 for this model
        :type channel: int

        :return: frequency in the channel
        :rtype: pint quantity

        """
        f = self.controller.get_frequency(channel)
        f = f * ur('hertz')
        return f
Exemple #30
0
    def get_voltage_limits(self, channel):
        """ Gets the set values for the voltage limits, high and low.

        :param channel:  number of channel. it can be 1 or 2 for this model
        :type channel: int

        :return: array with [high_value, low_value]
        :rtype: pint quantity array

        """
        values = self.controller.get_voltage_limits(channel)
        self.logger.debug(
            'Received value from the controller: {}'.format(values))

        if not self.dummy:
            value = values * ur('volt')
        else:
            value = 10000 * ur('volt')
            self.logger.warning(
                'The voltage is invented since your are in dummy mode')

        return value