Skip to content

Commit

Permalink
Merge pull request #220 from ap--/sr2-support
Browse files Browse the repository at this point in the history
SR2 support
  • Loading branch information
ap-- authored Nov 1, 2023
2 parents d7072c3 + 7265fb3 commit 2341c94
Show file tree
Hide file tree
Showing 4 changed files with 72 additions and 3 deletions.
1 change: 1 addition & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -90,6 +90,7 @@ To use the pyseabreeze backend (requires `pyusb`) simply run this before importi
| USB650 | | ap--/python-seabreeze#47 |
| SPARK | x | x |
| ADC1000 | | x |
| SR2 | | x |
| SR4 | | x |
| ST-VIS | | x |

Expand Down
9 changes: 6 additions & 3 deletions os_support/10-oceanoptics.rules
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
# udev rules file for Ocean Optics, Inc. spectrometers
# ====================================================
#
# version: 2.4
# version: 2.5
# updated: 2023-04-15
# maintainer: Andreas Poehlmann <[email protected]>
#
Expand All @@ -14,6 +14,7 @@
# $ seabreeze_os_setup
#
# Changes:
# - [2.5] added support for SR2 spectrometer
# - [2.4] added support for SR4 spectrometer
# - added support for HDX spectrometer
# - added support for QE-PRO class of OceanOptics spectrometers
Expand Down Expand Up @@ -85,9 +86,11 @@ ATTR{idVendor}=="0547", ATTR{idProduct}=="2235", SYMLINK+="ezUSB-FX-%n", MODE:="
ATTR{idVendor}=="04b4", ATTR{idProduct}=="8613", SYMLINK+="ezUSB-FX2-%n", MODE:="0666"
# Ocean Insight Inc. HDX spectrometer
ATTR{idVendor}=="2457", ATTR{idProduct}=="2003", SYMLINK+="oceanhdx-%n", MODE:="0666"
# Ocean Insight Inc. SR4 spectrometer
ATTR{idVendor}=="0999", ATTR{idProduct}=="1002", SYMLINK+="sr4-%n", MODE:="0666"
# Ocean Insight Inc. ST spectrometer
ATTR{idVendor}=="0999", ATTR{idProduct}=="1000", SYMLINK+="st-%n", MODE:="0666"
# Ocean Insight Inc. SR4 spectrometer
ATTR{idVendor}=="0999", ATTR{idProduct}=="1001", SYMLINK+="sr2-%n", MODE:="0666"
# Ocean Insight Inc. SR4 spectrometer
ATTR{idVendor}=="0999", ATTR{idProduct}=="1002", SYMLINK+="sr4-%n", MODE:="0666"

LABEL="oceanoptics_rules_end"
24 changes: 24 additions & 0 deletions src/seabreeze/pyseabreeze/devices.py
Original file line number Diff line number Diff line change
Expand Up @@ -1202,6 +1202,30 @@ class ADC1000USB(SeaBreezeDevice):
)


class SR2(SeaBreezeDevice):
model_name = "SR2"

# communication config
transport = (USBTransport,)
usb_vendor_id = 0x0999
usb_product_id = 0x1001
usb_endpoint_map = EndPointMap(ep_out=0x01, highspeed_in=0x81)
usb_protocol = OBP2Protocol

# spectrometer config
dark_pixel_indices = DarkPixelIndices.from_ranges((0, 24))
integration_time_min = 1 # 1 us
integration_time_max = 2000000 # 2 s
integration_time_base = 1
spectrum_num_pixel = 2110
spectrum_raw_length = (2110 * 2) + 32 # Metadata
spectrum_max_value = 65535
trigger_modes = TriggerMode.supported("OBP_NORMAL")

# features
feature_classes = (sbf.spectrometer.SeaBreezeSpectrometerFeatureSR2,)


class SR4(SeaBreezeDevice):
model_name = "SR4"

Expand Down
41 changes: 41 additions & 0 deletions src/seabreeze/pyseabreeze/features/spectrometer.py
Original file line number Diff line number Diff line change
Expand Up @@ -604,6 +604,47 @@ def get_intensities(self) -> NDArray[np.float_]:
return ret * self._normalization_value


class SeaBreezeSpectrometerFeatureSR2(SeaBreezeSpectrometerFeatureOBP):
def _get_spectrum_raw(self) -> NDArray[np.uint8]:
timeout = int(
self._integration_time_max * 1e-3
+ self.protocol.transport.default_timeout_ms
)
datastring = self.protocol.query(0x000_01C_00, timeout_ms=timeout)
return numpy.frombuffer(datastring, dtype=numpy.uint8)

def get_intensities(self) -> NDArray[np.float_]:
tmp = self._get_spectrum_raw()
# 32byte metadata block at beginning
ret = tmp[32:].view(numpy.dtype("<H")).astype(numpy.double)
return ret * self._normalization_value

def set_trigger_mode(self, mode: int) -> None:
if mode in self._trigger_modes:
self.protocol.send(0x000_00D_01, mode, request_ack=True)
else:
raise SeaBreezeError("Only supports: %s" % str(self._trigger_modes))

def set_integration_time_micros(self, integration_time_micros: int) -> None:
t_min = self._integration_time_min
t_max = self._integration_time_max
if t_min <= integration_time_micros < t_max:
i_time = int(integration_time_micros / self._integration_time_base)
self.protocol.send(0x000_00C_01, i_time)
else:
raise SeaBreezeError(f"Integration not in [{t_min:d}, {t_max:d}]")

def get_wavelengths(self) -> NDArray[np.float_]:
data = self.protocol.query(0x000_011_00)
num_coeffs = len(data) // 4
assert len(data) % 4 == 0 # ???
assert num_coeffs > 1 # ???
coeffs = struct.unpack("<" + "f" * num_coeffs, data)[1:]
# and generate the wavelength array
indices = numpy.arange(self._spectrum_length, dtype=numpy.float64)
return sum(wl * (indices**i) for i, wl in enumerate(coeffs)) # type: ignore


class SeaBreezeSpectrometerFeatureSR4(SeaBreezeSpectrometerFeatureOBP):
def _get_spectrum_raw(self) -> NDArray[np.uint8]:
timeout = int(
Expand Down

0 comments on commit 2341c94

Please sign in to comment.