Automatic vs Manual acquisitionπŸ”—

The StreamLSL object offers 2 mode of acquisition: automatic or manual. In automatic mode, the stream object acquires new chunks of samples at a regular interval. In manual mode, the user has to call the acquire() to acquire new chunks of samples from the network. The automatic or manual acquisition is selected via the acquisition_delay argument of connect():

  • a non-zero positive integer value will set the acquisition to automatic mode with the specified delay in seconds.

  • 0 will set the acquisition to manual mode.

Automatic acquisitionπŸ”—

When the stream is set to automatically acquire new samples at a regular interval, a background thread is created with concurrent.futures.ThreadPoolExecutor. The background thread is periodically receives a job to acquire new samples from the network.

Important

If the main thread is hogging all of the CPU resources, the delay between two acquisition job might be longer than the specified delay. The background thread will always do its best to acquire new samples at the specified delay, but it is not able to do so if the CPU is busy.

import uuid
from time import sleep

from matplotlib import pyplot as plt

from mne_lsl.datasets import sample
from mne_lsl.player import PlayerLSL
from mne_lsl.stream import StreamLSL

# create a mock LSL stream for this tutorial
fname = sample.data_path() / "sample-ant-raw.fif"
source_id = uuid.uuid4().hex
player = PlayerLSL(fname, chunk_size=200, source_id=source_id).start()
player.info
General
MNE object type Info
Measurement date Unknown
Participant Unknown
Experimenter mne_anonymize
Acquisition
Sampling frequency 1024.00 Hz
Channels
EEG
EOG
ECG
Stimulus
Galvanic skin response
Head & sensor digitization Not available
Filters
Highpass 0.00 Hz
Lowpass 512.00 Hz


Note

A chunk_size of 200 samples is used here to ensure stability and reliability while building the documentation on the CI. In practice, a chunk_size of 200 samples is too large to represent a real-time application.

stream = StreamLSL(bufsize=2, source_id=source_id).connect(acquisition_delay=0.1)
sleep(2)  # wait for new samples
print(f"New samples acquired: {stream.n_new_samples}")
stream.disconnect()
New samples acquired: 3200

<Stream: OFF | MNE-LSL-Player (source: c7421cb797524613932176f400b8e4f9)>

Manual acquisitionπŸ”—

In manual acquisition mode, the user has to call the acquire() to get new samples from the network. In this mode, all operation happens in the main thread and the user has full control over when to acquire new samples.

stream = StreamLSL(bufsize=2, source_id=source_id).connect(acquisition_delay=None)
sleep(2)  # wait for new samples
print(f"New samples acquired (before stream.acquire()): {stream.n_new_samples}")
stream.acquire()
print(f"New samples acquired (after stream.acquire()): {stream.n_new_samples}")
New samples acquired (before stream.acquire()): 0
New samples acquired (after stream.acquire()): 2048

However, it is also now up to the user to make sure he acquires new samples regularly and does not miss part of the stream. The created StreamInlet has its buffer set to the same value as the StreamLSL object.

stream.acquire()
data1, ts1 = stream.get_data(picks="Cz")
sleep(4)  # wait for 2 buffers
stream.acquire()
data2, ts2 = stream.get_data(picks="Cz")

f, ax = plt.subplots(1, 1, layout="constrained")
ax.plot(ts1 - ts1[0], data1.squeeze(), color="blue", label="acq 1")
ax.plot(ts2 - ts1[0], data2.squeeze(), color="red", label="acq 2")
ax.legend()
ax.set_xlabel("Time (s)")
ax.set_ylabel("EEG amplitude")
plt.show()
30 stream manual

Free resourcesπŸ”—

When you are done with a PlayerLSL or StreamLSL, don’t forget to free the resources they both use to continuously mock an LSL stream or receive new data from an LSL stream.

<Stream: OFF | MNE-LSL-Player (source: c7421cb797524613932176f400b8e4f9)>
<Player: MNE-LSL-Player | OFF | /home/runner/mne_data/MNE-LSL-data/sample/sample-ant-raw.fif>

Total running time of the script: (0 minutes 12.604 seconds)

Estimated memory usage: 265 MB

Gallery generated by Sphinx-Gallery