streaming analog data to LSL [resolved]

edited April 2024 in Software

Hi!
I’m trying to stream analog data from a photoresistor to LSL but keep running into problems:

1) Can’t stream through OpenBCI_LSL:
Streaming via OpenBCI_LSL [1] works fine in default mode, but when I set the board mode to analog I run into this error:
WARNING:root:ID:<15> <Unexpected END_BYTE found <193> instead of <192> Warning: ID:<15> <Unexpected END_BYTE found <193> instead of <192> Exception in thread Thread-1 (start_streaming): Traceback (most recent call last): File "C:\Users\user\.conda\envs\openbci\Lib\threading.py", line 1045, in _bootstrap_inner self.run() File "C:\Users\user\.conda\envs\openbci\Lib\threading.py", line 982, in run self._target(*self._args, **self._kwargs) File "C:\nfb\software\OpenBCI_LSL\lib\open_bci_v3.py", line 162, in start_streaming if ~sample.id % 2: ^^^^^^^^^ AttributeError: 'NoneType' object has no attribute 'id' WARNING:root:Reconnecting Warning: Reconnecting
This seems to be a common issue that hasn’t been fixed yet: [2], [3], [4]

2) Sampling frequency through OpenBCI GUI is too low:
When using the OpenBCI GUI Networking widget [5], I’m able to stream analog data to LSL, but the sampling rate is too low – sometimes it’s 40 Hz, 80 Hz or 90 Hz, and I don’t understand why. It also doesn’t matter whether I send it alone or together with other data. If I additionally send the raw time series (or even both the raw and filtered time series) together with the analog data, the time series have a srate of 125 Hz while the analog data srate is too low.

3) Brainflow Streamer isn’t working.
Trying to use the Brainflow Streamer as described in the ‘GUI to External Process’ [6] paragraph of the docs: I’m setting the IP address and port, start the session, and start the data stream. Should the stream be picked up by LSL after that, or am I missing something? (I installed Brainflow via ‘$ python -m pip install brainflow’)

[1] https://github.com/openbci-archive/OpenBCI_LSL
[2] https://github.com/openbci-archive/OpenBCI_LSL/issues/20
[3] https://github.com/openbci-archive/OpenBCI_LSL/issues/18
[4] https://openbci.com/forum/index.php?p=/discussion/comment/17802/#Comment_17802
[5] https://docs.openbci.com/Software/OpenBCISoftware/GUIWidgets/#networking
[6] https://docs.openbci.com/Software/OpenBCISoftware/GUIDocs/?_gl=1*1o7rg15*_ga*MTgyMTMxNDg2My4xNzA5OTIxNTUy*_ga_HVMLC0ZWWS*MTcxMjE2NDU5OS4zNC4xLjE3MTIxNjgyMzEuNy4wLjA.#gui-to-external-process

System info:
OS: Win 10 Enterprise
OpenBCI GUI v5.2.2
Amp: Cyton+Daisy - Firmware v3.1.2

Please let me know what I can next try to be able to stream the analog data at 125 Hz via LSL.

Comments

  • wjcroftwjcroft Mount Shasta, CA
    edited April 2024

    Hi Martin,

    Regarding your paragraphs above.

    (1) The OpenBCI_LSL repository / library is no longer supported or recommended. It has not been maintained in years.

    (2) The GUI developer, Richard @retiutut may have some insights on your question regarding the Networking Widget.

    (3) If you stream out from the GUI using the Brainflow Streamer, that assumes you have a Python (or other language) program running to receive the data stream using Brainflow library calls. There is no automatic conversion to LSL. If your Python program wants to write an LSL stream, it needs to use the appropriate Python LSL library calls.

    https://brainflow.readthedocs.io/en/stable/SupportedBoards.html#streaming-board
    https://brainflow.readthedocs.io/en/stable/Examples.html#python
    https://labstreaminglayer.readthedocs.io/info/intro.html
    https://labstreaminglayer.readthedocs.io/dev/app_dev.html#python-apps

    Regards, William

  • Hi William,
    Based on your answer I thought I might give Brainflow a go and wrote a Python script to read data via Brainflow (without using the GUI) and stream it to LSL.
    While the sampling rates for the eeg and analog stream are now (approximately) equal, I noticed other inconsistencies which I investigated further. It seems as if this results from how Brainflow reads the data. It looks like I get a srate of 120 Hz for 11 seconds, followed by 180 Hz for the 12th second. This averages out to the specified srate of 125 Hz (=(11s*120Hz+1s*180Hz)/12s):

    Effective srate: 119.909 Hz
    Effective srate: 119.950 Hz
    Effective srate: 119.960 Hz
    Effective srate: 120.986 Hz
    Effective srate: 119.950 Hz
    Effective srate: 119.891 Hz
    Effective srate: 119.921 Hz
    Effective srate: 120.972 Hz
    Effective srate: 119.987 Hz
    Effective srate: 119.999 Hz
    Effective srate: 119.962 Hz
    Effective srate: 180.957 Hz
    Effective srate: 119.965 Hz
    Effective srate: 119.951 Hz
    Effective srate: 119.956 Hz
    Effective srate: 120.880 Hz
    Effective srate: 119.914 Hz
    Effective srate: 119.952 Hz
    Effective srate: 119.911 Hz
    Effective srate: 120.885 Hz
    Effective srate: 119.935 Hz
    Effective srate: 119.992 Hz
    Effective srate: 119.890 Hz
    Effective srate: 180.857 Hz
    [...]
    

    This is a minimal script (from which I removed everything regarding LSL) that allows (at least on my system) to replicate the effective sampling rate above:

    import time
    from brainflow.board_shim import BoardShim, BrainFlowInputParams, BoardIds
    
    # Setup Brainflow
    BoardShim.enable_dev_board_logger()
    params = BrainFlowInputParams()
    params.serial_port = "COM5"
    board = BoardShim(BoardIds.CYTON_DAISY_BOARD, params)
    srate = board.get_sampling_rate(BoardIds.CYTON_DAISY_BOARD.value)
    board.prepare_session()
    board.start_stream ()
    eeg_chan = BoardShim.get_eeg_channels(BoardIds.CYTON_DAISY_BOARD.value)
    ana_chan = BoardShim.get_analog_channels(BoardIds.CYTON_DAISY_BOARD.value)
    
    # Monitor srate
    sample_count = 0
    start_time = time.time()
    
    while True:
        data = board.get_board_data()
    
        if data.size > 0:
            sample_count += data.shape[1]
    
        current_time = time.time()
        if current_time - start_time >= 1:
            effective_srate = sample_count / (current_time - start_time)
            print(f"Effective srate: {effective_srate:.3f} Hz")
    
            start_time = current_time
            sample_count = 0
    

    Is this typical behavior for Brainflow?

    I appreciate your help!
    Cheers, Martin

  • retiututretiutut Louisiana, USA

    Great suggestions William! I also recommend trying https://github.com/OpenBCI/OpenBCI_GUI/releases/tag/v6.0.0-beta.1.

  • wjcroftwjcroft Mount Shasta, CA

    @H3xon, hi.

    You cannot 'derive' certain sample rates based on the arrival times of the data at your program. The sample rate at the Cyton is always constant, either 250 Hz or 125 Hz, depending on the Daisy being present. The data packets are being buffered in the dongle, in usb buffers, in Python buffers, etc. This all influences how rapidly the data stream hits your program. Other factors include OS scheduling and system loading, etc.

    William

  • @wjcroft this makes total sense, thanks for the explanation!

    @retiutut the problem seems to be resolved with this newer version of the GUI, thank you!

Sign In or Register to comment.