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_()
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")
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)
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
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
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
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
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
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
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
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)
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()
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
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()
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()
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')
# 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
def test_cant_find_serial(): exc = Spectrometer._backend.SeaBreezeError with pytest.raises(exc): Spectrometer.from_serial_number("i-do-not-exist")
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
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)
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()
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]