python-seabreeze icon indicating copy to clipboard operation
python-seabreeze copied to clipboard

Ocean Optics Multi-Channel Spectrometry Oddities

Open evantaylor opened this issue 3 years ago • 1 comments

spectrometer and system information

  • model: Ocean Optics Jaz
  • operating system: Any
  • python version: 3.9.5
  • python-seabreeze version: 1.3.0
  • installed-via: pip

current problem

Ocean Optics Jaz Spectrometers provide multi-channel support for spectrometry. However, the seabreeze module defaults to a single channel with the normally supplied functions.

Andreas supplied example code for changing the channel using the f.raw_usb_bus.access functionality, but there is a timeout (well it just hangs, actually) issue when querying the devices for the number of modules/channels installed on the Jaz devices.

Good News: If you know your number of installed channels you can work around this and just directly send commands to set the channel.

Bad News: If you send the wrong command the device needs to be reset.

Weird News: If you work around the issue you must reset the channel you are polling from because the Jaz device Serial changes to each submodules.

steps to reproduce

import seabreeze
seabreeze.use('cseabreeze')
from seabreeze.spectrometers import list_devices, Spectrometer
import time
import struct

def init_seabreeze():
    global devices
    devices = []
    for i in list_devices():
        device_name = str(i)[-9:][:-1]
        devices.append(device_name)
    return devices

def get_channels(device):
    spec = Spectrometer.from_serial_number(device)
    spec.f.raw_usb_bus_access.raw_usb_write(data=struct.pack('<B', 0xC0), endpoint='primary_out')
    data = spec.f.raw_usb_bus_access.raw_usb_read(endpoint='primary_in')
    num_channels = struct.unpack('<B', data)
    return num_channels

If you pass either device string from the list devices, the query will hang on spec.f.raw_usb_access.raw_usb_read(endpoint='primary_in')

work-around

To work around this issue, I have some code for selecting the device channel as per Andreas' e-mail, as well as a function to keep the USB device ID consistent by resetting the channel.

def get_spectra(device, channel):
    spec = Spectrometer.from_serial_number(device)
    spec.f.raw_usb_bus_access.raw_usb_write(data=struct.pack('<BB', 0xC1, channel), endpoint='primary_out')
    time.sleep(.5)  # Not necessary?
    wavelengths = spec.wavelengths()
    intensities = spec.intensities()
    reset_channel(spec)
    spec.close()
    data = dict(zip(wavelengths, intensities))
    return data


def reset_channel(spec):
    channel = 0
    spec.f.raw_usb_bus_access.raw_usb_write(data=struct.pack('<BB', 0xC1, channel), endpoint='primary_out')

Apologies if this is not super clear, this is my first issue/bug report/sharing of my own work-around.

evantaylor avatar Jun 16 '21 19:06 evantaylor

Hi @evantaylor

Here's a few things you could try:

  • use 'secondary_in' or 'secondary_in2' as the endpoint argument for the read command
  • use the pyseabreeze backend

if none of the above work, I'll try to provide an example with the pyseabreeze backend that allows us to debug why it's not working

Cheers, Andreas :smiley:

ap-- avatar Jun 17 '21 21:06 ap--