示例#1
0
class PiezoStageHW(HardwareComponent):

    ## Define name of this hardware plug-in

    def setup(self):
        # Define your hardware settings here.
        # These settings will be displayed in the GUI and auto-saved with data files
        self.name = 'piezostage'
        self.settings.New('x_position', dtype=float, unit='um')
        self.settings.New('y_position', dtype=float, unit='um')

        self.settings.New('x_abs',
                          dtype=float,
                          initial=0,
                          unit='um',
                          vmin=0,
                          vmax=100)
        self.settings.New('y_abs',
                          dtype=float,
                          initial=0,
                          unit='um',
                          vmin=0,
                          vmax=100)

        self.settings.New('x_rel', dtype=float, initial=0, unit='um')
        self.settings.New('y_rel', dtype=float, initial=0, unit='um')

        self.add_operation('center_stage', self.center_piezo)
        self.add_operation('absolute_movement', self.abs_mov)
        self.add_operation('relative_movement', self.rel_mov)

    def connect(self):
        # Open connection to the device:
        self.pi_device = GCSDevice("E-710")  # Creates a Controller instant
        self.pi_device.ConnectNIgpib(board=0,
                                     device=4)  # Connect to GPIB board

        self.axes = self.pi_device.axes[
            0:2]  # selecting x and y axis of the stage
        self.pi_device.INI()
        self.pi_device.REF(axes=self.axes)
        self.pi_device.SVO(axes=self.axes,
                           values=[True, True
                                   ])  # Turn on servo control for both axes

        #Connect settings to hardware:
        LQ = self.settings.as_dict()
        LQ["x_position"].hardware_read_func = self.getX
        LQ["y_position"].hardware_read_func = self.getY

        LQ["x_position"].hardware_set_func = self.abs_mov
        LQ["y_position"].hardware_set_func = self.abs_mov

        LQ["x_position"].hardware_set_func = self.rel_mov
        LQ["y_position"].hardware_set_func = self.rel_mov

        #Take an initial sample of the data.
        self.read_from_hardware()

    def disconnect(self):
        #Disconnect the device and remove connections from settings
        self.settings.disconnect_all_from_hardware()
        if hasattr(self, 'pi_device'):
            self.pi_device.close()
            del self.pi_device
            self.pi_device = None

    def center_piezo(self):
        if hasattr(self, 'pi_device'):
            self.pi_device.MOV(axes=self.axes, values=[50, 50])
            self.read_from_hardware()

    def abs_mov(self):
        if hasattr(self, 'pi_device'):
            x_abs_pos = self.settings['x_abs']
            y_abs_pos = self.settings['y_abs']
            self.pi_device.MOV(axes=self.axes, values=[x_abs_pos, y_abs_pos])
            self.read_from_hardware()

    def rel_mov(self):
        if hasattr(self, 'pi_device'):
            x_rel_pos = self.settings['x_rel']
            y_rel_pos = self.settings['y_rel']
            self.pi_device.MVR(axes=self.axes, values=[x_rel_pos, y_rel_pos])
            self.read_from_hardware()

    def getX(self):
        return self.pi_device.qPOS(axes=self.axes)['1']

    def getY(self):
        return self.pi_device.qPOS(axes=self.axes)['2']
class MainWindow(TemplateBaseClass):
    def __init__(self):
        TemplateBaseClass.__init__(self)

        # Create the main window
        self.ui = WindowTemplate()
        self.ui.setupUi(self)

        self.ui.connect_checkBox.stateChanged.connect(
            self._handle_spectrometer_connection)
        self.ui.live_pushButton.clicked.connect(self.live)

        self.ui.path_to_folder_pushButton.clicked.connect(
            self.save_file_location)
        self.ui.save_single_spec_pushButton.clicked.connect(
            self.save_single_spec)

        self.ui.init_stage_pushButton.clicked.connect(self.init_piezo_stage)
        self.ui.show_curr_pos_pushButton.clicked.connect(
            self.current_piezo_stage_pos)
        self.ui.center_stage_pushButton.clicked.connect(self.center_piezo)
        self.ui.abs_mov_pushButton.clicked.connect(self.abs_mov)
        self.ui.rel_mov_pushButton.clicked.connect(self.rel_mov)
        self.ui.estimate_scan_time_pushButton.clicked.connect(
            self.estimate_scan_time)
        self.ui.start_x_y_sacan_pushButton.clicked.connect(self.x_y_scan)

        #        self.ui.clear_pushButton.clicked.connect(self.clear_plot)
        self.pi_device = None
        self.spec = None

        self.ui.status_textBrowser.setText("Welcome!\nGUI Initiated!")

        self.show()

    def _handle_spectrometer_connection(self):
        if self.ui.connect_checkBox.isChecked():
            self.connect_spectrometer()
        else:
            self.close_connection()

    def connect_spectrometer(self):
        if self.spec is None:
            devices = sb.list_devices()
            self.spec = sb.Spectrometer(devices[0])
            self.ui.status_textBrowser.append(
                "Ocean Optics Device Connected!\n\n Device:\n\n" +
                str(sb.list_devices()[0]))
        else:
            self.ui.status_textBrowser.append("Already Connected")

    def init_piezo_stage(self):
        if self.pi_device is None:
            self.pi_device = GCSDevice("E-710")  # Creates a Controller instant
            self.pi_device.ConnectNIgpib(board=0,
                                         device=4)  # Connect to GPIB board
            self.ui.status_textBrowser.append('Connected: {}'.format(
                self.pi_device.qIDN().strip()))
            #        print('connected: {}'.format(self.pi_device.qIDN().strip()))

            self.axes = self.pi_device.axes[
                0:2]  # selecting x and y axis of the stage

            self.pi_device.INI()
            self.pi_device.REF(axes=self.axes)

            self.pi_device.SVO(
                axes=self.axes,
                values=[True, True])  # Turn on servo control for both axes
            self.ui.status_textBrowser.append(
                "Current Stage Position:\n{}".format(
                    self.pi_device.qPOS(axes=self.axes)))

    #        print(self.pi_device.qPOS(axes=self.axes))
        else:
            self.ui.status_textBrowser.append(
                "Piezo Stage Is Already Initialized!")

    def center_piezo(self):
        if self.pi_device is None:
            self.init_piezo_stage()
        self.pi_device.MOV(axes=self.axes, values=[50, 50])
        self.ui.status_textBrowser.append("Piezo Stage Centered: [50x,50y]")

    def current_piezo_stage_pos(self):
        if self.pi_device is None:
            self.init_piezo_stage()
        self.ui.status_textBrowser.append("Current Stage Position:\n{}".format(
            self.pi_device.qPOS(axes=self.axes)))

    def abs_mov(self):
        if self.pi_device is None:
            self.init_piezo_stage()
        x_abs_pos = self.ui.x_abs_doubleSpinBox.value()
        y_abs_pos = self.ui.y_abs_doubleSpinBox.value()
        self.pi_device.MOV(axes=self.axes, values=[x_abs_pos, y_abs_pos])

    def rel_mov(self):
        if self.pi_device is None:
            self.init_piezo_stage()
        x_rel_pos = self.ui.x_rel_doubleSpinBox.value()
        y_rel_pos = self.ui.y_rel_doubleSpinBox.value()
        self.pi_device.MVR(axes=self.axes, values=[x_rel_pos, y_rel_pos])

    def estimate_scan_time(self):
        x_scan_size = self.ui.x_size_doubleSpinBox.value()
        y_scan_size = self.ui.y_size_doubleSpinBox.value()

        x_step = self.ui.x_step_doubleSpinBox.value()
        y_step = self.ui.y_step_doubleSpinBox.value()

        if y_scan_size == 0:
            y_scan_size = 1

        if x_scan_size == 0:
            x_scan_size = 1

        if y_step == 0:
            y_step = 1

        if x_step == 0:
            x_step = 1

        y_range = int(np.ceil(y_scan_size / y_step))
        x_range = int(np.ceil(x_scan_size / x_step))

        total_points = x_range * y_range

        intg_time_ms = self.ui.intg_time_spinBox.value()
        scans_to_avg = self.ui.scan_to_avg_spinBox.value()

        total_time = total_points * (intg_time_ms * 1e-3) * (scans_to_avg
                                                             )  # in seconds

        self.ui.status_textBrowser.append("Estimated scan time: " +
                                          str(np.float16(total_time / 60)) +
                                          " mins")

    def x_y_scan(self):
        if self.pi_device is None:
            self.init_piezo_stage()

        if self.spec is None:
            self.ui.status_textBrowser.append(
                "Spectrometer not connected!\nForce connecting the spectrometer..."
            )
            self.connect_spectrometer()

        start_time = time.time()
        x_start = self.ui.x_start_doubleSpinBox.value()
        y_start = self.ui.y_start_doubleSpinBox.value()

        x_scan_size = self.ui.x_size_doubleSpinBox.value()
        y_scan_size = self.ui.y_size_doubleSpinBox.value()

        x_step = self.ui.x_step_doubleSpinBox.value()
        y_step = self.ui.y_step_doubleSpinBox.value()

        if y_scan_size == 0:
            y_scan_size = 1

        if x_scan_size == 0:
            x_scan_size = 1

        if y_step == 0:
            y_step = 1

        if x_step == 0:
            x_step = 1

        y_range = int(np.ceil(y_scan_size / y_step))
        x_range = int(np.ceil(x_scan_size / x_step))

        # Define empty array for saving intensities
        data_array = np.zeros(shape=(x_range * y_range, 2048))

        self.ui.status_textBrowser.append("Starting Scan...")
        # Move to the starting position
        self.pi_device.MOV(axes=self.axes, values=[x_start, y_start])

        self.ui.status_textBrowser.append("Scan in Progress...")

        k = 0
        for i in range(y_range):
            for j in range(x_range):
                #                print(self.pi_device.qPOS(axes=self.axes))

                self._read_spectrometer()
                data_array[k, :] = self.y
                self.ui.plot.plot(self.spec.wavelengths(),
                                  self.y,
                                  pen='r',
                                  clear=True)
                pg.QtGui.QApplication.processEvents()

                self.pi_device.MVR(axes=self.axes[0], values=[x_step])

                self.ui.progressBar.setValue(100 * ((k + 1) /
                                                    (x_range * y_range)))
                k += 1
            # TODO
            # if statement needs to be modified to keep the stage at the finish y-pos for line scans in x, and same for y
            if i == y_range - 1:  # this if statement is there to keep the stage at the finish position (in x) and not bring it back like we were doing during the scan
                self.pi_device.MVR(axes=self.axes[1], values=[y_step])
            else:
                self.pi_device.MVR(axes=self.axes,
                                   values=[-x_scan_size, y_step])

        self.ui.status_textBrowser.append("Scan Complete!\nSaving Data...")

        save_dict = {
            "Wavelengths": self.spec.wavelengths(),
            "Intensities": data_array,
            "Scan Parameters": {
                "X scan start (um)": x_start,
                "Y scan start (um)": y_start,
                "X scan size (um)": x_scan_size,
                "Y scan size (um)": y_scan_size,
                "X step size (um)": x_step,
                "Y step size (um)": y_step
            },
            "OceanOptics Parameters": {
                "Integration Time (ms)":
                self.ui.intg_time_spinBox.value(),
                "Scans Averages":
                self.ui.scan_to_avg_spinBox.value(),
                "Correct Dark Counts":
                self.ui.correct_dark_counts_checkBox.isChecked()
            }
        }

        pickle.dump(
            save_dict,
            open(
                self.save_folder + "/" + self.ui.lineEdit.text() +
                "_raw_PL_spectra_data.pkl", "wb"))

        self.ui.status_textBrowser.append(
            "Data saved!\nTotal time taken:" +
            str(np.float16((time.time() - start_time) / 60)) + " mins")

    def save_file_location(self):
        self.save_folder = QtWidgets.QFileDialog.getExistingDirectory(
            self, caption="Select Folder")

    def save_single_spec(self):
        save_array = np.zeros(shape=(2048, 2))
        self._read_spectrometer()
        save_array[:, 1] = self.y
        save_array[:, 0] = self.spec.wavelengths()

        np.savetxt(self.save_folder + "/" + self.ui.lineEdit.text() + ".txt",
                   save_array,
                   fmt='%.5f',
                   header='Wavelength (nm), Intensity (counts)',
                   delimiter=' ')

    def live(self):
        save_array = np.zeros(shape=(2048, 2))

        self.ui.plot.setLabel('left', 'Intensity', units='a.u.')
        self.ui.plot.setLabel('bottom', 'Wavelength', units='nm')
        j = 0
        while self.spec is not None:  #self.ui.connect_checkBox.isChecked(): # this while loop works!
            self._read_spectrometer()
            save_array[:, 1] = self.y

            self.ui.plot.plot(self.spec.wavelengths(),
                              self.y,
                              pen='r',
                              clear=True)

            if self.ui.save_every_spec_checkBox.isChecked():
                save_array[:, 0] = self.spec.wavelengths()
                np.savetxt(self.save_folder + "/" + self.ui.lineEdit.text() +
                           str(j) + ".txt",
                           save_array,
                           fmt='%.5f',
                           header='Wavelength (nm), Intensity (counts)',
                           delimiter=' ')

            pg.QtGui.QApplication.processEvents()
            j += 1

    def _read_spectrometer(self):
        if self.spec is not None:

            intg_time_ms = self.ui.intg_time_spinBox.value()
            self.spec.integration_time_micros(intg_time_ms * 1e3)

            scans_to_avg = self.ui.scan_to_avg_spinBox.value()
            Int_array = np.zeros(shape=(2048, scans_to_avg))

            for i in range(scans_to_avg):  #software average
                data = self.spec.spectrum(
                    correct_dark_counts=self.ui.correct_dark_counts_checkBox.
                    isChecked())
                Int_array[:, i] = data[1]
                self.y = np.mean(Int_array, axis=-1)

        else:
            self.ui.status_textBrowser.append("Connect to Spectrometer!")
            raise Exception("Must connect to spectrometer first!")

    def close_connection(self):
        if self.spec is not None:
            self.spec.close()
            self.ui.status_textBrowser.append(
                "Ocean Optics Device Disconnected")
            del self.spec
            self.spec = None

    def close_application(self):
        choice = QtGui.QMessageBox.question(
            self, 'EXIT!', "Do you want to exit the app?",
            QtGui.QMessageBox.Yes | QtGui.QMessageBox.No)
        if choice == QtGui.QMessageBox.Yes:
            sys.exit()
        else:
            pass