Example #1
0
    def __init__(self, device_obj=None, **kwargs):

        # Yes, I am aware that having a self._device inside the
        # Device class can be somewhat confusing
        if device_obj is None:
            self._device = Spectrometer.from_first_available()
        else:
            self._device = Spectrometer(device_obj)
    def __init__(self, spec=None):
        if spec is None:
            dev = list_devices()[0]
            self.spec = Spectrometer(dev)
        else:
            self.spec = spec
        self.lmbd = self.spec.wavelengths()
        self.bg = np.zeros_like(self.lmbd)
        self.calibration = np.load(
            "/home/xmas/Documents/Python/xmas/oceanoptics/calibration.npy")

        self.app = QtGui.QApplication([])
        self.ui = uic.loadUi(
            "/home/xmas/Documents/Python/xmas/oceanoptics/spectrum.ui")
        self.plot_live = pg.PlotCurveItem()
        self.pen = pg.mkPen(color='r')
        self.ui.plot_full.addItem(self.plot_live)
        self.ui.show()

        self.ui.plot_full.showGrid(x=True, y=True, alpha=1.0)
        self.ui.xmin.setMinimum(0)
        self.ui.xmax.setMinimum(0)
        self.ui.xmin.setMaximum(self.lmbd.max() * 2)
        self.ui.xmax.setMaximum(self.lmbd.max() * 2)
        #self.ui.xmin.setValue(self.lmbd.min())
        #self.ui.xmax.setValue(self.lmbd.max())
        self.ui.xmin.setValue(960)
        self.ui.xmax.setValue(1100)
        self.ui.integration.setMinimum(
            self.spec.integration_time_micros_limits[0] / 1000.0)
        self.ui.integration.setMaximum(
            self.spec.integration_time_micros_limits[1] / 1000.0)
        self.ui.integration.setValue(
            self.spec.integration_time_micros_limits[0] / 1000.0)
        self.set_integration_cb()
        self.update_range_cb()

        self.ui.integration.valueChanged.connect(self.set_integration_cb)
        self.ui.xmin.valueChanged.connect(self.update_range_cb)
        self.ui.xmax.valueChanged.connect(self.update_range_cb)
        self.ui.autoY.clicked.connect(self.autoY)
        self.ui.autoXY.clicked.connect(self.autoXY)

        self.reset_avg()

        self.timer = pg.QtCore.QTimer()
        self.timer.timeout.connect(self.acquire)
        self.timer.start(5)

        self.app.exec_()
Example #3
0
File: FlameS.py Project: NREL/QIS
    def animate(i):
        spec = Spectrometer.from_first_available()
        spec.integration_time_micros(integ)
        a = spec.wavelengths()
        b = spec.intensities()
        a = a[30:]  # delete the first pseudo peak
        b = b[30:]
        if b.max() > 65500:
            msg = "Flame is saturated, please reduce integration time"
            print(msg)

        step = abs(a[1] - a[0])
        if wavelength1 is not None:
            p = np.where(abs(a - wavelength1) < step)[0][0]  # define baseline
            a = a[p:]
            b = b[p:]

        if wavelength2 is not None:
            q = np.where(abs(a - wavelength2) < step)[0][0]
            a = a[:q]
            b = b[:q]

        # for i in range(len(b)):  #filter out peaks
        #     if b[i]>3000:
        #         b[i]=2400

        ax1.clear()
        ax1.plot(a, b)
        plt.title(title)
        plt.xlabel('Wavelength, nm')
        plt.ylabel('Signal Amplitude, AU')
        print(i)
def test_crash_may_not_influence_following_tests(backendlified_serial):
    devices = list(list_devices())
    if len(devices) == 0:
        pytest.skip("no supported device connected")

    _ = Spectrometer.from_serial_number(backendlified_serial)
    raise Exception("crash on purpose")
Example #5
0
def test_read_spectrum(backendlified_serial):
    devices = list(list_devices())
    if len(devices) == 0:
        pytest.skip("no supported device connected")

    spec = Spectrometer.from_serial_number(backendlified_serial)
    arr = spec.spectrum()
    assert arr.shape == (2, spec.pixels)
Example #6
0
def test_read_serial_number(backendlified_serial):
    devices = list(list_devices())
    if len(devices) == 0:
        pytest.skip("no supported device connected")

    spec = Spectrometer.from_serial_number(backendlified_serial)
    serial = spec.serial_number
    assert len(serial) > 0
def open_spect(t_integracion,logger):
  try:
      spec = Spectrometer.from_first_available()
      #spec = Spectrometer.from_serial_number("S05507")
      spec.integration_time_micros(t_integracion)
      return spec
  except SeaBreezeError as e: # Spectrometer.CalledProcessError as err:
      #logger.error("Error conectando el espectrometro",e) 
      return 0
Example #8
0
def test_max_intensity(backendlified_serial):
    devices = list(list_devices())
    if len(devices) == 0:
        pytest.skip("no supported device connected")

    spec = Spectrometer.from_serial_number(backendlified_serial)
    value = spec.max_intensity
    assert isinstance(value, float)
    assert 0 < value < 1e8
Example #9
0
def test_integration_time_limits(backendlified_serial):
    devices = list(list_devices())
    if len(devices) == 0:
        pytest.skip("no supported device connected")

    spec = Spectrometer.from_serial_number(backendlified_serial)
    low, high = spec.integration_time_micros_limits
    assert isinstance(low, int)
    assert isinstance(high, int)
    assert 0 < low < high < 2**64
Example #10
0
def open_spect():
    try:
        spec = Spectrometer.from_first_available()
        print("conectando")

        return spec

    except:  #excepcion en caso de que el espectrometro no este conectada
        #logger.error("Error conectando el espectrometro")
        print("no se pudo conectar")
        return 0
Example #11
0
 def connect(self):
     self.device = None
     try:
         devices = list_devices()
     except:
         devices = list_devices()
     for device in devices:
         pyusb_device = device._raw_device.pyusb_device
         if pyusb_device.idVendor == self.device_id.vid and pyusb_device.idProduct == self.device_id.pid:
             self.device = device
     if self.device == None:
         log.error("Ocean Device: No ocean device found. Returning")
         self.message_queue.put_nowait(None)
         return False
     self.spec = Spectrometer(self.device)
     self.settings.eeprom.model = self.device.model
     self.settings.eeprom.serial_number = self.device.serial_number
     self.settings.eeprom.active_pixels_horizontal = self.device.features[
         'spectrometer'][0]._spectrum_num_pixel
     self.settings.eeprom.detector = "Ocean"  # Ocean API doesn't have access to detector info
     return True
Example #12
0
class Device(object):
    # {{{
    def __init__(self, device_obj=None, **kwargs):

        # Yes, I am aware that having a self._device inside the
        # Device class can be somewhat confusing
        if device_obj is None:
            self._device = Spectrometer.from_first_available()
        else:
            self._device = Spectrometer(device_obj)

    def measure(self, **kwargs):

        correct_nl = kwargs["correct_nl"] if "correct_nl" in kwargs else False
        correct_dc = kwargs["correct_dc"] if "correct_dc" in kwargs else False

        return self._device.intensities(correct_dc, correct_nl)

    def wavelengths(self, **kwargs):
        return self._device.wavelengths()

    def set_int_time(self, int_time, sleep_time=5, **kwargs):
        self._device.integration_time_micros(int_time)

        # This is to account for the delay involved in changing
        # the spectrometer's integration time
        sleep(sleep_time)

    @property
    def int_time_limits(self):
        return self._device.integration_time_micros_limits

    @property
    def sat_intensity(self):
        return self._device.max_intensity

    @property
    def temperature(self):
        return 0  # Implement this
def test_correct_dark_pixels(backendlified_serial):
    devices = list(list_devices())
    if len(devices) == 0:
        pytest.skip("no supported device connected")
    # noinspection PyProtectedMember
    SeaBreezeError = Spectrometer._backend.SeaBreezeError

    spec = Spectrometer.from_serial_number(backendlified_serial)
    try:
        arr = spec.intensities(correct_dark_counts=True)
    except SeaBreezeError:
        pytest.skip("does not support dark counts")
    else:
        assert arr.size == spec.pixels
Example #14
0
def test_trigger_mode(backendlified_serial):
    devices = list(list_devices())
    if len(devices) == 0:
        pytest.skip("no supported device connected")

    exc = Spectrometer._backend.SeaBreezeError
    spec = Spectrometer.from_serial_number(backendlified_serial)

    spec.trigger_mode(0x00)  # <- normal mode

    with pytest.raises(exc):
        spec.trigger_mode(0xF0)  # <- should be unsupported for all specs
    # test again to see if the bus is locked
    spec.trigger_mode(0x00)  # <- normal mode
Example #15
0
def test_integration_time(backendlified_serial):
    devices = list(list_devices())
    if len(devices) == 0:
        pytest.skip("no supported device connected")

    exc = Spectrometer._backend.SeaBreezeError
    spec = Spectrometer.from_serial_number(backendlified_serial)

    with pytest.raises(exc):
        # fail because too low
        spec.integration_time_micros(0)

    with pytest.raises(exc):
        # fail because too large
        spec.integration_time_micros(2**62)

    with pytest.raises(exc):
        # fail because too large long overflow
        spec.integration_time_micros(2**64)

    spec.integration_time_micros(10000)
Example #16
0
File: FlameS.py Project: NREL/QIS
def FlameS_save(wavelength1, wavelength2, integ, folder, filename, title):
    spec = Spectrometer.from_first_available()
    spec.integration_time_micros(integ)  #us
    a = spec.wavelengths()
    b = spec.intensities()
    a = a[30:]  # delete the first pseudo peak
    b = b[30:]
    msg = ''

    if b.max() > 65500:
        msg = "Flame is saturated, please reduce integration time."
        print(msg)

    step = abs(a[1] - a[0])

    if (wavelength1 is not None) and (wavelength2 is not None):
        msg = msg + "\nPart of the spectrum is plotted."
        print(msg)

    if wavelength1 is not None:
        p = np.where(abs(a - wavelength1) < step)[0][0]  # define baseline
        a = a[p:]
        b = b[p:]

    if wavelength2 is not None:
        q = np.where(abs(a - wavelength2) < step)[0][0]
        a = a[:q]
        b = b[:q]

    np.savetxt(folder + '/' + filename + "wl.csv", a,
               delimiter=",")  # save wavelength
    np.savetxt(folder + '/' + filename + ".csv", b,
               delimiter=",")  # save fluorescen intensity
    plt.plot(a, b)
    plt.title(title + ' ' + filename)
    plt.xlabel('Wavelength, nm')
    plt.ylabel('Signal Amplitude, AU')
    plt.show()
    return msg
class SpectraViewer():
    def __init__(self, spec=None):
        if spec is None:
            dev = list_devices()[0]
            self.spec = Spectrometer(dev)
        else:
            self.spec = spec
        self.lmbd = self.spec.wavelengths()
        self.bg = np.zeros_like(self.lmbd)
        self.calibration = np.load(
            "/home/xmas/Documents/Python/xmas/oceanoptics/calibration.npy")

        self.app = QtGui.QApplication([])
        self.ui = uic.loadUi(
            "/home/xmas/Documents/Python/xmas/oceanoptics/spectrum.ui")
        self.plot_live = pg.PlotCurveItem()
        self.pen = pg.mkPen(color='r')
        self.ui.plot_full.addItem(self.plot_live)
        self.ui.show()

        self.ui.plot_full.showGrid(x=True, y=True, alpha=1.0)
        self.ui.xmin.setMinimum(0)
        self.ui.xmax.setMinimum(0)
        self.ui.xmin.setMaximum(self.lmbd.max() * 2)
        self.ui.xmax.setMaximum(self.lmbd.max() * 2)
        #self.ui.xmin.setValue(self.lmbd.min())
        #self.ui.xmax.setValue(self.lmbd.max())
        self.ui.xmin.setValue(960)
        self.ui.xmax.setValue(1100)
        self.ui.integration.setMinimum(
            self.spec.integration_time_micros_limits[0] / 1000.0)
        self.ui.integration.setMaximum(
            self.spec.integration_time_micros_limits[1] / 1000.0)
        self.ui.integration.setValue(
            self.spec.integration_time_micros_limits[0] / 1000.0)
        self.set_integration_cb()
        self.update_range_cb()

        self.ui.integration.valueChanged.connect(self.set_integration_cb)
        self.ui.xmin.valueChanged.connect(self.update_range_cb)
        self.ui.xmax.valueChanged.connect(self.update_range_cb)
        self.ui.autoY.clicked.connect(self.autoY)
        self.ui.autoXY.clicked.connect(self.autoXY)

        self.reset_avg()

        self.timer = pg.QtCore.QTimer()
        self.timer.timeout.connect(self.acquire)
        self.timer.start(5)

        self.app.exec_()

    def reset_avg(self):
        self.n = 0
        self.spectra_avg = np.zeros_like(self.lmbd)

    def autoXY(self):
        self.ui.xmin.setValue(self.lmbd.min())
        self.ui.xmax.setValue(self.lmbd.max())
        self.update_range_cb()
        self.autoY()

    def autoY(self, pad=0.05):
        ydata = self.plot_live.getData()[1]
        ymin, ymax = ydata.min(), ydata.max()
        diff = ymax - ymin
        self.ui.plot_full.setYRange(ymin - diff * pad, ymax + diff * pad)

    def acquire(self):
        self.spectra_avg += self.spec.intensities()
        self.n += 1
        if self.n == self.ui.n_average.value():
            self.update_plot()
        elif self.n > self.ui.n_average.value():
            self.reset_avg()

    def update_range_cb(self):
        self.ui.plot_full.setXRange(self.ui.xmin.value(), self.ui.xmax.value())

    def save_spectrum(self, all=False):
        name = self.ui.savepath.text()
        if name == '':
            name = 'spectrum'
        if all:
            name = paths.return_folder(paths.oceanoptics() + name) + "/" + name
        else:
            name = paths.oceanoptics() + name
            self.ui.saveone_button.setChecked(False)
        np.save(name + "_" + datetime.today().strftime("%H%M%S_%f"),
                self.spectra_avg)

    def update_plot(self):
        self.spectra_avg /= self.ui.n_average.value()

        if self.ui.saveBG.isChecked():
            self.bg = self.spectra_avg.copy()
            self.ui.saveBG.setChecked(False)
        elif self.ui.saveall_button.isChecked():
            self.save_spectrum(all=True)
        elif self.ui.saveone_button.isChecked():
            self.save_spectrum(all=False)
            self.ui.saveone_button.setChecked(False)

        if self.ui.subBG.isChecked():
            self.spectra_avg -= self.bg

        if self.ui.calibrate.isChecked():
            self.spectra_avg *= self.calibration

        self.plot_live.setData(x=self.lmbd, y=self.spectra_avg, pen=self.pen)
        self.reset_avg()

    def set_integration_cb(self):
        self.spec.integration_time_micros(
            int(self.ui.integration.value() * 1000))
        self.reset_avg()
Example #18
0
    def ini_detector(self, controller=None):
        """Detector communication initialization

        Parameters
        ----------
        controller: (object) custom object of a PyMoDAQ plugin (Slave case). None if only one detector by controller (Master case)

        Returns
        -------
        self.status (edict): with initialization status: three fields:
            * info (str)
            * controller (object) initialized controller
            *initialized: (bool): False if initialization failed otherwise True
        """

        try:
            self.status.update(
                edict(initialized=False,
                      info="",
                      x_axis=None,
                      y_axis=None,
                      controller=None))
            if self.settings.child('controller_status').value() == "Slave":
                if controller is None:
                    raise Exception(
                        'no controller has been defined externally while this detector is a slave one'
                    )
                else:
                    self.controller = controller
            else:
                # From what I understand this will just get the spectro currently selected in the list
                dvc = self.settings.child('device').value()
                self.controller = Spectrometer(dvc)
                self.controller.open()
                #####################################

            # Oceanoptics spectrometers (at least the ones i Know) have fixed axis
            # get inactive pixels
            c0 = self.controller.f.spectrometer.get_electric_dark_pixel_indices(
            )[-1]
            self.settings.child('advanced').child('dark_channels').setValue(c0)
            # get the x_axis
            data_x_axis = self.controller.wavelengths(
            )  # Way to get the x axis
            data_x_axis = data_x_axis[c0:]  # Get rid of the dark pixels
            self.x_axis = Axis(data=data_x_axis,
                               label='wavelength',
                               units='nm')
            self.emit_x_axis()

            # Get the name
            specname = f"Ocean Insight {self.controller.model}"

            # initialize viewers pannel with the future type of data
            self.data_grabed_signal_temp.emit([
                DataFromPlugins(name=specname,
                                data=[np.zeros_like(data_x_axis)],
                                dim='Data1D',
                                labels=['Intensity'],
                                x_axis=self.x_axis),
            ])

            # Update the parameters
            # Here we need to do a few things. Get the integration time limits and set it in the settings
            tlimits = np.array(
                self.controller.integration_time_micros_limits) / 1000
            self.settings.child('integration').setLimits(tlimits)
            # Here we need to update the advanced parameters
            advanced_settings = self.settings.child('advanced')
            sn = self.controller.serial_number
            advanced_settings.child('serial_number').setValue(sn)
            # non linearity coefficients
            nlc_feat = self.controller.f.nonlinearity_coefficients
            if nlc_feat is not None and not any(
                    np.isnan(nlc_feat.get_nonlinearity_coefficients())):
                advanced_settings.child('correct_non_linearity').setValue(True)
            else:
                advanced_settings.child('correct_non_linearity').setValue(
                    False)
                advanced_settings.child('correct_non_linearity').setOpts(
                    enabled=False)

            # measure the readout time
            Nperf = 200
            self.settings.child('integration').setValue(
                tlimits[0])  # Update the parameter value to the lower limit
            self.controller.integration_time_micros(
                tlimits[0] * 1000)  # Set the readout time to lower limit
            perf = timeit(lambda: self.controller.intensities(),
                          number=Nperf)  # time the execution of code in [s]
            self.settings.child('advanced').child('readout_time').setValue(
                1000 * perf / Nperf)  # set the settings

            ##############################

            self.status.info = f"Initialized {specname} spectrometer"
            self.status.initialized = True
            self.status.controller = self.controller
            return self.status

        except Exception as e:
            self.emit_status(
                ThreadCommand('Update_Status',
                              [getLineInfo() + str(e), 'log']))
            self.status.info = getLineInfo() + str(e)
            self.status.initialized = False
            return self.status
Example #19
0
numArg = 2
if len(sys.argv) != numArg:
    print(
        "Function expects " + str(numArg - 1) +
        " argument(s). Example: 'spectroscopyLive.py 30' measures spectrometer for 30 seconds"
    )
    exit()

# Parameters
loopTime = int(sys.argv[1])
normalization = 25000

# Obtain the spectrometer object
devices = list_devices()
print(devices)
spec = Spectrometer(devices[0])

# Generate live plot
plt.ion()

# Start counting the time
tStart = time.time()

# Update the live graph
while (time.time() - tStart <= loopTime):
    wavelengthsPlot = spec.wavelengths()[20:]
    intensityPlot = spec.intensities()[20:] / normalization
    totalIntensity = sum(intensityPlot)
    print("Total Intensity = ", totalIntensity)
    plt.plot(wavelengthsPlot, intensityPlot)
    plt.draw()
Example #20
0
 def __init__(self,parent=None):
     super().__init__(parent)
     
     self.confFrog=QtCore.QSettings('confFrog.ini', QtCore.QSettings.IniFormat)
     p = pathlib.Path(__file__)
     sepa=os.sep
     self.icon=str(p.parent) + sepa+'icons'+sepa
     self.setWindowIcon(QIcon(self.icon+'LOA.png'))
     self.left=30
     self.top=30
     self.width=1200
     self.height=750
     self.setGeometry(self.left,self.top,self.width,self.height)
     self.iconPlay=self.icon+'Play.png'
     self.iconSnap=self.icon+'Snap.png'
     self.iconStop=self.icon+'Stop.png'
     self.iconBg=self.icon+'coin.png'
     self.iconPlay=pathlib.Path(self.iconPlay)
     self.iconPlay=pathlib.PurePosixPath(self.iconPlay)
     self.iconStop=pathlib.Path(self.iconStop)
     self.iconStop=pathlib.PurePosixPath(self.iconStop)
     self.iconSnap=pathlib.Path(self.iconSnap)
     self.iconSnap=pathlib.PurePosixPath(self.iconSnap)
     
     self.iconBg=pathlib.Path(self.iconBg)
     self.iconBg=pathlib.PurePosixPath(self.iconBg)
     
     self.setWindowIcon(QIcon(self.icon+'LOA.png'))
     self.setWindowTitle('FROG ')
     
     self.motorName="moteurTest"#"Moteur0A"
     self.motorType='MotorTest'#"A2V"
     self.configPath="./fichiersConfig/"
     self.configMotName='configMoteurTest.ini'#'configMoteurA2V.ini'
     
     self.confpath=str(p.parent) + sepa
     # print('confpath',self.confpath)
     
     self.bg=0
     self.motor=ONEMOTOR(mot0=self.motorName,motorTypeName0=self.motorType,unit=3,jogValue=1)
     self.motor.startThread2()
     
     MOT=self.motor.MOT
     self.scanWidget=SCAN(MOT=MOT,motor=self.motorName,configMotName=self.configPath+self.configMotName) # for the scan)
     
     
     
     listdevice=list_devices() ## open device flame spectrometer 
     try : 
         self.spectrometer=Spectrometer(listdevice[0])
         sh=int(self.confFrog.value('VISU'+'/shutter'))
         try:
             self.spectrometer.integration_time_micros(sh*1000) # en micro
         except: 
             self.spectrometer.integration_time_micros(100*1000)
     except :
         self.spectrometer=[]
         msg = QMessageBox()
         msg.setIcon(QMessageBox.Critical)
         msg.setText("Error connexion Spectrometer")
         msg.setInformativeText("Try to reconnect the USB or resart the program")
         msg.setWindowTitle("Spectrometer not connected...")
         msg.setWindowFlags(QtCore.Qt.WindowStaysOnTopHint)
         msg.exec_()
         pass
     print('__________  F R O G  __________')
     print('')
     print('  Version  : ',version)
     print("  Spectrometer connected @ ",self.spectrometer)
     self.wavelengths=self.spectrometer.wavelengths() # array Wavelengths of the spectrometer 
     print("  Wavelength : " ,self.wavelengths.min(),self.wavelengths.max())
     print('  Motor name: ',self.motorName,'  Type: ',self.motorType)
     print('')
     self.MatData=[]
     self.MatFs=[]
     self.position=0
     self.moyenne=1
     self.nbShot=1
     self.row=0
     self.setup()
     self.actionButton()
Example #21
0
class FROG(QMainWindow) :
    
    isrunning=QtCore.pyqtSignal(bool)
    
    def __init__(self,parent=None):
        super().__init__(parent)
        
        self.confFrog=QtCore.QSettings('confFrog.ini', QtCore.QSettings.IniFormat)
        p = pathlib.Path(__file__)
        sepa=os.sep
        self.icon=str(p.parent) + sepa+'icons'+sepa
        self.setWindowIcon(QIcon(self.icon+'LOA.png'))
        self.left=30
        self.top=30
        self.width=1200
        self.height=750
        self.setGeometry(self.left,self.top,self.width,self.height)
        self.iconPlay=self.icon+'Play.png'
        self.iconSnap=self.icon+'Snap.png'
        self.iconStop=self.icon+'Stop.png'
        self.iconBg=self.icon+'coin.png'
        self.iconPlay=pathlib.Path(self.iconPlay)
        self.iconPlay=pathlib.PurePosixPath(self.iconPlay)
        self.iconStop=pathlib.Path(self.iconStop)
        self.iconStop=pathlib.PurePosixPath(self.iconStop)
        self.iconSnap=pathlib.Path(self.iconSnap)
        self.iconSnap=pathlib.PurePosixPath(self.iconSnap)
        
        self.iconBg=pathlib.Path(self.iconBg)
        self.iconBg=pathlib.PurePosixPath(self.iconBg)
        
        self.setWindowIcon(QIcon(self.icon+'LOA.png'))
        self.setWindowTitle('FROG ')
        
        self.motorName="moteurTest"#"Moteur0A"
        self.motorType='MotorTest'#"A2V"
        self.configPath="./fichiersConfig/"
        self.configMotName='configMoteurTest.ini'#'configMoteurA2V.ini'
        
        self.confpath=str(p.parent) + sepa
        # print('confpath',self.confpath)
        
        self.bg=0
        self.motor=ONEMOTOR(mot0=self.motorName,motorTypeName0=self.motorType,unit=3,jogValue=1)
        self.motor.startThread2()
        
        MOT=self.motor.MOT
        self.scanWidget=SCAN(MOT=MOT,motor=self.motorName,configMotName=self.configPath+self.configMotName) # for the scan)
        
        
        
        listdevice=list_devices() ## open device flame spectrometer 
        try : 
            self.spectrometer=Spectrometer(listdevice[0])
            sh=int(self.confFrog.value('VISU'+'/shutter'))
            try:
                self.spectrometer.integration_time_micros(sh*1000) # en micro
            except: 
                self.spectrometer.integration_time_micros(100*1000)
        except :
            self.spectrometer=[]
            msg = QMessageBox()
            msg.setIcon(QMessageBox.Critical)
            msg.setText("Error connexion Spectrometer")
            msg.setInformativeText("Try to reconnect the USB or resart the program")
            msg.setWindowTitle("Spectrometer not connected...")
            msg.setWindowFlags(QtCore.Qt.WindowStaysOnTopHint)
            msg.exec_()
            pass
        print('__________  F R O G  __________')
        print('')
        print('  Version  : ',version)
        print("  Spectrometer connected @ ",self.spectrometer)
        self.wavelengths=self.spectrometer.wavelengths() # array Wavelengths of the spectrometer 
        print("  Wavelength : " ,self.wavelengths.min(),self.wavelengths.max())
        print('  Motor name: ',self.motorName,'  Type: ',self.motorType)
        print('')
        self.MatData=[]
        self.MatFs=[]
        self.position=0
        self.moyenne=1
        self.nbShot=1
        self.row=0
        self.setup()
        self.actionButton()
        
    def setup(self):
        
        hbox1=QHBoxLayout() # horizontal layout pour run snap stop
        self.sizebuttonMax=30
        self.sizebuttonMin=30
        self.runButton=QToolButton(self)
        self.runButton.setMaximumWidth(self.sizebuttonMax)
        self.runButton.setMinimumWidth(self.sizebuttonMax)
        self.runButton.setMaximumHeight(self.sizebuttonMax)
        self.runButton.setMinimumHeight(self.sizebuttonMax)
        self.runButton.setStyleSheet("QToolButton:!pressed{border-image: url(%s);background-color: transparent ;border-color: green;}""QToolButton:pressed{image: url(%s);background-color: gray ;border-color: gray}"% (self.iconPlay,self.iconPlay) )
        self.runButton.setToolTip("Free Run")
        self.snapButton=QToolButton(self)
        self.snapButton.setPopupMode(0)
        menu=QMenu()
        # menu.addAction('acq',self.oneImage)
        menu.addAction('set nb of shot',self.nbShotAction)
        self.snapButton.setMenu(menu)
        self.snapButton.setMaximumWidth(self.sizebuttonMax)
        self.snapButton.setMinimumWidth(self.sizebuttonMax)
        self.snapButton.setMaximumHeight(self.sizebuttonMax)
        self.snapButton.setMinimumHeight(self.sizebuttonMax)
        self.snapButton.setStyleSheet("QToolButton:!pressed{border-image: url(%s);background-color: transparent ;border-color: green;}""QToolButton:pressed{image: url(%s);background-color: gray ;border-color: gray}"% (self.iconSnap,self.iconSnap) )
        self.snapButton.setToolTip("Snap")
        self.stopButton=QToolButton(self)
        
        self.stopButton.setMaximumWidth(self.sizebuttonMax)
        self.stopButton.setMinimumWidth(self.sizebuttonMax)
        self.stopButton.setMaximumHeight(self.sizebuttonMax)
        self.stopButton.setMinimumHeight(self.sizebuttonMax)
        self.stopButton.setStyleSheet("QToolButton:!pressed{border-image: url(%s);background-color: gray ;border-color: gray;}""QToolButton:pressed{image: url(%s);background-color: gray ;border-color: gray}"% (self.iconStop,self.iconStop) )
        self.stopButton.setEnabled(False)
        self.stopButton.setToolTip("Stop Acquisition")
        self.bgButton=QToolButton(self)
        self.bgButton.setMaximumWidth(self.sizebuttonMax)
        self.bgButton.setMinimumWidth(self.sizebuttonMax)
        self.bgButton.setMaximumHeight(self.sizebuttonMax)
        self.bgButton.setMinimumHeight(self.sizebuttonMax)
        self.bgButton.setStyleSheet("QToolButton:!pressed{border-image: url(%s);background-color: transparent ;border-color: gray;}""QToolButton:pressed{image: url(%s);background-color: gray ;border-color: gray}"% (self.iconBg,self.iconBg) )
        self.bgButton.setToolTip("Take a Background")
        
        self.bgLayout=QHBoxLayout()
        self.bgLayout.setContentsMargins(0,0,0,0)
        self.bgLabel=QLabel('Background :')
        self.bgLabel.setStyleSheet('font :bold  8pt')
        self.bgSoustract=QCheckBox()
        self.bgSoustract.setToolTip("Background Soustraction (On/Off)")
        self.bgLayout.addWidget(self.bgLabel)
        self.bgLayout.addWidget(self.bgSoustract)
        
        hbox1.addWidget(self.runButton)
        hbox1.addWidget(self.snapButton)
        hbox1.addWidget(self.stopButton)
        hbox1.addWidget(self.bgButton)
        hbox1.addLayout(self.bgLayout)
        hbox1.setSizeConstraint(QtGui.QLayout.SetFixedSize)
        hbox1.setContentsMargins(5, 24, 0, 10)
        self.widgetControl=QWidget(self)
        
        self.widgetControl.setLayout(hbox1)
        self.dockControl=QDockWidget(self)
        self.dockControl.setWidget(self.widgetControl)
        self.dockControl.resize(80,80)
        
        self.trigg=QComboBox()
        self.trigg.setMaximumWidth(80)
        self.trigg.addItem('OFF')
        self.trigg.addItem('ON')
        self.trigg.setStyleSheet('font :bold  8pt;color: white')
        self.labelTrigger=QLabel('Trig')
        self.labelTrigger.setMaximumWidth(80)
        self.labelTrigger.setStyleSheet('font :bold  12pt')
        self.itrig=self.trigg.currentIndex()
        hbox2=QHBoxLayout()
        hbox2.setSizeConstraint(QtGui.QLayout.SetFixedSize)
        hbox2.setContentsMargins(5, 26, 0, 0)
        hbox2.addWidget(self.labelTrigger)
        hbox2.addWidget(self.trigg)
        self.widgetTrig=QWidget(self)
        
        self.widgetTrig.setLayout(hbox2)
        self.dockTrig=QDockWidget(self)
        self.dockTrig.setWidget(self.widgetTrig)
        
        self.labelExp=QLabel('Exposure (ms)')
        self.labelExp.setStyleSheet('font :bold  10pt')
        self.labelExp.setMaximumWidth(500)
        self.labelExp.setAlignment(Qt.AlignCenter)
        
        self.hSliderShutter=QSlider(Qt.Horizontal)
        self.hSliderShutter.setMaximumWidth(80)
        self.hSliderShutter.setValue(int(self.confFrog.value('VISU'+'/shutter')))
        self.shutterBox=QSpinBox()
        self.shutterBox.setStyleSheet('font :bold  8pt')
        self.shutterBox.setMaximumWidth(200)
        self.hSliderShutter.setMaximum(1100)
        self.shutterBox.setMaximum(1100)
        self.shutterBox.setValue(int(self.confFrog.value('VISU'+'/shutter')))
        hboxShutter=QHBoxLayout()
        hboxShutter.setContentsMargins(5, 0, 0, 0)
        hboxShutter.setSpacing(10)
        vboxShutter=QVBoxLayout()
        vboxShutter.setSpacing(0)
        vboxShutter.addWidget(self.labelExp)#,Qt.AlignLef)
        
        hboxShutter.addWidget(self.hSliderShutter)
        hboxShutter.addWidget(self.shutterBox)
        vboxShutter.addLayout(hboxShutter)
        vboxShutter.setSizeConstraint(QtGui.QLayout.SetFixedSize)
        vboxShutter.setContentsMargins(5, 5, 0, 0)
        
        self.widgetShutter=QWidget(self)
        
        self.widgetShutter.setLayout(vboxShutter)
        self.dockShutter=QDockWidget(self)
        self.dockShutter.setWidget(self.widgetShutter)
        
        
        
        self.labelMoy=QLabel('Average')
        self.labelMoy.setStyleSheet('font :bold  10pt')
        self.labelMoy.setMaximumWidth(120)
        self.labelMoy.setAlignment(Qt.AlignCenter)
        
       
        self.moyBox=QSpinBox()
        self.moyBox.setMaximumWidth(60)
        self.moyBox.setStyleSheet('font :bold  8pt')
        self.moyBox.setMaximum(100)
        self.moyBox.setValue(1)
        
        hboxMoy=QHBoxLayout()

        hboxMoy.addWidget(self.labelMoy)
        hboxMoy.addWidget(self.moyBox)
        
        hboxMoy.setSpacing(1)
        
        hboxMoy.setContentsMargins(5, 17, 200, 0)
        hbox2Moy=QHBoxLayout()
        hbox2Moy.addLayout(hboxMoy)
        hbox2Moy.setSizeConstraint(QtGui.QLayout.SetFixedSize)
        self.widgetMoy=QWidget(self)
        self.widgetMoy.setLayout(hbox2Moy)
        
        self.dockMoy=QDockWidget(self)
        self.dockMoy.setWidget(self.widgetMoy)
        
        
        
        
        
        self.graph=GRAPHCUT(symbol=None,title='Spectra',pen='w',label='Wavelenght (nm)',labelY='int')
        self.widgetRange=self.graph.widgetRange
        self.widgetRange.labelXmin.setText("Wavelenght(nm) Min ")
        self.widgetRange.labelXmax.setText("Wavelenght(nm) Max ")
        self.dockControl.setTitleBarWidget(QWidget()) # to ovoid title
        self.graph.addDockWidget(Qt.TopDockWidgetArea,self.dockControl)
        self.dockTrig.setTitleBarWidget(QWidget())
        self.graph.addDockWidget(Qt.TopDockWidgetArea,self.dockTrig)
        self.dockShutter.setTitleBarWidget(QWidget())
        self.graph.addDockWidget(Qt.TopDockWidgetArea,self.dockShutter)
        self.dockMoy.setTitleBarWidget(QWidget())
        self.graph.addDockWidget(Qt.TopDockWidgetArea,self.dockMoy)
        
        
        
        self.hbox=QHBoxLayout()
        
        
        self.hbox.addWidget(self.graph)
        
        self.vLatBox=QVBoxLayout()
        # hboxRange=QHBoxLayout()
        # hboxRange.setAlignment(Qt.AlignCenter)
        # labelRange=QLabel('Range')
        # labelRange.setStyleSheet("font: bold 20pt;color:white")
        # hboxRange.addWidget(labelRange)
        # self.vLatBox.addLayout(hboxRange)
        self.vLatBox.addWidget(self.widgetRange)
        
        
        self.vLatBox.addStretch(0)
        self.vLatBox.addWidget(self.motor)
        self.vLatBox.addStretch(0)
        
        self.vLatBox.addWidget(self.scanWidget)
        # self.vLatBox.setContentsMargins(0,0,0,0)
        # self.vLatBox.setStretch(5,0)
        self.hbox.addLayout(self.vLatBox)
        self.hbox.setStretch(0, 3)
        #self.scanWidget.setStyleSheet('border-color:w')
        
        WidgetSpectro=QWidget()
        WidgetSpectro.setLayout(self.hbox)
        
        
        self.tabs=QTabWidget()
        self.tab0=WidgetSpectro
        
        self.tabs.addTab(self.tab0,'   Spectro & Motors    ')
        
        
        self.WidgetResult=SEERESULT(confpath=self.confpath+'confFrog.ini') # graph 2D data vs motor position
        
        # self.hresultLayout=QHBoxLayout()
        # # self.hresultLayout.addWidget(self.visualisation)
        # WidgetResult.setLayout(self.hresultLayout)
        self.tab1=self.WidgetResult
        
        self.tabs.addTab(self.tab1,'    Results    ')
        
        
        self.setCentralWidget(self.tabs)
    
        self.threadOneAcq=ThreadOneAcq(self)
        self.threadOneAcq.newDataRun.connect(self.newImageReceived)#,QtCore.Qt.DirectConnection)
        self.threadOneAcq.newStateCam.connect(self.stateCam)
        self.threadRunAcq=ThreadRunAcq(self)
        self.threadRunAcq.newDataRun.connect(self.newImageReceived)
        
        self.threadBgAcq=THREADBGACQ(self)
        self.threadBgAcq.newDataRun.connect(self.newBgReceived)
        self.threadBgAcq.newStateCam.connect(self.stateCam)
        
    def actionButton(self): 
        '''action when button are pressed
        '''
        self.runButton.clicked.connect(self.acquireMultiImage)
        self.snapButton.clicked.connect(self.acquireOneImage)
        self.stopButton.clicked.connect(self.stopAcq)
        self.bgButton.clicked.connect(self.bgAcq)
        
        
        self.shutterBox.editingFinished.connect(self.shutter)    
        self.hSliderShutter.sliderReleased.connect(self.mSliderShutter)
        self.moyBox.editingFinished.connect(self.MoyenneAct)    
        self.scanWidget.acqMain.connect(self.acquireScan)
        
        self.scanWidget.scanStop.connect(self.endScan)
        
        self.scanWidget.startOn.connect(self.ResetData)
        
        # self.trigg.currentIndexChanged.connect(self.trigger)
    
    def MoyenneAct(self):
        self.moyenne=(self.moyBox.value())
        self.scanWidget.val_time.setValue(0.2+self.moyenne*self.shutterBox.value()/1000)
        #print(self.moyenne)
        
    def ResetData(self):
        ##â—™ reset data when scan start
        self.MatData=[]
        self.MatFs=[]
        # print('reset DATMAT')
        
    def shutter (self):
        '''
        set exposure time 
        '''
        
        sh=self.shutterBox.value() # 
        self.hSliderShutter.setValue(sh) # set value of slider
        time.sleep(0.1)
        self.spectrometer.integration_time_micros(sh*1000) # en micro
        # print(sh)
        self.confFrog.setValue('VISU'+'/shutter',sh)
        self.MoyenneAct()
    
    
    def mSliderShutter(self): # for shutter slider 
        sh=self.hSliderShutter.value() 
        self.shutterBox.setValue(sh) # 
        self.spectrometer.integration_time_micros(sh*1000)
        self.confFrog.setValue('VISU'+'/shutter',sh)
    
    def acquireMultiImage(self):
        ''' 
            start the acquisition thread
        '''
        
        self.runButton.setEnabled(False)
        self.runButton.setStyleSheet("QToolButton:!pressed{border-image: url(%s);background-color: gray ;border-color: gray;}""QToolButton:pressed{image: url(%s);background-color: gray ;border-color: gray}"%(self.iconPlay,self.iconPlay))
        self.snapButton.setEnabled(False)
        self.snapButton.setStyleSheet("QToolButton:!pressed{border-image: url(%s);background-color: gray ;border-color: gray;}""QToolButton:pressed{image: url(%s);background-color: gray ;border-color: gray}"%(self.iconSnap,self.iconSnap))
        self.stopButton.setEnabled(True)
        self.stopButton.setStyleSheet("QToolButton:!pressed{border-image: url(%s);background-color: transparent ;border-color: gray;}""QToolButton:pressed{image: url(%s);background-color: gray ;border-color: gray}"%(self.iconStop,self.iconStop) )
        self.trigg.setEnabled(False)
        self.bgButton.setEnabled(False)
        self.bgButton.setStyleSheet("QToolButton:!pressed{border-image: url(%s);background-color: gray ;border-color: gray;}""QToolButton:pressed{image: url(%s);background-color: gray ;border-color: gray}"%(self.iconBg,self.iconBg))
        
        self.threadRunAcq.newRun() # to set stopRunAcq=False
        self.threadRunAcq.start()
        self.camIsRunnig=True
    
    def acquireScan(self,pos,nbShoot):
        #acquire on image with scan program
        self.scanWidget.AcqRunning(acqRunning=True)
        self.nbShoot=nbShoot # numero du shoot
        
        self.acquireOneImage()
        self.position=pos # on recupere la valeur de la postion moteur a chaque acquisition
       
    
    def acquireOneImage(self):
        '''Start on acquisition
        '''
        # print('acquire on image spectro')
        self.imageReceived=False
        self.runButton.setEnabled(False)
        self.runButton.setStyleSheet("QToolButton:!pressed{border-image: url(%s);background-color: gray ;border-color: gray;}""QToolButton:pressed{image: url(%s);background-color: gray ;border-color: gray}"%(self.iconPlay,self.iconPlay))
        self.snapButton.setEnabled(False)
        self.snapButton.setStyleSheet("QToolButton:!pressed{border-image: url(%s);background-color: gray ;border-color: gray;}""QToolButton:pressed{image: url(%s);background-color: gray ;border-color:gray}"%(self.iconSnap,self.iconSnap))
        self.bgButton.setEnabled(False)
        self.bgButton.setStyleSheet("QToolButton:!pressed{border-image: url(%s);background-color: gray ;border-color: gray;}""QToolButton:pressed{image: url(%s);background-color: gray ;border-color: gray}"%(self.iconBg,self.iconBg))
        
        
        self.stopButton.setEnabled(True)
        self.stopButton.setStyleSheet("QToolButton:!pressed{border-image: url(%s);background-color: transparent ;border-color: gray;}""QToolButton:pressed{image: url(%s);background-color: gray ;border-color: gray}"%(self.iconStop,self.iconStop) )
        self.trigg.setEnabled(False)
        self.camIsRunnig=True
        self.threadOneAcq.newRun() # to set stopRunAcq=False
        self.threadOneAcq.start()
    
    
    def bgAcq(self):
        
        self.runButton.setEnabled(False)
        self.runButton.setStyleSheet("QToolButton:!pressed{border-image: url(%s);background-color: gray ;border-color: gray;}""QToolButton:pressed{image: url(%s);background-color: gray ;border-color: gray}"%(self.iconPlay,self.iconPlay))
        self.snapButton.setEnabled(False)
        self.snapButton.setStyleSheet("QToolButton:!pressed{border-image: url(%s);background-color: gray ;border-color: gray;}""QToolButton:pressed{image: url(%s);background-color: gray ;border-color:gray}"%(self.iconSnap,self.iconSnap))
        
        self.bgButton.setEnabled(False)
        self.bgButton.setStyleSheet("QToolButton:!pressed{border-image: url(%s);background-color: gray ;border-color: gray;}""QToolButton:pressed{image: url(%s);background-color: gray ;border-color: gray}"%(self.iconBg,self.iconBg))
        
        self.stopButton.setEnabled(True)
        self.stopButton.setStyleSheet("QToolButton:!pressed{border-image: url(%s);background-color: transparent ;border-color: gray;}""QToolButton:pressed{image: url(%s);background-color: gray ;border-color: gray}"%(self.iconStop,self.iconStop) )
        self.trigg.setEnabled(False)
        self.camIsRunnig=True
        self.threadBgAcq.newRun()
        self.threadBgAcq.start()
    
    def endScan (self):
        # at the end of the scan we plot MatData( 2d matrix of specta) vs MatFs (vector of the position of the motor) 
        self.MatDataNumpy=np.array(self.MatData)
        self.MatFsNumpy=np.array(self.MatFs)
    
        self.wavelengths=np.array(self.wavelengths)
        self.WidgetResult.newDataReceived(self.MatDataNumpy,axisX=self.MatFsNumpy,axisY=self.wavelengths)
        print('  ')
        print('  ')
        print(' ___RESULTS___')
        print('  dim matrice result :',self.MatDataNumpy.shape)
        print('  dim matrice fs :',len(self.MatFsNumpy))
        print('  dim matrice wavelengths : ',len(self.wavelengths))
        print('  ')
        print('  ')
        
        #self.MatFs=[]
        self.tabs.setCurrentIndex(1)
        self.stopAcq()
        
    
    def stateCam(self,state):
        self.camIsRunnig=state
        
    def newBgReceived(self,data):
        
        self.bg=data
        self.bgSoustract.setChecked(True)
        if self.camIsRunnig is False:
            self.stopAcq()
            
    def newImageReceived(self,data):
        
        if self.bgSoustract.isChecked():
            self.data=data-self.bg
            
        else :
            self.data=data
       
        self.graph.PLOT(self.data,axis=self.wavelengths)
       
        # self.MatData=np.append(self.MatData,self.data)
        self.MatData.append(self.data)
        # print(self.position)
        self.MatFs.append(self.position)
        
        self.scanWidget.AcqRunning(acqRunning=False)
        
        if self.camIsRunnig is False:
            self.stopAcq()
    
    def nbShotAction(self):
        '''
        number of snapShot
        '''
        nbShot, ok=QInputDialog.getInt(self,'Number of SnapShot ','Enter the number of snapShot ')
        if ok:
            self.nbShot=int(nbShot)
            if self.nbShot<=0:
                self.nbShot=1
               
               
    def stopAcq(self):
        '''Stop  acquisition
        '''
        
        self.runButton.setEnabled(True)
        self.runButton.setStyleSheet("QToolButton:!pressed{border-image: url(%s);background-color: transparent ;border-color: gray;}""QToolButton:pressed{image: url(%s);background-color: gray ;border-color: gray}"%(self.iconPlay,self.iconPlay))
        self.snapButton.setEnabled(True)
        self.snapButton.setStyleSheet("QToolButton:!pressed{border-image: url(%s);background-color: transparent ;border-color: gray;}""QToolButton:pressed{image: url(%s);background-color: gray ;border-color: gray}"%(self.iconSnap,self.iconSnap))
        
        self.bgButton.setEnabled(True)
        self.bgButton.setStyleSheet("QToolButton:!pressed{border-image: url(%s);background-color: transparent ;border-color: gray;}""QToolButton:pressed{image: url(%s);background-color: gray ;border-color: gray}"%(self.iconBg,self.iconBg))
        
        
        
        self.stopButton.setEnabled(False)
        self.stopButton.setStyleSheet("QToolButton:!pressed{border-image: url(%s);background-color: gray ;border-color: gray;}""QToolButton:pressed{image: url(%s);background-color: gray ;border-color: gray}"%(self.iconStop,self.iconStop) )
        self.trigg.setEnabled(True)  
        
        self.threadRunAcq.stopThreadRunAcq()
    
    def closeEvent(self,event):
        # when the window is closed
        # to do close motor and spectro
        print('close')
Example #22
0
# Print a line to quickly spot the start of the output
print('\n--------------------------------------------')

# Check that the number of arguments is correct
# NUMARG = 2
# if len(sys.argv)!=NUMARG:
# 	print("Function expects "+str(NUMARG-1)+" argument(s). Example: [...]")
# 	exit()

# Define arduino address
arduinoPI = serial.Serial(arduinoAddress, baudrate=38400, timeout=1)

# Obtain the spectrometer object
devices = list_devices()
print(devices)
spec = Spectrometer(devices[0])

# Obtain thermal camera object
dev, ctx = openThermalCamera()

# Initialize arrays in which to save outputs
y1Save = []
y2Save = []

Niter = u1Vec.shape[1]
for i in range(Niter):

    iterString = "\nIteration %d out of %d" % (i, Niter)
    print(iterString)

    # Send inputs
Example #23
0
def test_cant_find_serial():
    exc = Spectrometer._backend.SeaBreezeError
    with pytest.raises(exc):
        Spectrometer.from_serial_number("i-do-not-exist")
Example #24
0
class DAQ_1DViewer_Seabreeze(DAQ_Viewer_base):
    """
    """
    # Upon initialisation
    devices = list_devices()

    #Supports pseudo hardware-averaging
    hardware_averaging = True

    params = comon_parameters + [{
        'title': 'Device:',
        'name': 'device',
        'type': 'list',
        'limits': devices
    }, {
        'title': 'Integration (ms):',
        'name': 'integration',
        'type': 'float',
        'value': 1.0
    }, {
        'title':
        'Advanced:',
        'name':
        'advanced',
        'type':
        'group',
        'children': [
            {
                'title': 'Serial Number:',
                'name': 'serial_number',
                'type': 'str',
                'value': "",
                'readonly': True
            },
            {
                'title': 'Non Linearity correction:',
                'name': 'correct_non_linearity',
                'type': 'bool',
                'value': False
            },
            {
                'title': 'Max Intensity',
                'name': 'max_intensity',
                'type': "float",
                'value': 65535,
                'readonly': True
            },
            {
                'title': 'Pixels:',
                'name': 'pixels',
                'type': 'int',
                'value': 2048,
                'readonly': True
            },
            {
                'title': 'Dark Channels:',
                'name': 'dark_channels',
                'type': 'int',
                'value': 10,
                'readonly': True
            },
            {
                'title': 'Readout Time (ms)',
                'name': 'readout_time',
                'type': 'float',
                'value': 666,
                'readonly': True
            },
        ]
    }]

    def __init__(self, parent=None, params_state=None):
        super().__init__(parent, params_state)
        self.x_axis = None

    def commit_settings(self, param):
        """
        """
        if param.name() == "integration":
            self.controller.integration_time_micros(param.value() * 1000)
            # There is no way to get feedback from the spectrometer on the currently set integration time
        # elif ...
        ##

    def ini_detector(self, controller=None):
        """Detector communication initialization

        Parameters
        ----------
        controller: (object) custom object of a PyMoDAQ plugin (Slave case). None if only one detector by controller (Master case)

        Returns
        -------
        self.status (edict): with initialization status: three fields:
            * info (str)
            * controller (object) initialized controller
            *initialized: (bool): False if initialization failed otherwise True
        """

        try:
            self.status.update(
                edict(initialized=False,
                      info="",
                      x_axis=None,
                      y_axis=None,
                      controller=None))
            if self.settings.child('controller_status').value() == "Slave":
                if controller is None:
                    raise Exception(
                        'no controller has been defined externally while this detector is a slave one'
                    )
                else:
                    self.controller = controller
            else:
                # From what I understand this will just get the spectro currently selected in the list
                dvc = self.settings.child('device').value()
                self.controller = Spectrometer(dvc)
                self.controller.open()
                #####################################

            # Oceanoptics spectrometers (at least the ones i Know) have fixed axis
            # get inactive pixels
            c0 = self.controller.f.spectrometer.get_electric_dark_pixel_indices(
            )[-1]
            self.settings.child('advanced').child('dark_channels').setValue(c0)
            # get the x_axis
            data_x_axis = self.controller.wavelengths(
            )  # Way to get the x axis
            data_x_axis = data_x_axis[c0:]  # Get rid of the dark pixels
            self.x_axis = Axis(data=data_x_axis,
                               label='wavelength',
                               units='nm')
            self.emit_x_axis()

            # Get the name
            specname = f"Ocean Insight {self.controller.model}"

            # initialize viewers pannel with the future type of data
            self.data_grabed_signal_temp.emit([
                DataFromPlugins(name=specname,
                                data=[np.zeros_like(data_x_axis)],
                                dim='Data1D',
                                labels=['Intensity'],
                                x_axis=self.x_axis),
            ])

            # Update the parameters
            # Here we need to do a few things. Get the integration time limits and set it in the settings
            tlimits = np.array(
                self.controller.integration_time_micros_limits) / 1000
            self.settings.child('integration').setLimits(tlimits)
            # Here we need to update the advanced parameters
            advanced_settings = self.settings.child('advanced')
            sn = self.controller.serial_number
            advanced_settings.child('serial_number').setValue(sn)
            # non linearity coefficients
            nlc_feat = self.controller.f.nonlinearity_coefficients
            if nlc_feat is not None and not any(
                    np.isnan(nlc_feat.get_nonlinearity_coefficients())):
                advanced_settings.child('correct_non_linearity').setValue(True)
            else:
                advanced_settings.child('correct_non_linearity').setValue(
                    False)
                advanced_settings.child('correct_non_linearity').setOpts(
                    enabled=False)

            # measure the readout time
            Nperf = 200
            self.settings.child('integration').setValue(
                tlimits[0])  # Update the parameter value to the lower limit
            self.controller.integration_time_micros(
                tlimits[0] * 1000)  # Set the readout time to lower limit
            perf = timeit(lambda: self.controller.intensities(),
                          number=Nperf)  # time the execution of code in [s]
            self.settings.child('advanced').child('readout_time').setValue(
                1000 * perf / Nperf)  # set the settings

            ##############################

            self.status.info = f"Initialized {specname} spectrometer"
            self.status.initialized = True
            self.status.controller = self.controller
            return self.status

        except Exception as e:
            self.emit_status(
                ThreadCommand('Update_Status',
                              [getLineInfo() + str(e), 'log']))
            self.status.info = getLineInfo() + str(e)
            self.status.initialized = False
            return self.status

    def close(self):
        """
        Terminate the communication protocol
        """
        self.controller.close()
        ##

    def grab_data(self, Naverage=1, **kwargs):
        """
        Parameters
        ----------
        Naverage: (int) Number of hardware averaging
        kwargs: (dict) of others optionals arguments
        """
        nlc = self.settings.child('advanced').child(
            'correct_non_linearity').value()
        c0 = self.settings.child('advanced').child('dark_channels').value()
        # synchrone version (blocking function)
        # Pseudo-hardware-averaging
        if Naverage > 1:
            data = [
                self.controller.intensities(correct_nonlinearity=nlc)[c0:]
                for i in range(Naverage)
            ]
            data = np.array(data)
            data = data.mean(0)
        # Otherwise normal single-acquisition
        else:
            data = self.controller.intensities(correct_nonlinearity=nlc)[c0:]

        data_emit = DataFromPlugins(name='oceanseabreeze',
                                    data=[data],
                                    dim='Data1D',
                                    labels=['spectrum'])

        self.data_grabed_signal.emit([data_emit])
        #########################################################

    def callback(self):
        """optional asynchrone method called when the detector has finished its acquisition of data"""
        pass
        # data_tot = self.controller.your_method_to_get_data_from_buffer()
        # self.data_grabed_signal.emit([DataFromPlugins(name='Mock1', data=data_tot,
        #                                           dim='Data1D', labels=['dat0', 'data1'])])

    def stop(self):
        pass
Example #25
0
class OceanDevice:
    def __init__(self, device_id, message_queue=None):

        # if passed a string representation of a DeviceID, deserialize it
        if type(device_id) is str:
            device_id = DeviceID(label=device_id)

        self.device_id = device_id
        self.message_queue = message_queue

        #self.lock = threading.Lock()

        self.connected = False

        # Receives ENLIGHTEN's 'change settings' commands in the spectrometer
        # process. Although a logical queue, has nothing to do with multiprocessing.
        self.command_queue = []

        self.immediate_mode = False

        self.settings = SpectrometerSettings(self.device_id)
        self.summed_spectra = None
        self.sum_count = 0
        self.session_reading_count = 0
        self.take_one = False
        self.failure_count = 0

        self.process_id = os.getpid()
        self.last_memory_check = datetime.datetime.now()
        self.last_battery_percentage = 0
        self.init_lambdas()

    def connect(self):
        self.device = None
        try:
            devices = list_devices()
        except:
            devices = list_devices()
        for device in devices:
            pyusb_device = device._raw_device.pyusb_device
            if pyusb_device.idVendor == self.device_id.vid and pyusb_device.idProduct == self.device_id.pid:
                self.device = device
        if self.device == None:
            log.error("Ocean Device: No ocean device found. Returning")
            self.message_queue.put_nowait(None)
            return False
        self.spec = Spectrometer(self.device)
        self.settings.eeprom.model = self.device.model
        self.settings.eeprom.serial_number = self.device.serial_number
        self.settings.eeprom.active_pixels_horizontal = self.device.features[
            'spectrometer'][0]._spectrum_num_pixel
        self.settings.eeprom.detector = "Ocean"  # Ocean API doesn't have access to detector info
        return True

    def init_lambdas(self):
        f = {}
        f["integration_time_ms"] = lambda x: self.spec.integration_time_micros(
            int(round(x * 1000)))  # conversion from millisec to microsec
        self.lambdas = f

    def acquire_data(self):
        self.settings.wavelengths = self.spec.wavelengths(
        )  # setting wavelengths one init doesn't work for some reaons
        reading = self.take_one_averaged_reading()
        return reading

    def take_one_averaged_reading(self):
        averaging_enabled = (self.settings.state.scans_to_average > 1)

        if averaging_enabled and not self.settings.state.free_running_mode:
            # collect the entire averaged spectrum at once (added for
            # BatchCollection with laser delay)
            #
            # So: we're NOT in "free-running" mode, so we're basically being
            # slaved to parent process and doing exactly what is requested
            # "on command."  That means we can perform a big, heavy blocking
            # scan average all at once, because they requested it.
            self.sum_count = 0
            loop_count = self.settings.state.scans_to_average
        else:
            # we're in free-running mode
            loop_count = 1

        log.debug("take_one_averaged_reading: loop_count = %d", loop_count)

        # either take one measurement (normal), or a bunch (blocking averaging)
        reading = None
        for loop_index in range(0, loop_count):

            # start a new reading
            # NOTE: reading.timestamp is when reading STARTED, not FINISHED!
            reading = Reading(self.device_id)

            # TODO...just include a copy of SpectrometerState? something to think
            # about. That would actually provide a reason to roll all the
            # temperature etc readouts into the SpectrometerState class...
            try:
                reading.integration_time_ms = self.settings.state.integration_time_ms
                reading.laser_power_perc = self.settings.state.laser_power_perc
                reading.laser_power_mW = self.settings.state.laser_power_mW
                reading.laser_enabled = self.settings.state.laser_enabled
                reading.spectrum = list(self.spec.intensities())
            except usb.USBError:
                self.failure_count += 1
                log.error(
                    f"Ocean Device: encountered USB error in reading for device {self.device}"
                )

            if reading.spectrum is None or reading.spectrum == []:
                if self.failure_count > 3:
                    return False

            if not reading.failure:
                if averaging_enabled:
                    if self.sum_count == 0:
                        self.summed_spectra = [
                            float(i) for i in reading.spectrum
                        ]
                    else:
                        log.debug(
                            "device.take_one_averaged_reading: summing spectra"
                        )
                        for i in range(len(self.summed_spectra)):
                            self.summed_spectra[i] += reading.spectrum[i]
                    self.sum_count += 1
                    log.debug(
                        "device.take_one_averaged_reading: summed_spectra : %s ...",
                        self.summed_spectra[0:9])

            # count spectra
            self.session_reading_count += 1
            reading.session_count = self.session_reading_count
            reading.sum_count = self.sum_count

            # have we completed the averaged reading?
            if averaging_enabled:
                if self.sum_count >= self.settings.state.scans_to_average:
                    reading.spectrum = [
                        x / self.sum_count for x in self.summed_spectra
                    ]
                    log.debug(
                        "device.take_one_averaged_reading: averaged_spectrum : %s ...",
                        reading.spectrum[0:9])
                    reading.averaged = True

                    # reset for next average
                    self.summed_spectra = None
                    self.sum_count = 0
            else:
                # if averaging isn't enabled...then a single reading is the
                # "averaged" final measurement (check reading.sum_count to confirm)
                reading.averaged = True

            # were we told to only take one (potentially averaged) measurement?
            if self.take_one and reading.averaged:
                log.debug("completed take_one")
                self.change_setting("cancel_take_one", True)

        log.debug("device.take_one_averaged_reading: returning %s", reading)
        if reading.spectrum is not None and reading.spectrum != []:
            self.failure_count = 0
        # reading.dump_area_scan()
        return reading

    def change_setting(self, setting, value):
        if setting == "scans_to_average":
            self.sum_count = 0
            self.settings.state.scans_to_average = int(value)
            return
        f = self.lambdas.get(setting, None)
        if f is None:
            # quietly fail no-ops
            return False

        return f(value)
Example #26
0
    def __init__(self,
                 int_time=None,
                 wavelengths=None,
                 device=None,
                 from_index=None,
                 to_index=None,
                 intensities=None,
                 **kwargs):
        # {{{
        """
        Initializes the instance with the default values, unless specified otherwise.
        If you wish to use all the default values except for a few, specify them with kwargs.
        """

        if device is not None:
            self.device = device

            if self.device != Spectrometer:
                raise TypeError(
                    "Invalid type for device attribute. Please enter a seabreeze Spectrometer instance."
                )

        if wavelengths is not None:
            if isinstance(wavelengths, (np.ndarray, list, tuple)):
                self._wavel = np.array(wavelengths)
            else:
                raise TypeError(
                    "Invalid type for wavelengths array. Please enter a numpy array, a list, or a tuple."
                )
        else:
            # Will use the wavelenghts array provided by the spectrometer by default

            if not self.device:
                """
                If by this point the spectrometer hasn't been specified, it will use the first
                one seabreeze finds by default
                """

                if list_devices():
                    self.device = Spectrometer(list_devices()[0])
                else:
                    raise RuntimeError("No spectrometers found.")
                self._warn(
                    "No spectrometer object passed. Using {} by default.".
                    format(self.device))

            self._wavel = np.array(self.device.wavelengths())
            self._warn(
                "No wavelength array provided. Using the device's wavelength array by default."
            )

        if int_time is not None:
            self.int_time = int(int_time)

        if from_index is not None:
            if isinstance(from_index, (int, float)):
                self.from_index = from_index
            else:
                raise TypeError(
                    "to_index and from_index must be either integers for proper indexes, or floats, for wavelengths."
                )

        if to_index is not None:
            if isinstance(to_index, (int, float)):
                self.to_index = to_index
            else:
                raise TypeError(
                    "to_index and from_index must be either integers for proper indexes, or floats, for wavelengths."
                )

        if 'correct_nl' in kwargs:
            self.correct_nl = kwargs['correct_nl']

        if 'correct_dc' in kwargs:
            self.correct_dc = kwargs['correct_dc']

        if intensities is not None:
            if isinstance(intensities, (np.ndarray, list, tuple)):
                self._inten = np.array(intensities)
            else:
                raise TypeError(
                    "Invalid type for intensities array. Please enter a numpy array, a list, or a tuple."
                )
        else:
            self._inten = self._measure_inten()
Example #27
0
class Spectrum(object):
    """
    Class variables. Mainly default values that are used whenever their instance counterparts
    are not specified when initializing a Spectrum object.
    """

    # {{{
    device = None  # will use the first spectrometer seabreeze finds by default
    correct_nl = False  # correct non-linearity
    correct_dc = False  # correct dark counts
    int_time = None  # integration time in microseconds
    _inten = None  # intensities for internal use
    _wavel = None  # wavelengths for internal use
    from_index = None
    to_index = None
    wavel_slice = None
    opt_warnings = True  # determines whether or not to show warnings
    _current_int_time = None  # keeps track of the integration time most recently set in the spectrometer

    # }}}

    def __init__(self,
                 int_time=None,
                 wavelengths=None,
                 device=None,
                 from_index=None,
                 to_index=None,
                 intensities=None,
                 **kwargs):
        # {{{
        """
        Initializes the instance with the default values, unless specified otherwise.
        If you wish to use all the default values except for a few, specify them with kwargs.
        """

        if device is not None:
            self.device = device

            if self.device != Spectrometer:
                raise TypeError(
                    "Invalid type for device attribute. Please enter a seabreeze Spectrometer instance."
                )

        if wavelengths is not None:
            if isinstance(wavelengths, (np.ndarray, list, tuple)):
                self._wavel = np.array(wavelengths)
            else:
                raise TypeError(
                    "Invalid type for wavelengths array. Please enter a numpy array, a list, or a tuple."
                )
        else:
            # Will use the wavelenghts array provided by the spectrometer by default

            if not self.device:
                """
                If by this point the spectrometer hasn't been specified, it will use the first
                one seabreeze finds by default
                """

                if list_devices():
                    self.device = Spectrometer(list_devices()[0])
                else:
                    raise RuntimeError("No spectrometers found.")
                self._warn(
                    "No spectrometer object passed. Using {} by default.".
                    format(self.device))

            self._wavel = np.array(self.device.wavelengths())
            self._warn(
                "No wavelength array provided. Using the device's wavelength array by default."
            )

        if int_time is not None:
            self.int_time = int(int_time)

        if from_index is not None:
            if isinstance(from_index, (int, float)):
                self.from_index = from_index
            else:
                raise TypeError(
                    "to_index and from_index must be either integers for proper indexes, or floats, for wavelengths."
                )

        if to_index is not None:
            if isinstance(to_index, (int, float)):
                self.to_index = to_index
            else:
                raise TypeError(
                    "to_index and from_index must be either integers for proper indexes, or floats, for wavelengths."
                )

        if 'correct_nl' in kwargs:
            self.correct_nl = kwargs['correct_nl']

        if 'correct_dc' in kwargs:
            self.correct_dc = kwargs['correct_dc']

        if intensities is not None:
            if isinstance(intensities, (np.ndarray, list, tuple)):
                self._inten = np.array(intensities)
            else:
                raise TypeError(
                    "Invalid type for intensities array. Please enter a numpy array, a list, or a tuple."
                )
        else:
            self._inten = self._measure_inten()
# }}}

    def _measure_inten(self, samples=1, boxcar=False, boxcar_len=0):
        # {{{
        if self.int_time and Spectrum._current_int_time != self.int_time:
            self.device.integration_time_micros(self.int_time)
            sleep(
                2
            )  # accounting for the delay of the spectrometer to change its integration time
            Spectrum._current_int_time = self.int_time

        return self.device.intensities(self.correct_dc, self.correct_nl)
# }}}

    def write_to_file(self, file_path=None, save_fields=True, **kwargs):
        # {{{
        """
        Stores spectrum in a .dat text file, using a format that is easy to parse
        in gnu octave, R or any other programming language, or visualize in gnuplot,
        or any spreadsheet program.
        """

        overwrite = kwargs['overwrite'] if 'overwrite' in kwargs else None
        if path.exists(file_path):
            if overwrite:
                self._warn(
                    f"WARNING: File {file_path} exists. Overwriting it.")
            else:
                raise RuntimeError(
                    f"File {file_path} already exists. Pass 'overwrite=True' if you are sure you want to overwrite it."
                )

        # set this kwarg to True if you wish to store the entire wavelengths and intensities array,
        # as opposed to just the array delimited by from_index and to_index
        entire_spectrum = kwargs[
            'entire_spectrum'] if 'entire_spectrum' in kwargs else False
        only_wavelengths = kwargs[
            'only_wavelengths'] if 'only_wavelengths' in kwargs else False
        only_intensities = kwargs[
            'only_intensities'] if 'only_intensities' in kwargs else False

        to_save = {'int_time', 'correct_nl',
                   'correct_dc'}  # fields that will be written to the file
        if entire_spectrum:  # will only write these fields if entire_spectrum is set to True
            to_save = to_save.union({'from_index', 'to_index'})

        if not file_path and isinstance(file_path, str):
            raise (ValueError(
                "Please pass a string as the file path wherein to save the spectrum."
            ))

        with open(file_path, 'w+') as arq:
            gen_comments = (f'# {name} = {value}\n'
                            for name, value in vars(self).items()
                            if name in to_save)
            arq.writelines(gen_comments)

            if only_wavelengths:
                if entire_spectrum:
                    gen_wavel_inten = (f'{wavel}\n' for wavel in self._wavel)
                else:
                    gen_wavel_inten = (f'{wavel}\n'
                                       for wavel in self.wavelengths)
            elif only_intensities:
                if entire_spectrum:
                    gen_wavel_inten = (f'{inten}\n' for inten in self._inten)
                else:
                    gen_wavel_inten = (f'{inten}\n'
                                       for inten in self.intensities)
            else:
                if entire_spectrum:
                    gen_wavel_inten = (f'{wavel}\t{inten}\n'
                                       for wavel, inten in zip(*self._spec))
                else:
                    gen_wavel_inten = (f'{wavel}\t{inten}\n'
                                       for wavel, inten in zip(*self.spectrum))

            arq.writelines(gen_wavel_inten)
# }}}

    def set_wavel_slice(self):
        # {{{
        from_index = self.from_index if self.from_index else 0
        to_index = self.to_index if self.to_index else -1

        if type(
                from_index
        ) == float:  # assumes the value is a wavelength if it has a decimal point
            from_index = self.find_wavel_index(self._wavel, from_index)
        elif type(
                from_index
        ) == int:  # assumes the value is a proper index if it is an integer
            if abs(from_index) > self._wavel.size:
                raise IndexError(
                    "Invalid index of {} for wavelength array of size {}".
                    format(from_index, self._wavel.size))
        elif type(from_index) == str:
            try:
                float(from_index)
            except ValueError:
                raise TypeError(
                    "Invalid type of {} for wavelength index. Please enter either a float for a wavelength or an integer for a proper index."
                    .format(from_index))
            if '.' in from_index:
                from_index = self.find_wavel_index(self._wavel,
                                                   float(from_index))
            else:
                from_index = int(from_index)
        else:
            raise TypeError(
                "Invalid type of {} for wavelength index. Please enter either a float for a wavelength or an integer for a proper index."
                .format(from_index))

        if type(
                to_index
        ) == float:  # assumes the value is a wavelength if it has a decimal point
            to_index = self.find_wavel_index(self._wavel, to_index)
        elif type(
                to_index
        ) == int:  # assumes the value is a proper index if it is an integer
            if abs(to_index) > self._wavel.size:
                raise IndexError(
                    "Invalid index of {} for wavelength array of size {}".
                    format(from_index, self._wavel.size))
        elif type(to_index) == str:
            try:
                float(to_index)
            except ValueError:
                raise TypeError(
                    "Invalid type of {} for wavelength index. Please enter either a float for a wavelength or an integer for a proper index."
                    .format(to_index))
            if '.' in to_index:
                to_index = self.find_wavel_index(self._wavel, float(to_index))
            else:
                to_index = int(to_index)
        else:
            raise TypeError(
                "Invalid type of {} for wavelength index. Please enter either a float for a wavelength or an integer for a proper index."
                .format(to_index))
        self.wavel_slice = slice(from_index, to_index)
# }}}

    def get_wavel_slice(self):
        if self.wavel_slice:  # {{{
            pass
        else:
            self.set_wavel_slice()
        return self.wavel_slice  # }}}

    @property
    def _spec(self):
        return self._wavel, self._inten

    @property
    def spectrum(self):
        return self.wavelengths, self.intensities

    @property
    def wavelengths(self):
        return self._wavel[self.get_wavel_slice()]

    @property
    def intensities(self):
        return self._inten[self.get_wavel_slice()]

    @classmethod
    def from_file(cls, inten_wavel_file=None, **kwargs):
        # {{{
        """
        Creates a spectrum instance with the wavelengths and/or intensities read
        from a text file. Additionally, it looks for key-word arguments at the first
        few lines of the file. If the same kwargs are passed to this function, they
        take precedence.
        """

        wavel_file = kwargs['wavel_file'] if 'wavel_file' in kwargs else None
        inten_file = kwargs['inten_file'] if 'inten_file' in kwargs else None
        inten_array = None
        wavel_array = None
        new_kwargs = {}

        if 'inten_wavel_file' in kwargs:
            inten_Wavel_file = kwargs['inten_wavel_file']

        if inten_wavel_file:
            wavel_array, inten_array, new_kwargs = cls._read_file(
                inten_wavel_file)

        if wavel_file:
            wavel_array, _, new_kwargs = cls._read_file(wavel_file)

        if inten_file:
            inten_array, _, new_kwargs = cls._read_file(inten_file)

        if not inten_file and not inten_wavel_file and not wavel_file:
            cls._warn(
                "WARNING: Instantiating a spectrum with function from_file, but no file path arguments were passed."
            )

        new_kwargs['intensities'] = inten_array
        new_kwargs['wavelengths'] = wavel_array
        new_kwargs.update(kwargs)

        return cls(**new_kwargs)
# }}}

    @staticmethod
    def _read_file(text_file):
        # {{{
        """
        Used internally by the class method from_file. Returns as many numpy arrays
        as there are columns in the file, and a dictionary with whatever comments
        (prefaced by #) it finds.
        """

        dict_args = {}
        col1 = []
        col2 = []

        with open(text_file, 'r') as arq:

            # Generator for the lines in the archive
            gen_lines = (line.split() for line in arq)

            for line_split in gen_lines:

                if line_split[
                        0] == '#':  # comment, presumably containing arguments for __init__
                    dict_args[line_split[1]] = line_split[3]
                elif len(
                        line_split
                ) > 1:  # 2 or more columns. Will ignore anything after the second column
                    col1.append(float(line_split[0]))
                    col2.append(float(line_split[1]))
                elif len(line_split) == 1:  # 1 column
                    col1.append(float(line_split[0]))

            if not dict_args and not col1 and not col2:
                # Check if they're all empty

                raise RuntimeError(
                    f"No arguments, wavelengths and intensities found in {text_file}. Please check if this is a valid file."
                )

            return np.array(col1), np.array(col2), dict_args
# }}}

    @staticmethod
    def find_wavel_index(wavel_array, wavel):
        # {{{
        """
        Attempts to find 'wavel' in 'wavel_array'. Will try using the first wavelength
        at most 0.5 units from 'wavel' if an exact match cannot be found
        """

        try:
            wavel_index = np.where(wavel_array == wavel)
            return wavel_index[0][0]
        except:
            try:
                wavel_index = np.where(np.isclose(wavel_array, wavel,
                                                  atol=0.5))
                print("Exact match for {} not found. Using {} instead".format(
                    wavel, wavel_array[wavel_index[0][0]]))
                return wavel_index[0][0]
            except:
                raise ValueError(str(wavel) + " not found.")

# }}}

    @staticmethod
    def _warn(string):
        # {{{
        """
        Warnings can be disabled by setting the class variable 'opt_warnings' to False
        """

        if Spectrum.opt_warnings:
            print(string)
# }}}

# Magic methods start here

    def __iter__(self):
        return zip(*self.spectrum)

    def __add__(self, other):
        # {{{
        """
        Adds the spectrum's intensities to the 'other' array. If 'other' is also a spectrum,
        their wavelengths arrays must be equal. If you wish to add spectrums with different
        wavelengths arrays, refer to the 'combine' method.

        This operation will always return another spectrum with the added intensities. The new
        spectrum's fields will be inherited from the first operand.
        """

        if isinstance(other, Spectrum):

            if np.array_equal(self._wavel, other._wavel):
                new_inten = self._inten + other._inten
            else:
                raise ValueError(
                    "The added spectrums must have the same wavelengths array."
                )

        elif isinstance(other, (np.ndarray, list)):

            if len(other) == self._wavel.size or len(other) == 1:
                new_inten = self._inten + other

            elif len(other) == self.wavelengths.size:
                new_inten = self._inten
                new_inten[self.get_wavel_slice()] = self.intensities + other

            else:
                raise (ValueError(
                    "The other operand must have the same size as the spectrum's wavelengths array, or size 1."
                ))

        else:
            raise (TypeError("Incompatible types for addition."))

        self_params = vars(self).copy()
        self_params.update({'intensities': new_inten, 'device': None})

        return Spectrum(**self_params)

# }}}

    def __radd__(self, other):
        return self + other

    def __sub__(self, other):
        #{{{
        if isinstance(other, Spectrum):
            if np.array_equal(self._wavel, other._wavel):
                return self + np.negative(other._inten)
            else:
                raise ValueError(
                    "The subtracted spectrums must have the same wavelengths array."
                )
        else:
            return self + np.negative(other)
#}}}

    def __rsub__(self, other):
        raise NotImplementedError

    def __mul__(self, other):
        raise NotImplementedError

    def __div__(self, other):
        raise NotImplementedError

    def __getitem__(self, key):
        #{{{
        """
        Takes the key to be a proper index if it is an integer, and as a wavelength
        if it is float. It also accepts numpy slices and regular slices, of course.
        """

        if isinstance(key, (int, list, np.ndarray)):
            return self.intensities[key]
        elif isinstance(key, float):
            int_index = self.find_wavel_index(self.wavelengths, key)
            return self.intensities[int_index]
        else:
            raise TypeError(
                "Invalid type for index. Please enter an integer, list, numpy array or a float."
            )
#}}}

    def __setitem__(self, key, val):
        #{{{
        """
        Changes the intensity with index 'key' to 'val'. The new value must be a number,
        a tuple, list or numpy array. In the latter 3 cases, numpy will handle the assignment.
        """

        if isinstance(key, (list, tuple, np.ndarray)):
            key = [
                self.find_wavel_index(self.wavelengths, x) if isinstance(
                    x, float) else x for x in key
            ]
        elif isinstance(key, float):
            key = self.find_wavel_index(self.wavelengths, key)
        elif isinstance(key, int):
            if abs(key) > self.wavelengths.size:
                raise IndexError(
                    f"Invalid index of {val} for wavelengths array of size {self.wavelengths.size}"
                )
        else:
            raise TypeError(
                "Invalid type for index. Please enter an integer, list, numpy array or a float."
            )

        if isinstance(val, (tuple, list, np.ndarray)):
            try:
                val = [float(x) for x in val]
            except (TypeError, ValueError) as exception:
                raise ValueError(
                    f"The {type(val)} {val} must contain only numbers.")
        else:
            try:
                val = float(val)
            except:
                raise ValueError(
                    f"Invalid value of {val} for intensity. Please enter something convertible to float."
                )

        self.intensities[key] = val


#}}}

    def __contains__(self, value):
        raise NotImplementedError

    def __repr__(self):
        return "Spectrum({}, {})".format(self.wavelengths, self.intensities)

    def __len__(self):
        return self.wavelengths.size
#!/usr/bin/env python3
# -*- coding: utf-8 -*-
"""
Created on Mon Aug 10 10:27:12 2020

@author: jtm
"""

import pandas as pd
from seabreeze.spectrometers import Spectrometer

from oceanops import dark_measurement

#%% make a df to hold data
# connect to OceanOptics spectrometer
oo = Spectrometer.from_first_available()
data = pd.DataFrame()
it = 10
integration_times = []
while it < oo.integration_time_micros_limits[1]:
    integration_times.append(it)
    it *= 2

#%% set desired temperature before running this cell
t = oo.f.temperature.temperature_get_all()[0]
cycle = 0
while t < 45.00:
    data = data.append(dark_measurement(oo, integration_times))
    data['cycle'] = cycle
    cycle += 1
    t = oo.f.temperature.temperature_get_all()[0]