Currently, I am using Zeto dry EEG headset and try to read the data in real-time through LSL. After reading the data in real-time, I would like process it with mne in real-time. If I enter the data of sample in LSL code into data variable as follows, can I make raw data of mne?
raw = mne.io.RawArray(data, info)
from pylsl import StreamInlet, resolve_stream
def main():
# first resolve an EEG stream on the lab network
print(“looking for an EEG stream…”)
streams = resolve_stream(‘type’, ‘EEG’)
# create a new inlet to read from the stream
inlet = StreamInlet(streams[0])
while True:
# get a new sample (you can also omit the timestamp part if you're not
# interested in it)
sample, timestamp = inlet.pull_chunk()
print(timestamp, sample)
It’s not easy but here is how I did it in one of my projects. @kyuwanchoi
retrieve the sampling rate from info.nominal_srate() looping on for info in pylsl.resolve_streams() and making sure you catch the right one by checking info.name() or other parameters
define the SteamInlet with the max_buflen parameter matching the max number of seconds you want to retrieve, for me it was 2 seconds pylsl.StreamInlet(info, max_buflen=2000, processing_flags=pylsl.proc_clocksync | pylsl.proc_dejitter)
Create an empty numpy buffer or np.ndarray(N electrodes, N seconds x sampling rate)
This is still a mistery to me how to do it right, but periodically retrieve your data properly in a numpy array the size of the buffer.
create a mne.io.RawArray. I think you have to use y = np.transpose(array) because lsl and MNE have different structure. Then create a raw off your info and data raw = mne.io.RawArray(data=y, info=data_inlet.mne_info, verbose=False)
Try to find a way to rename the channels. Also, make sure to put a filename to prevent a bug in plotting your data: raw._filenames = [‘lsl_is_not_a_file_duuh’]
Now you don’t want to reinitialize any raw. Copy your raw and perform stuff you want to do on it. Just make a copy before reusable_raw = raw.copy()
Erase the data from it reusable_raw ._data = None
Pickle the raw, it will keep information stored along with the raw: pickled_raw= pickle.dumps(reusable_raw ). Of course don’t do this after you performed any data transformation, but before.
on the next iteration, load the pickled raw raw = pickle.loads(pickled_raw). and put the new data directly inside raw._data = y. Enjoy massive performance gains by using the pickle trick (“I’m Pickle riiick”)
If you want, you can have a look at NeuroDecode, especially to my fork which improves the low-level LSL communication classes and methods. I will soon rename the library to bsl and publish it on pip.
Basically, it would look like this for EEG:
import mne
from neurodecode import StreamReceiver
sr = StreamReceiver(stream_name='Name')
sr.acquire()
data, timestamps = sr.get_window() # data is samples x channels
data *= 1e-6 # convert to Volts, to be adapted.
info = mne.create_info(
ch_names=sr.streams['Name'].ch_list,
sfreq=sr.streams['Name'].sample_rate,
ch_types=['eeg']*len(sr.streams['Name'].ch_list))
raw = mne.io.RawArray(data.T, info) # expect channels x samples
The StreamReceiver allows you to connect to multiple LSL streams and to retrieve data from one or more of those streams. It basically is a wrapper to simplify the use of pylsl.
For recording, you have a StreamRecorder provided in the lib.