Giter Club home page Giter Club logo

Comments (5)

cboulay avatar cboulay commented on May 30, 2024

You cannot use StreamOutlet to receive data. You must be mistaken there.

If you want 2 streams to arrive with their timestamps synchronized to the same base, then you must enable timestamp post-processing on your inlet.
https://github.com/labstreaminglayer/pylsl/blob/master/pylsl/pylsl.py#L698-L701

As for whether or not you provide manual timestamps to the push_sample or push_chunk calls, I highly recommend you do not and you let LSL stamp them automatically, unless you know the true offset between the event and when you make the push_ call, in which case the timestamp should be pylsl.local_clock() - offset.

from labstreaminglayer.

ChadChen68 avatar ChadChen68 commented on May 30, 2024

I'm sorry for being so late in replying

I have read the file you recommended. So I did some practice and tried to synchronize 2 streams on the same PC.

At first, I use "SendData" and "SendStringMarkers" examples to generate an event and signal. And based on the liblsl example "ReceiveData" and "ReceiveStringMarkers".

To me, it looks like they are not synchronized

By the way, after I use outlet to push data and events, I just need to run my inlet script and it should synchronize my 2 streams, right?

Here is my inlet

螢幕擷取畫面 2024-03-01 171617

And here is the result
With proc
tp_proc
Without proc
tp_noproc

from labstreaminglayer.

cboulay avatar cboulay commented on May 30, 2024

The mistake here is that the pull_sample calls are blocking, waiting for data to become available, but they are only pulling one sample at a time. Your EEG stream is accumulating data because you're only pulling a single sample then waiting for a marker, then pulling a single sample of EEG again and waiting for a marker again.

You have a couple options. You can either call pull_sample with timeout=0.0 and skip over the case when nothing is returned, or you can call pull_chunk to get all samples in the buffer and then only look at the most recent timestamp.

Try this instead:

import pylsl


def main():
    # first resolve an EEG stream on the lab network
    print("looking for an EEG stream...")
    eeg_streams = pylsl.resolve_stream('type', 'EEG')
    marker_streams = pylsl.resolve_stream('type', 'Markers')

    # create a new inlet to read from the stream
    eeg_inlet = pylsl.StreamInlet(eeg_streams[0], processing_flags=pylsl.proc_ALL)
    marker_inlet = pylsl.StreamInlet(marker_streams[0], processing_flags=pylsl.proc_ALL)

    while True:
        # Wait until a marker is received...
        marker, marker_ts = marker_inlet.pull_sample()
        # And get whatever eeg has accumulated since the laste marker.
        eeg_chunk, eeg_ts = eeg_inlet.pull_chunk(timeout=0.0)

        # Print output
        print(f"Marker: {marker}\t\tMarkerTS:\t{marker_ts:3f}")
        if len(eeg_ts):
            print(f"EEG most recent ts: \t\t{eeg_ts[-1]:.3f}\tDelta: {eeg_ts[-1] - marker_ts:.3f}")


if __name__ == '__main__':
    main()

I get this output:

Marker: ['Testtest']		MarkerTS:	425804.079366
EEG most recent ts: 		425804.082	Delta: 0.003
Marker: ['Marker']		MarkerTS:	425806.760775
EEG most recent ts: 		425806.762	Delta: 0.001
Marker: ['Testtest']		MarkerTS:	425808.099470
EEG most recent ts: 		425808.092	Delta: -0.007
Marker: ['Testtest']		MarkerTS:	425808.507533
EEG most recent ts: 		425808.502	Delta: -0.006

from labstreaminglayer.

ChadChen68 avatar ChadChen68 commented on May 30, 2024

I'm so grateful for your help @cboulay, before your help I thought I was just like a headless fly.

I changed a little bit because my event is not continuous, so I added timeout=0.0, to avoid my inlet waiting for my event stream even if that time should be no events.

# create a new inlet to read from the stream
eeg_inlet = pylsl.StreamInlet(eeg_streams[0], processing_flags=pylsl.proc_ALL)
marker_inlet = pylsl.StreamInlet(marker_streams[0], processing_flags=pylsl.proc_ALL)

while True:
    # Wait until a marker is received...
    marker, marker_ts = marker_inlet.pull_sample(timeout=0.0)
    # And get whatever eeg has accumulated since the laste marker.
    eeg_chunk, eeg_ts = eeg_inlet.pull_sample(timeout=0.0)
   
    # Print output
    if marker_ts :
        print(f"Marker: {marker}\t\tMarkerTS:\t{marker_ts:3f}")
   print(f"Marker: {EEG}\t\eeg_ts:\t{eeg_chunk:3f}")

I believe the clocks are synchronized, and I don't know mine offset, so I will keep let timestamp catch automatically.
but there's still one thing I can't figure out. The red box is where my event should be, and the yellow box is where my event actually occurred after I load xdf from xdfimport plugin. It was lag 0.0479891017312184 second.

In this video https://www.youtube.com/watch?v=tDDkrmv3ZKE have mention that It might cause lagging because of network, router, load of network, load of PC. I also set both stream sample rate to 250Hz.

Do you have any clue that might cause 0.048 second lagging? I will try to change my 2.4G router to 5G router and see it will get better or not.

image

from labstreaminglayer.

cboulay avatar cboulay commented on May 30, 2024

Are you using more than 1 computer? Are they connected over wi-fi? If so that will cause poor synchronization. Briefly, the synchronization algorithm relies on the roundtrip time between the receiver and the sender being symmetrical -- same time to send and receive. This breaks down in wi-fi if packets are dropped and have to be re-sent. If synchronization is important then please run all applications on the same computer or use a wired LAN. If you absolutely need to use a wireless setup then there are some settings you can change.

The red box is where my event should be, and the yellow box is where my event actually occurred after I load xdf from xdfimport plugin.

I don't know what this means.

A couple comments about your new code:

  • I strongly recommend against using pull_sample for your EEG. Imagine if the print statement took 1.001 msec but your EEG sample rate was 1 kHz. You would never be able to catch up! Please use pull_chunk for anything faster than 10 Hz so you have ~95 msec to process between chunks.
  • For the eeg_inlet you use timeout=0.0 but you don't check if eeg_ts is empty before printing it. This only works because you're too far behind and never catching up! If you were caught up then at least some of the pull_sample calls would not get any data and you would be printing blank data.
  • The image you pasted was clearly not generated using the code you pasted because the formats don't match. I can't help you if I get incorrect information.

from labstreaminglayer.

Related Issues (20)

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.