Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

High-speed acquisition mode using the Ocean Binary Protocol on OceanFX #59

Closed
aarpon opened this issue Jul 10, 2018 · 48 comments
Closed

Comments

@aarpon
Copy link

aarpon commented Jul 10, 2018

spectrometer and system information

  • model: OceanFX (FlameX)
  • operating system: Windows 7 64bit
  • python version: Python 3.6.6 :: Anaconda custom (64-bit)
  • python-seabreeze version: 0.6.0
  • installed-via: conda

current problem

Using the Ocean Binary Protocol (OBP) it should be possible to achieve a rate of 4500 spectra/s over USB. This requires the following sequence of operations (pseudocode from the OBP documentation for the OceanFX spectrometer):

Set trigger mode = 0 // software trigger (HW triggering can also be used)
Set buffering = enabled
Set number of back-to-back spectra per trigger = 50000
Set integration time = 10 // microseconds
Clear the buffer // optional
SpectrumData[] = new Spectrum[15] // Allocate a buffer to hold the spectra response data
RequestRawSpectrumWithMetadata(15) // Request up to 15 spectra
START_LOOP
    RequestRawSpectrumWithMetadata(15) // Request the next 15 spectra
    SpectrumData = ReadRawSpectrumWithMetadata(15) // Read (up to) the next 15 spectra
    // *** Do stuff with the returned spectra here ***
    // *** Note: any number of spectra from 0 – 15 may be returned ***
END_LOOP
SpectrumData = ReadRawSpectrumWithMetadata(15) // Read (up to) the last 15 spectra
// *** Do stuff with the returned spectra here ***
// *** Note: any number of spectra from 0 – 15 may be returned ***

Is there an API that already provides this buffered reading of spectra? If not, could you provide me with some hints on how to implement it? In particular, I would like to know if it is possible to perform the Set buffering = enabled and Set number of back-to-back spectra per trigger = 50000 using python-seabreeze with any of the backends, and how.

@ap--
Copy link
Owner

ap-- commented Jul 19, 2018

Hi @aarpon

I recommend you look for a datasheet of the OceanFX that has the full command set available.
(I couldn't find one just now)
An implementation of the OBP protocol is here https://github.com/ap--/python-seabreeze/blob/master/seabreeze/pyseabreeze/interfaces/communication.py#L100-L340
if you want to extend pyseabreeze you would just interface with the spectrometer via the .send_command and .query methods

Best,
Andreas

@aarpon
Copy link
Author

aarpon commented Aug 6, 2018

Hi,

great, thank you for the pointer! I will have a look.

a2

@tobiasium
Copy link

Hi aarpon,
did you manage to have a look at this or get it to work? I also have two FX spectrometers that I would like to read out fast... Currently I get around 390 FPS with seabreeze, which is the same as a normal Flame spectrometer.

@aarpon
Copy link
Author

aarpon commented Sep 25, 2018

Hi,

nope, not yet. But I plan to work on it soon (hopefully from next week).

Thanks,
a2

@aarpon
Copy link
Author

aarpon commented Oct 12, 2018

Hi,

the python backend of python-seabreeze does not recognize the OceanFX spectrometer (0x2001). I have been (quickly) looking at the interfaces\defines.py file. Any pointers on how and where I can collect all the relevant information (dark pixels, end points, trigger modes)? Also, is there some documentation on how I can add a complete new spectrometer to pyseabreeze?

Thanks,
a2

@ap--
Copy link
Owner

ap-- commented Sep 11, 2019

There is one small thing missing that I didn't wrap in the cseabreeze backend for version 1.0.0 😞 because it's only exposed via unformatted spectra...

def get_fast_buffer_spectrum(self):
# TODO: requires wrapping of OBP command GetRawSpectrumWithMetadata
# which returns N raw spectra each with a 64 byte metadata prefix
# int spectrometerGetFastBufferSpectrum(long deviceID, long spectrometerFeatureID, int *errorCode,
# unsigned char *dataBuffer, int dataMaxLength,
# unsigned int numberOfSampleToRetrieve) # currently 15 max
raise NotImplementedError("Not yet supported via cseabreeze. Requires changes to libseabreeze.")

There's two ways to do this:

  • implement the cython interface for the function above, then you can access it via:

    spec = Spectrometer.from_first_available()
    spec.f.spectrometer.get_fast_buffer_spectrum()

    (the other fast_buffer feature functions are already wrapped)

  • implement the functionality in pyseabreeze, which requires:

    • add support for the FlameX to pyseabreeze
    • implement the FastBufferFeature
    • implement the get_fast_buffer_spectrum() method in the SpectrometerFeature

With v1.0.0 I rewrote the whole pyseabreeze backend with v1.0.0 so that it's easier to extend:

https://python-seabreeze.readthedocs.io/en/latest/contributing.html
Shows how to add a spectrometer.
And the code should (hopefully 😅 ) be well documented 🎉

@Roy4777
Copy link

Roy4777 commented Jun 25, 2020

@aarpon I am using an Ocean FX-XR1. I am trying to add a new spectrometer using the documentation here

Can you please provide me a copy of inputs for the following variables for Ocean FX?

# communication config
transport = (USBTransport, )
usb_product_id = 0x4200
usb_endpoint_map = EndPointMap(ep_out=0x01, lowspeed_in=0x81)  # XXX: we'll ignore the alternative EPs
usb_protocol = OBPProtocol

# spectrometer config
dark_pixel_indices = DarkPixelIndices.from_ranges()
integration_time_min = 10
integration_time_max = 85000000
integration_time_base = 1
spectrum_num_pixel = 1024
spectrum_raw_length = (1024 * 2) + 64  # XXX: Metadata
spectrum_max_value = 16383
trigger_modes = TriggerMode.supported('OBP_NORMAL', 'OBP_EXTERNAL', 'OBP_INTERNAL')

@aarpon
Copy link
Author

aarpon commented Jun 25, 2020

@ap-- Unfortunately, I won't have access to the Ocean FX for the next few weeks...

@Roy4777
Copy link

Roy4777 commented Jul 20, 2020

@aarpon Did you manage to implement the High-Speed Acquisition mode for Ocean FX on python-seabreeze? If yes, can you please share how you achieved it?

@aarpon
Copy link
Author

aarpon commented Aug 3, 2020

@Roy4777 We ended up going down a completely different path (i.e. not using python-seabreeze). We should publish a paper about it soon, after which we will upload the code to either github or our gitlab instance.

@Roy4777
Copy link

Roy4777 commented Aug 3, 2020

@aarpon That's awesome! I'll be looking forward to it.

@ptapping
Copy link

I have just got hold of an Ocean FX VIS-NIR for a pre-purchase test, which I will have access to for a couple of weeks. We want to use it to capture at high speed, and integrate it into a python code base.

Just to clarify the current state of seabreeze at this time, it looks like seabreeze works with the FX, but it appears as a FlameX and doesn't support the short integration time and "throughput" or buffered mode of the FX required to reach the advertised 4500 spectra per second.

Initially I thought a basic ctypes interface into the omnidriver.so/omnidriver.dll would be quick and easy, but no, it doesn't work. So I'm looking at other options. Writing my own wrapper around the Java or C++ omnidriver libraries would work, but be horribly tedious and bloated. Ultimately, I think it would be nice if I could hack at an open source library like seabreeze instead...

Anyway, I have ssh access to the machine with the FX connected by USB, and will look at what it will take to implement the buffered acquisition mode. Any suggestions are welcome, and/or if you'd like me to test or report any data from the FX, let me know.

Also, @aarpon if you have published that paper or have other hints about how you achieved fast acquisition from the FX, I'd love to hear it!

@ap--
Copy link
Owner

ap-- commented Oct 13, 2020

Hi @ptapping

Thanks for offering to contribute! ❤️ Implementing the fast buffer spectrum feature shouldn't take very long, as you have the hardware to test it. I don't have a developer data sheet for the OceanFX but since it uses the OceanBinaryProtocol for communication it should also be fairly standardized in its behavior. Still, if you find one it would be incredibly helpful.

As described in an older comment of mine above https://github.com/ap--/python-seabreeze/issues/59#issuecomment-530549301 you do have two options to get started:
1.) you can wrap the missing C++ functionality for the FlameX and expose the fast buffer spectrum functionality via the cseabreeze backend
2.) you could add the OceanFX to the pyseabreeze library and implement the feature there.

Ultimately it just depends in which codebase you feel more at home. (1) is probably faster to do if you're familiar with c++ and cython and you just need it to work. (2) will probably be easier to iterate and hack on.

I would probably recommend (2) and implementing it in the pyseabreeze backend. It's biggest problem is though, that it's quite a bit unpythonic, because I tried back then (bad decision) to make it mirror the abstraction layers of the c++ seabreeze library and over the years it became quite a bit ugly due to backwards-compatibility and hotfixes. But if I'll ever release python-seabreeze-v2 I would probably drop the cseabreeze backend and refactor pyseabreeze with only python3.6+ in mind...

So let me know if I can do anything to get you started, and feel free to ask questions if you get stuck. If you open a draft PR, I can help you with code review and point you in the right directions.

Cheers,
Andreas 😃

@ptapping
Copy link

Thanks for the encouragement! I managed to have a bit of a look at this today.

So it turns out the Ocean FX detects as a FlameX using the cseabreeze API, and it reports that it supports the fastbuffer, databuffer etc features. So this is possible:

import seabreeze
seabreeze.use('cseabreeze')
from seabreeze.spectrometers import Spectrometer
spec = Spectrometer.from_first_available()
spec.f.fast_buffer.set_buffering_enable(True)
spec.f.fast_buffer.set_consecutive_sample_count(100)
# The FlameX only supports 1000 us, the FX should support 10 us
spec.integration_time_micros(1000)

wavelengths = spec.wavelengths()
intensities = spec.intensities()

print(spec.f.databuffer.get_number_of_elements())

# Remember to do this...
spec.close()

The databuffer reports the correct number of spectra acquired, but of course the call to intensities() only returns a single spectra. I have a feeling if I just implement the get_fast_buffer_spectrum() method on line 842 of c_seabreeze_wrapper.pyx then that should do it. The comment says it interfaces to the spectrometerGetFastBufferSpectrum call (in the FX OBP documentation).

So I'll start there and see how we go. If it works, then it should just need a new OceanFX device definition, which should be mostly a copy-paste from the FlameX one.

Ultimately though, yes, I think it would be nice to implement the pyseabreeze backend.

@aarpon
Copy link
Author

aarpon commented Oct 27, 2020

Hi, guys. As I said in a previous comment, we "solved" the issue in a different way. We contacted Ocean Optics and were sent a DLL (written in C# by Oliver Lischtschenko) that allows us to unlock the complete set of functionalities in OceanFX. For us, this solution was fair enough, since we are implementing a whole analysis platform, and were fine relying on having the bidirectional communication between the photometer and the CPU set up by someone else. As for our discussions with OO, the DLL can be freely used but must be distributed in binary form. We are somehow being delayed with our publications, but the idea is to get the whole code on github soon(ish).

@ptapping
Copy link

Thanks for the update!
I have access to the OmniDriver, but it's not pretty. I didn't get a ctypes interface into the .dll or .so working at all, and the C libraries just wrap the underlying Java library so would be a bloated mess of wrapped wrappers, hence looking at this library instead. It sounds like they gave you something different and not publicly released though.

I haven't worked on this in a week or so, but made some progress. I started implementing the FX support into pyseabreeze, but got stuck pretty quickly on what looks like a low-level communications issue. I can open the spectrometer (which reads the serial number), but after that communications will time out and the spectrometer will stop responding. I did find that doing a low-level read would seem to clear buffers or something and the spectrometer would respond again. My guess is that a read and/or write in the OBP or transport layer is sending/receiving the wrong size data chunks or unexpected data.

I found this issue #109 but not sure it's related.

It might also be to do with the acknowledgement request flag. For example:

import seabreeze.pyseabreeze as psb
api = psb.SeaBreezeAPI()
api.supported_models()          # FX is listed
api.list_devices()              # FX is detected
dev = api.list_devices()[0]     # USB read timeout
dev = api.list_devices()[0]     # Works this time...?
dev.serial_number               # Got serial number OK
# But now everything will timeout again
# If we just read raw bytes, it will come back to life
_ = dev._transport._device.pyusb_device.read(0x01, 2**16)

# Sending raw commands like this seems to work every time
dev._transport.protocol.send(0x00000100, request_ack=False) # Request serial number
dev._transport.protocol.receive()

# But times out if the acknowledgement reply is requested?
dev._transport.protocol.send(0x00000100, request_ack=True)
dev._transport.protocol.receive()

Anyway, have been busy with other tasks, so need to look into this more, but thought I'd report my progress. Any suggestions or ideas welcome of course.

I've also attached the output of lsusb -v just in case it's of some use to anyone.
OceanFX-lsusb.txt

@ap--
Copy link
Owner

ap-- commented Oct 28, 2020

Hi @aarpon and @ptapping

We contacted Ocean Optics and were sent a DLL (written in C# by Oliver Lischtschenko) that allows us to unlock the complete set of functionalities in OceanFX. For us, this solution was fair enough, since we are implementing a whole analysis platform, and were fine relying on having the bidirectional communication between the photometer and the CPU set up by someone else.

I'd be happy to accept PRs for vendoring and integrating the DLL together with a python wrapper as another backend in python-seabreeze. It's too bad that it's win only.

It might also be to do with the acknowledgement request flag. For example:

The request_ack flag is used within the send command to make the spectrometer acknowledge it received the command. If the command does not produce a new reply by the spectrometer there won't be any data to receive afterwards.

It's best to use send to send commands to the spectrometer that don't cause a reply, and query to send commands that return data from the spectrometer. (query, is send with request_ack=False and receive afterwards.)

The command acknowledging mechanism doesn't really make sense for USB connected spectrometers. The OPBProtocol is also used on spectrometers that support RS232...

Let me know if that helps clearing things up,
-Andreas 😃

@sharmila-velamur
Copy link

sharmila-velamur commented Jan 9, 2021

Hi, guys. As I said in a previous comment, we "solved" the issue in a different way. We contacted Ocean Optics and were sent a DLL (written in C# by Oliver Lischtschenko) that allows us to unlock the complete set of functionalities in OceanFX. For us, this solution was fair enough, since we are implementing a whole analysis platform, and were fine relying on having the bidirectional communication between the photometer and the CPU set up by someone else. As for our discussions with OO, the DLL can be freely used but must be distributed in binary form. We are somehow being delayed with our publications, but the idea is to get the whole code on github soon(ish).

@aarpon
I am new to working with spectrometers and seabreeze, but for my purpose, I too need sustained burst mode (4500 Hz) data acquisition. I have been trying some solutions and then came across this discussion. Have you published your code/paper yet? Would really appreciate any information on how you achieved sustained high speed data acquisition. BTW, I am working with an OceanFX spectrometer. Since it is a DLL maybe it is meant only for Windows env, is there anything similar that might work for RPi?

Thank you.

@aarpon
Copy link
Author

aarpon commented Jan 9, 2021

@sharmila-velamur I have to check with the original code by Oliver Lischtschenko: I think it could reach the maximum theoretical throughput; our solution saturates at around 2200 Hz, but in practice, for our purposes, we probably work at 800 Hz: to even get some signal from our fluorophores, we have to illuminate longer and therefore slow everything down. I am afraid for our code to be accessible online it will take some more time, but I can investigate whether we can share the original code from OO. As I mentioned in the past, it's C# and runs on Windows. I guess you could give mono a shot if you need to use it on other platforms and you (mostly) lose the UI. This code just gets spectra and plots them (a few times a second), but should have all the elements in place to get you started.

@sharmila-velamur
Copy link

@sharmila-velamur I have to check with the original code by Oliver Lischtschenko: I think it could reach the maximum theoretical throughput; our solution saturates at around 2200 Hz, but in practice, for our purposes, we probably work at 800 Hz: to even get some signal from our fluorophores, we have to illuminate longer and therefore slow everything down. I am afraid for our code to be accessible online it will take some more time, but I can investigate whether we can share the original code from OO. As I mentioned in the past, it's C# and runs on Windows. I guess you could give mono a shot if you need to use it on other platforms and you (mostly) lose the UI. This code just gets spectra and plots them (a few times a second), but should have all the elements in place to get you started.

Thank you so much for replying to me @aarpon. I do not need the UI at all. If I can get ~2000 Hz that would be pretty awesome (I am at 160 Hz now) to start with. What is mono? I have not come across that in the OceanFX documentation to the best of my recall.

@aarpon
Copy link
Author

aarpon commented Jan 11, 2021

@sharmila-velamur. The code we got from Oliver Lischtschenko cannot be found anywhere officially, also I could never really find the documentation needed to replicate what it does. The problem is that Oliver's demo is heavily bound to a UI (it's just one big C# file). So, you'd need to extricate what you need from all the UI callbacks. Our tool is also a heavily graphical thing, and massively larger. Would you be able to work from a C# solution?
Finally, mono is an opensource implementation of .NET that runs cross-platform (and has some support for Windows Forms).

@ap--
Copy link
Owner

ap-- commented Jan 11, 2021

Hi @sharmila-velamur and @aarpon

Hope you all had a good start into 2021.
I can help with implementing the high-speed mode in python-seabreeze, but I lack the hardware to test it.

It would be incredibly helpful, if one of you could get a USB Packet dump using https://desowin.org/usbpcap/ of OceanView (or alternatively in aapron's case: Oliver's tool) requesting a spectrum in high speed mode.
With that we should have everything needed to implement full support in python-seabreeze. (note: the packet dump will contain your spectrometer's serial number in case you share it publicly)
(if we don't have it, it might require a bit more guesswork, and we might hit a roadblock)

I think I can reserve time this weekend to help test the code on your hardware and we could debug it together 😃

Let me know what you think or if I can be of further help in the meantime,
Cheers,
Andreas 😃

@aarpon
Copy link
Author

aarpon commented Jan 11, 2021

Hi, @ap--. Happy new year to you, too! I should be able to get my hands on the hardware this week (can't tell you when, yet, though). And I can give it a shot.

@sharmila-velamur
Copy link

Hi @sharmila-velamur and @aarpon

Hope you all had a good start into 2021.
I can help with implementing the high-speed mode in python-seabreeze, but I lack the hardware to test it.

It would be incredibly helpful, if one of you could get a USB Packet dump using https://desowin.org/usbpcap/ of OceanView (or alternatively in aapron's case: Oliver's tool) requesting a spectrum in high speed mode.
With that we should have everything needed to implement full support in python-seabreeze. (note: the packet dump will contain your spectrometer's serial number in case you share it publicly)
(if we don't have it, it might require a bit more guesswork, and we might hit a roadblock)

I think I can reserve time this weekend to help test the code on your hardware and we could debug it together 😃

Let me know what you think or if I can be of further help in the meantime,
Cheers,
Andreas 😃

Hi @ap--
Ocean Optics provided me an SDK called Ocean Direct. I've been working with it (using ctypes wrapper), but still have some issues. Setting 10 ms integration time throws Data Transfer Error and the API's get_raw_spectrum_with_meta_data which is supposed to return 15 rows at a time, maxes out at 50,000 (the max buffer capacity). I have access to the hardware and I will try capturing the USB packets, but it could take a few days into next week. It would be so awesome if sustained high speed data acquisition is integrated into the seabreeze library. Looking forward to working with you on that. Thank you.

@aarpon
Copy link
Author

aarpon commented Jan 24, 2021

Cool! I should be able to get on the machine next week. I'll try to get a packet dump, too.

@ap--
Copy link
Owner

ap-- commented Jan 24, 2021

Ocean Optics provided me an SDK called Ocean Direct

Interesting! I assume this is closed source?

@sharmila-velamur wrote: have access to the hardware and I will try capturing the USB packets, but it could take a few days into next week.
@aarpon wrote: Cool! I should be able to get on the machine next week. I'll try to get a packet dump, too.

Awesome. I have to see when I can free up a day to work on this. Though, it is unlikely that I will find time in the next two weeks. So no rush.

Have a great day 😃
-Andreas

@sharmila-velamur
Copy link

Ocean Optics provided me an SDK called Ocean Direct

Interesting! I assume this is closed source?

@sharmila-velamur wrote: have access to the hardware and I will try capturing the USB packets, but it could take a few days into next week.
@aarpon wrote: Cool! I should be able to get on the machine next week. I'll try to get a packet dump, too.

Awesome. I have to see when I can free up a day to work on this. Though, it is unlikely that I will find time in the next two weeks. So no rush.

Have a great day 😃
-Andreas

I am not sure. I will find out tomorrow and let you know if this is a source I can share or not.

Have a great one :)

@ptapping
Copy link

Hi all,

I had been meaning to post here again with my progress, and the recent activity has reminded me about this...

In the end, we did not end up purchasing the FX after our trial, so I didn't pursue this much further. We ended up choosing a more expensive option, but one which should hopefully also get us more spectra per second. Yes, Ocean Insight lost a customer because of their poor software and API.

I still think the way to go is implementing the pure python OBP methods for the buffer management and retrieval of spectra. Add the FX in pyseabreeze/devices.py with a class something like this:

class FX(SeaBreezeDevice):

    model_name = "FX"

    # communication config
    transport = (USBTransport,)
    usb_product_id = 0x2001
    usb_endpoint_map = EndPointMap(
        ep_out=0x01, lowspeed_in=0x81, highspeed_in=0x00, highspeed_in2=0x00
    )
    usb_protocol = OBPProtocol

    # spectrometer config
    dark_pixel_indices = DarkPixelIndices.from_ranges()
    integration_time_min = 10
    integration_time_max = 10000000
    integration_time_base = 1
    spectrum_num_pixel = 2068
    spectrum_raw_length = (2068 * 2) + 64  # XXX: Metadata
    spectrum_max_value = 65535
    trigger_modes = TriggerMode.supported(
        "OBP_NORMAL", "OBP_EDGE", "OBP_LEVEL", "DISABLED"
    )

    # features
    feature_classes = (
        sbf.spectrometer.SeaBreezeSpectrometerFeatureFX,
        sbf.rawusb.SeaBreezeRawUSBBusAccessFeature,
        sbf.nonlinearity.NonlinearityCoefficientsFeatureOBP,
    )

and to pyseabrease/features/spectrometer.py with something like:

class SeaBreezeSpectrometerFeatureFX(SeaBreezeSpectrometerFeatureOBP):
    def _get_spectrum_raw(self):
        timeout = int(
            self._integration_time_max * 1e-3
            + self.protocol.transport.default_timeout_ms
        )
        # the message type is different than the default defined in the protocol,
        # requires addition of a new message type in protocol to work
        datastring = self.protocol.query(0x00101000, timeout_ms=timeout)
        return numpy.fromstring(datastring, dtype=numpy.uint8)

(these are based off the HDX which is similar, but I'm not certain the spectrum_num_pixels is correct).

However, the initialisation will still not work because of the issue I described above --- I think the initialisation and/or initial query of device serial number fails because the spectrometer does not return the expected number of bytes. I didn't follow this further to see exactly why, but setting the request_ack to false in the OBPProtocol.send() method seemed to help I think?
Anyway, once (sort of) initialised, I could empty the read buffers with something like _ = dev._transport._device.pyusb_device.read(0x81, 2**16), and then send and receive raw OBP commands with dev._transport.protocol.send(...) and dev._transport.protocol.receive() messages.
So, assuming the above issue is fixed and the FX follows the rest of the OBP specification (here), it should just be the spectrometer buffer commands, particularly the GetRawSpectrumWithMetadata() method that needs to be implemented.

Good luck!

@ghost
Copy link

ghost commented Aug 2, 2021

@ap-- I have an Ocean FX XR1 in my lab. Are you still interested in developing the high frame rate support? If so, I could get you the packet dump/other info you need. We are very interested in my group to get this working with SeaBreeze.

@ap--
Copy link
Owner

ap-- commented Aug 3, 2021

Hi @npeard

Time is a bit scarce on my side, but I'd be very happy to offer assistance in implementing high-speed acquisition mode.
Having the USB packet dump would be a great resource for whoever implements it :)

I can sketch out the required functionality and maybe a savvy programmer from your group with more time can fill in the usb communication details?

Cheers,
Andreas

@vchikan
Copy link

vchikan commented Aug 5, 2021

A LabVIEW Solution: I had the same as problem as above obtaining high speed data from Ocean FX spectrometer using omnidriver. I decided to implement the known OBP protocol in Labview for controlling and reading data from the Ocean FX spectrometer directly via the USB port. I had written a small driver to replace the WinUSB driver with mine to read and write the USB port Labview Visa. Step 1. Replace the WinUSB driver with the OceanFX driver. Step 2 run the simple spectrometer VI to see if there is communication. The save high speed data into binary allows triggered high-speed acquisition from Ocean FX spectrometer. The analysis file provided will convert and graph the saved binary data. I was able to get around 4kHz data rate with Labview. Enjoy!
oceanFX.zip

@ghost
Copy link

ghost commented Aug 17, 2021

@ap-- I used USBPcap to acquire the attached data with the Ocean FX XR1 running in 10us integration time (the minimum possible value, OceanView software acquires the spectra with net ~3800 fps). This is new for me, so I hope I did it correctly/got the necessary data. Any advice on how to proceed?
fast10usInt_OceanFXR_1.pcap.zip

@aarpon
Copy link
Author

aarpon commented Sep 16, 2021

Good morning @ap--, @tobiasium, @sharmila-velamur and @vchikan, and sorry for the long silence on this thread.

As I mentioned earlier, we went down another path to exploit our OceanFX spectrometer for high-content screening. Since the first paper is now accepted and in print, I can finally share the code with you: https://github.com/SpectraSorter/SpectraSorter.

Again, while our code (in C#) is free and opensource, we make use of a closed-source DLL by Oliver Lischtschenko from OO (https://github.com/SpectraSorter/SpectraSorter/blob/master/src/SpectraSorter/OBP_Library.dll) that implements the Ocean Binary Protocol and allows us to reach full performance at 4,500 spectra collected per second.

I don't know if you can take advantage in any way from either the source code, the OBP library or, hopefully!, SpectraSorter itself, but we would definitely be interested in knowing if it can work out of the box with your hardware (we could only test it with our OceanFX).

You can find the user manual at https://github.com/SpectraSorter/SpectraSorter/blob/master/docs/SpectraSorter_User_Manual.docx and a short video demonstration at https://vimeo.com/601011694.

Any feedback is greatly welcome!

Thanks in advance,
a2

@ap--
Copy link
Owner

ap-- commented Sep 20, 2021

Hi @aarpon,
very nice. Good to see that you could opensource your code ❤️. If you like I can add a reference to the python-seabreeze docs. 😃

@npeard
Sorry for the delay. If you use wireshark you can have a look at the packet capture file.

Screenshot from 2021-09-20 21-58-29

You can then check the transferred data. For the command in the screenshot it boils down to:

# GetRawSpectrumWithMetadata --> 0x00100908

c1 c0                                            # header
00 00                                            # protocol_version
00 00                                            # flags
00 00                                            # error_number
80 09 10 00                                      # message_type
00 00 00 00                                      # regarding
00 00 00 00 00 00                                # reservered
00                                               # checksum type
04                                               # immediate length
01 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00  # immediate data
14 00 00 00                                      # bytes remaining
00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00  # checksum
c5 c4 c3 c2                                      # footer

Which you can check against the datasheet for the OceanFX that's linked to in a response further up.

Screenshot from 2021-09-20 22-28-05

Ultimately you just need to send the commands in the correct order. The package dump can help you with that. (If you check yours, it turns out you're missing the setup commands, and it just captured very many of the GetRawSpectrumWithMetadata commands)

Cheers,
Andreas 😃

@aarpon
Copy link
Author

aarpon commented Sep 22, 2021

Hi, @ap--

Thanks, it would be great if you could add a reference to SpectraSorter to the python-seabreeze docs!
a2

@italavica
Copy link

italavica commented May 4, 2022

Hi @aarpon

Thanks a lot for the contribution of Spectra Sorter, I am trying to use the software to apply one of the triggering functions of OCEAN FX, but unfortunately I don't have the "Arduino MEGA 2560", I am using "Arduino MEGA ADK". Do you know if it is possible to modify the source code to adapt the software for the Arduino that I have?, if yes could you give some insight where I should change the code for my specific arduino?.

Cheers,
italavica

@aarpon
Copy link
Author

aarpon commented May 4, 2022

Hi, @italavica. The communication with the Arduino board is managed by the spectra.devices.Arduino class (https://github.com/SpectraSorter/SpectraSorter/blob/master/src/SpectraSorter/devices/Arduino.cs). The MEGA 2560 is connected over a COM port (via an USB-to-serial converter, as in the MEGA ADK, as far as I can tell). As long as the Arduino is recognized by the OS once plugged in, you should be able to use it with no change in the code.

@italavica
Copy link

Hi @aarpon,
Thanks for the the feedback, yes indeed I did not have to change anything to the code, I just compiled the "SpectraSorter_Trigger.ino" file in my current arduino and now it is working.

@aarpon
Copy link
Author

aarpon commented May 4, 2022

Hi, @italavica. Sorry, yep. Forgot to mention that ;-)

@italavica
Copy link

Hi, @aarpon. As I mentioned, I managed to connect the arduino "MEGA ADK" and set the parameters through the software (Spectra Sorter), but once I start the acquisition using the triggering mode "Legacy Synchronous" it doesn't display and save the spectrum in the csv file. What do you think it can be the issue?

Thanks in advance.

Cheers,
italavica

image
image
image

@aarpon
Copy link
Author

aarpon commented May 6, 2022

Hi, @italavica. I am afraid that this trigger mode is not implemented.

@italavica
Copy link

Hi, @aarpon, I am just wandering if you already implemented the "Legacy Synchronous" triggering mode?, if not could you advice me where to start for implement it?

@padalev
Copy link
Contributor

padalev commented Feb 6, 2024

Hi everyone.

I'm in the process of implementing the fast buffer method for the cseabreeze backend at least and I could use some input.

As mentioned before the spectra come as raw spectra and have a 64 byte header each. So this is the code I came up with:
https://github.com/padalev/python-seabreeze/blob/7897407fbbb0538b1828c46e321123282d2c9778/src/seabreeze/cseabreeze/c_seabreeze_wrapper.pyx#L889C5-L928C22

I get back spectrums that are the "same" as when read directly with spec.intensities(). I also get a raw bytestream for the header which for now is relatively useless.

A few thoughts:

  • Does anyone have an idea what the content of the header is exactly and how it's structured? I can identify some bytes that seem to be a timestamp incrementing in units of microseconds. But I don't know exactly what kind of timestamp it is. There also seem to be some bytes used as a buffer id in some way as it increments with measurements. I think it would be really useful to hand those things back in a structured way. Right now I'm handing the data back as a list of python dicts with the header and the spectrum. But maybe it would be better to split that into a different function so that the original fastBuffer function better reflects the original ocean c++. I don't know. Any ideas?
  • As was already mentioned in the comment of the dummy function there is a limit of max 15 spectra that can be read from the buffer at a time. If I try to do more I get a hangup. The function should probably throw an error if anything higher is handed over instead of just correcting it as I did here. Also: What's the origin of that limit? Is that something that could be worked on?
  • Not directly related: I can't set the integration time of the spectrometer to anything below 1000 micros even though it should be able to go down to 10. There's probably some need for modifications in the c++ backend in that case, right?

I have full access to an OceanFX-XR1 spectrometer, so I'll probably be able to put some more effort into this. I might even start implementing it in the pyseabreeze backend but wanted to get something to work quickly so I went this route.

@padalev
Copy link
Contributor

padalev commented Feb 6, 2024

Here's a dump of the bytes received for 3 spectra in case anyone wants to have a look. I have shone my iPhones LED into the detector to make the spectra distinguishable.

OceanFXdata.txt

@ap--
Copy link
Owner

ap-- commented Feb 6, 2024

@padalev great to see that there's some new momentum regarding the OceanFX support.

(1) The metadata structure should be as follows:

oceanfx_Metadata1
oceanfx_metadata2

(2) some more information regarding the fast spectrum functionality

The OceanFX supports up to 15 spectra per response message.

BUFFERING DISABLED:
If buffering is disabled, this command blocks and returns exactly the number of spectra requested.
If scans to average is greater than 1 AND buffering is disabled, this command preserves it's blocking
nature retrieving the required number of raw spectrum in order to return the requested number of
averaged spectrum. For example, if scans to average is set to 10 and 5 spectra are requested per
message, then each message will result in 50 raw spectra being acquired and averaged in groups of
10 to return 5 averaged spectra.
BUFFERING ENABLED:
If buffering is enabled, this command returns up to the number of spectra requested (it may return
zero spectra or any other number of spectra less than requested). When buffering is enabled, this
command is effectively non-blocking... it returns the number of spectra in the buffer at the time the
request is received (up to the number of spectra requested).
If scans to average is greater than 1 this command preserves its non-blocking nature. If scans to
average is set to 10, for example, then there must be at least 10 raw spectra in the buffer in order for
1 averaged spectra to be returned. If there are 20 raw spectra in the buffer, then 2 averaged spectra
can be returned, etc.

(3) here's the link to the limit:

const long FlameXSpectrometerFeature::INTEGRATION_TIME_MINIMUM = 1000;

@ap--
Copy link
Owner

ap-- commented Feb 6, 2024

Right now I'm handing the data back as a list of python dicts with the header and the spectrum. But maybe it would be better to split that into a different function so that the original fastBuffer function better reflects the original ocean c++. I don't know. Any ideas?

Trying to stay compatible with the original c++ library was in hindsight a big mistake. Ocean Insight does not seem to support the open-sourced seabreeze library anymore, and there have been no updates from them for years. At the time I wrote this python library, I designed pyseabreeze to be as close as possible to the c++ interface so that I would be able to easily port new functionality to the pure python implementation when it would have been added by ocean optics.

This just made pyseabreeze a lot more complex compared to when I would have written it as a Python first library.

the cseabreeze backend will at some point in the future become an optional module that can be installed as an extra, and pyseabreeze should become the default backend. If you just look at basic functionality, pyseabreeze already supports more spectrometers than the cseabreeze one.

So to summarize, that's been a long explanation to just say: don't worry about the compatibility between them. structuring the metadata as a dict or namedtuple makes a lot of sense.

@padalev
Copy link
Contributor

padalev commented Feb 7, 2024

(1) The metadata structure should be as follows:

wow. That's exactly what I was looking for. I have already started implementing that to return a list of namedtuples.

(2) some more information regarding the fast spectrum functionality

that is very helpful! I wasn't quite aware of the exact mechanism.

(3) here's the link to the limit:

I see. Why is the file called FlameX...? Is that an internal ocean insight name for the model? Or is that a group of spectrometers? I'm afraid I will affect other spectrometers by just changing that value...
What kind of checkboxes should be fulfilled so that the OceanFX could be considered to be supported? I mean, just reading a spectrum works fine already...

Ocean Insight does not seem to support the open-sourced seabreeze library anymore, and there have been no updates from them for years.

I already had a feeling. Sad to see companies dropping the open source approach. Seems like we are doing their job now...

, and pyseabreeze should become the default backend.

all the more reasons to implement the fast Buffer functionality to that backend as well I guess.

I have working code now but I want to improve error handling a bit and add the new functionality to the docs. Then I will go for the pull request, since it is a general function, which does not theoretically depend on the specific spectrometer. I'll do the rest of the compatibility separately afterwards.

There remains one issue that I see right now:
The maximum number of spectra that can be requested depends on the spectrometer as far as I understand. Yet it is not part of the spectrometer feature definition files. So right now I don't see a proper way for error handling here. So I'm leaving that part out for now but maybe add a comment to the documentation.

@ap--
Copy link
Owner

ap-- commented Feb 21, 2024

v2.7.0 has this functionality exposed in the cseabreeze backend (not directly exposed to the Spectrometer class yet) thanks to @padalev

@ap-- ap-- closed this as completed Jun 27, 2024
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

9 participants