Diagram dat gesynchroniseerde neurowetenschappelijke gegevensverzameling illustreert met behulp van Lab Streaming Layer (LSL). Een Emotiv EEG-headset, audiobron en event-trigger streamen EEG-signalen, audiogolfvormen en getimede markeringen naar uitgelijnde tijdlijnen die samenkomen in een centrale opname-interface voor gesynchroniseerde multimodale gegevensanalyse.

Lab Streaming Layer (LSL) voor het synchroniseren van meerdere gegevensstromen

Dr. Roshini Randeniya en Lucas Kleine

Bijgewerkt op

17 mei 2024

Diagram dat gesynchroniseerde neurowetenschappelijke gegevensverzameling illustreert met behulp van Lab Streaming Layer (LSL). Een Emotiv EEG-headset, audiobron en event-trigger streamen EEG-signalen, audiogolfvormen en getimede markeringen naar uitgelijnde tijdlijnen die samenkomen in een centrale opname-interface voor gesynchroniseerde multimodale gegevensanalyse.

Lab Streaming Layer (LSL) voor het synchroniseren van meerdere gegevensstromen

Dr. Roshini Randeniya en Lucas Kleine

Bijgewerkt op

17 mei 2024

Diagram dat gesynchroniseerde neurowetenschappelijke gegevensverzameling illustreert met behulp van Lab Streaming Layer (LSL). Een Emotiv EEG-headset, audiobron en event-trigger streamen EEG-signalen, audiogolfvormen en getimede markeringen naar uitgelijnde tijdlijnen die samenkomen in een centrale opname-interface voor gesynchroniseerde multimodale gegevensanalyse.

Lab Streaming Layer (LSL) voor het synchroniseren van meerdere gegevensstromen

Dr. Roshini Randeniya en Lucas Kleine

Bijgewerkt op

17 mei 2024

Welkom! In deze handleiding leren we hoe we Lab Streaming Layer (LSL) in Python kunnen gebruiken om Emotiv EEG-gegevens van meerdere apparaten te verzamelen en te synchroniseren. Hiervoor is een basiskennis van de programmeertaal Python vereist.

Wat u zult leren

  1. Wat Lab Streaming Layer (LSL) is en waarom onderzoekers het gebruiken

  2. Hoe u gesynchroniseerde gegevens van meerdere Emotiv EEG-apparaten kunt verzamelen

  3. Hoe u verzamelde gegevens kunt importeren en inspecteren

1.1 Wat is LSL en waar is het goed voor?

Lab streaming layer (LSL) is een open-source toolbox die kan worden gebruikt voor het verzenden, ontvangen en synchroniseren van neurale, fysiologische en gedragsmatige gegevensstromen van diverse sensorhardware. Steeds krachtigere, nauwkeurigere en mobielere hersen- en lichaamssensoren (zoals Emotiv EEG-systemen) brengen neurowetenschap buiten het lab naar de wereld van realtime gegevens. Waar hersenmetingen zoals EEG en MEG ooit beperkt waren tot onderzoekslaboratoria, stellen mobiele apparaten ons in staat om meerdere gegevensstromen te verzamelen in meer natuurlijke omgevingen, en van meerdere mensen tegelijk.

Een onderzoeker kan geïnteresseerd zijn in fysiologische synchroniciteit tussen twee mensen die naar dezelfde muziek luisteren. LSL kan ons helpen om gegevens van twee EEG-headsets afzonderlijk te verzamelen die ook gesynchroniseerd zijn met de presentatie van geluid.

Enkele voorbeelden van andere toepassingen voor LSL:

  1. Gebeurtenismarkeringen (event markers) van een experiment toevoegen aan lopende EEG-gegevens

  2. Gegevens uit meerdere bronnen in de tijd uitlijnen voor een enkele deelnemer (bijv. hartslag, EMG, EEG)

  3. Gegevens van meerdere deelnemers in de tijd uitlijnen (bijv. EEG Hyperscanning-onderzoeken)

1.2 Hoe werkt LSL?

Lab Streaming Layer is een protocol voor de realtime uitwisseling van tijdreeksgegevens tussen meerdere apparaten. LSL kan worden geïmplementeerd met behulp van open-source bibliotheken voor programmeertalen zoals Python, MATLAB, C++, Java and andere.

De kernfunctionaliteit draait om LSL-gegevensstromen:

1. Een acquisitie-apparaat/software verzamelt gegevens en creëert een gegevensstroom - Fysiologische gegevens kunnen naar LSL worden gestreamd vanaf EEG-registratieapparaten, eye-trackers, motion capture-systemen, hartslagmeters, enz., inclusief metadata (bemonsteringsfrequentie, datatype, kanaalinformatie, enz.) - Gebeurtenismarkeringen van experimenten (bijv. met PsychoPy) kunnen ook als een gegevensstroom worden verzonden met behulp van LSL

2. De gegevensstroom wordt op het netwerk gepubliceerd - Dit is hoe gegevens worden verzonden via LSL; de gegevensstroom wordt "uitgezonden" naar het netwerk - Gepubliceerde stromen zijn beschikbaar op het netwerk en vindbaar door andere LSL-ondersteunde apparaten op hetzelfde netwerk - LSL kent aan elk gegevenssegment of monster een tijdstempel toe op basis van een gemeenschappelijke klok (volgens het Network Time Protocol). - De stroom wordt monster-voor-monster (of segment-voor-segment) door een "outlet" geduwd

3. Verzamelapparaat/apparaten "abonneren" op gegevensstroom/stromen - Dit is hoe gegevens worden ontvangen met behulp van LSL - Verzamelapparaten op hetzelfde netwerk ontvangen gepubliceerde gegevensstromen via "inlets". - Elke inlet ontvangt de stroommonsters en metadata van slechts één outlet

4. Gegevens opslaan - Na het abonneren op een gegevensstroom kunt u deze opslaan in een variabele in uw favoriete programmeertaal, of de meegeleverde software LabRecorder van LSL gebruiken om deze op te slaan in een standaardformaat zoals .xdf.

2.0 Overzicht van de handleiding

In deze handleiding nemen we een voorbeeld van een experimentele opstelling en leiden we u door de nodige stappen en code om deze te implementeren met behulp van LSL in Python. We gebruiken Python om een geluid af te spelen terwijl we EEG-gegevens verzamelen van twee mensen die Emotiv-headsets dragen. We gebruiken twee computers die elk EmotivPRO draaien om de EEG-gegevens te verzamelen, en zenden elke stroom uit via een aparte LSL-outlet. We gebruiken een Python-bibliotheek om een audiobestand af te spelen en tegelijkertijd een trigger te verzenden telkens wanneer het bestand start.

STAPPEN:

1. Gebruik EmotivPRO om gegevens te streamen via LSL-outlets, inclusief EEG-gegevens (en/of beweging, contactkwaliteit, signaalkwaliteit, enz.) 2. Speel een audiotrack af met een Python-script en stuur tegelijkertijd een trigger via een andere LSL. Gebruik LabRecorder om alle drie de gegevensstromen vast te leggen en op te slaan via een LSL-inlet.

2.1 STAP 1 - Installatie en configuratie

  1. U hebt ondersteunde gegevensacquisitie-apparaten nodig om gegevens te verzamelen
    • Alle brainware-apparaten van Emotiv maken verbinding met LSL via de EmotivPRO-software

  2. Installeer EmotivPRO op uw apparaat/apparaten. U hebt een geldige EmotivPRO-licentie nodig om LSL te gebruiken.

  3. Installeer de Python LSL-bibliotheek met de volgende opdracht:
    pip install pylsl

  4. Download de LabRecorder-software. Dit is een eenvoudige, gratis app die kan worden uitgevoerd vanaf
    de opdrachtregel of met behulp van een zelfstandige download

  5. Voor ons experiment: Installeer de benodigde pakketten voor het afspelen van audio met Python
    pip install sounddevice soundfile

2.2 STAP 3 - Verzend de gegevens van EmotivPRO via een LSL-stroom

  1. Zoek de "..." in de rechterbovenhoek van de app, navigeer naar Instellingen

  2. Zoek de sectie 'Lab Streaming Layer' en de subsectie 'Outlet'

  3. Selecteer alle datatypes die u wilt uitzenden

  4. Selecteer het gegevensformaat (32-bits float of 64-bits double)

  5. Selecteer of u de gegevens monster-voor-monster of in segmenten van monsters wilt verzenden

  6. Klik op 'Start' om een LSL-gegevensstroom uit te zenden

2.3 STAP 4 - Gebruik een Python-script om audio af te spelen en triggers te verzenden

  1. Kopieer en plak het volgende codeblok in een Python-bestand en sla het op uw computer op.

  2. Zoek een audiobestand (bij voorkeur een .wav-bestand) dat u wilt afspelen en bewerk het script door de
    variabele audio_filepath te wijzigen in het bestandspad naar uw audiobestand op uw computer

  3. Open een opdrachtprompt om de opdrachtregel te gebruiken en navigeer naar de map waar
    uw Python-bestand is opgeslagen

  4. Voer in: python3 bestandsnaam.py
    • Afhankelijk van uw Python-installatie gebruikt u mogelijk python in plaats van python3

    Opmerking: Vervang /path/to/audio.wav door de locatie van het audiobestand dat u tijdens uw experiment wilt afspelen.

"""
LSL Example: Play audio and send a trigger marker
<p>This script creates an LSL marker stream, waits for the user to<br>press ENTER, then plays an audio file and sends a marker that<br>can be synchronized with EEG data collected through LabRecorder.<br>"""</p>
<p>import sounddevice as sd<br>import soundfile as sf<br>from pylsl import StreamInfo, StreamOutlet</p>
<p>def wait_for_keypress():<br>print("Press ENTER to start audio playback and send an LSL marker.")<br>while True:<br>if input() == "":<br>break</p>
<p>def play_audio_and_send_marker(audio_file, outlet):<br>data, fs = sf.read(audio_file)</p>
<pre><code>print("Playing audio and sending LSL marker...")

marker_val = [1]
outlet.push_sample(marker_val)

sd.play(data, fs)
sd.wait()

print("Audio playback finished.")
</code></pre>
<p>if <strong>name</strong> == "<strong>main</strong>":</p>
<pre><code>info = StreamInfo(
    name="AudioMarkers",
    type="Markers",
    channel_count=1,
    nominal_srate=0,
    channel_format="int32",
    source_id="uniqueMarkerID12345"
)

outlet = StreamOutlet(info)

while True:
    wait_for_keypress()

    audio_filepath = "/path/to/audio.wav"

    play_audio_and_send_marker(
        audio_filepath,
        outlet
    )</code></pre><h2 dir="auto">2.4 STEP 5 - Use LabRecorder to view and save all LSL streams</h2><ol dir="auto"><li data-preset-tag="p"><p>Open LabRecorder</p></li><li data-preset-tag="p"><p>Press <code>Update</code>. The available LSL streams should be visible in the stream list<br> You should be able to see streams from both EmotivPROs (usually called “Emotiv-<br>DataStream”) and the marker stream (called “AudioMarkers”)</p></li><li data-preset-tag="p"><p>Click <code>Browse</code> to select a location to store data (and set other parameters)</p></li><li data-preset-tag="p"><p>Select all streams and press <code>Record</code> to start recording</p></li></ol><h2 dir="auto">3.0 Working with the data</h2><p dir="auto">LabRecorder outputs an XDF file (Extensible Data Format) that contains data from all the streams. XDF files are structured into, streams, each with a different header that describes what it contains (device name, data type, sampling rate, channels, and more). You can use the below codeblock to open your XDF file and display some basic information.</p><p dir="auto"><strong>Note: Replace </strong><code><strong>/path/to/your/file.xdf</strong></code><strong> with the filepath for your LabRecorder XDF output file.</strong></p><pre data-language="JSX"><code>import pyxdf
</code></pre>
<p>import mne<br>import matplotlib.pyplot as plt<br>import numpy as np</p>
<h1>Give the path to your LSL output file here.</h1>
<p>data_path = "/path/to/your/file.xdf"</p>
<h1>Load the XDF file.</h1>
<p>streams, fileheader = pyxdf.load_xdf(data_path)</p>
<p>print("XDF File Header:", fileheader)<br>print("Number of streams found:", len(streams))</p>
<p>for i, stream in enumerate(streams):<br>print("\nStream", i + 1)<br>print("Stream Name:", stream["info"]["name"][0])<br>print("Stream Type:", stream["info"]["type"][0])<br>print("Number of Channels:", stream["info"]["channel_count"][0])</p>
<pre><code>sfreq = float(stream["info"]["nominal_srate"][0])
print("Sampling Rate:", sfreq)

print("Number of Samples:", len(stream["time_series"]))
print("First 5 data points:", stream["time_series"][:5])

channel_names = [
    chan["label"][0]
    for chan in stream["info"]["desc"][0]["channels"][0]["channel"]
]

print("Channel Names:", channel_names)

channel_types = "eeg"</code></pre><h3 dir="auto"><br></h3><h2 dir="auto">4.0 Additional Resources</h2><h4 dir="auto">Official Documentation</h4><ol dir="auto"><li data-preset-tag="p"><p>Check out the <a href="1. Check out the online documentation, including the official README file on GitHub 2. Additional resources: • Code to run LSL using Emotiv’s devices, with example scripts • Useful LSL demo on YouTube • SCCN LSL GitHub repository for all associated libraries • LSL GitHub repository for a collection a submodules and apps 3. HyPyP analysis pipeline for Hyperscanning studies" target="_blank">online documentation</a>, including the <a href="https://github.com/sccn/labstreaminglayer/" target="_blank">official README file on GitHub</a></p></li><li data-preset-tag="p"><p>Additional resources:<br> <a href="https://github.com/Emotiv/labstreaminglayer" target="_blank">Code</a> to run LSL using Emotiv’s devices, with example scripts<br> Useful <a href="https://www.youtube.com/watch?v=Y1at7yrcFW0&amp;list=PLVnr33MP5RMRhGwY36zHHDOmAaYTB138D" target="_blank">LSL demo on YouTube</a><br> <a href="https://github.com/sccn/labstreaminglayer" target="_blank">SCCN LSL GitHub repository</a> for all associated libraries<br> <a href="https://github.com/labstreaminglayer" target="_blank">LSL GitHub repository</a> for a collection a submodules and apps</p></li><li data-preset-tag="p"><p><a href="https://academic.oup.com/scan/article/16/1-2/72/5919711?login=false" target="_blank">HyPyP analysis pipeline</a> for Hyperscanning studies</p></li></ol>
</code></pre

"""
LSL Example: Play audio and send a trigger marker
<p>This script creates an LSL marker stream, waits for the user to<br>press ENTER, then plays an audio file and sends a marker that<br>can be synchronized with EEG data collected through LabRecorder.<br>"""</p>
<p>import sounddevice as sd<br>import soundfile as sf<br>from pylsl import StreamInfo, StreamOutlet</p>
<p>def wait_for_keypress():<br>print("Press ENTER to start audio playback and send an LSL marker.")<br>while True:<br>if input() == "":<br>break</p>
<p>def play_audio_and_send_marker(audio_file, outlet):<br>data, fs = sf.read(audio_file)</p>
<pre><code>print("Playing audio and sending LSL marker...")

marker_val = [1]
outlet.push_sample(marker_val)

sd.play(data, fs)
sd.wait()

print("Audio playback finished.")
</code></pre>
<p>if <strong>name</strong> == "<strong>main</strong>":</p>
<pre><code>info = StreamInfo(
    name="AudioMarkers",
    type="Markers",
    channel_count=1,
    nominal_srate=0,
    channel_format="int32",
    source_id="uniqueMarkerID12345"
)

outlet = StreamOutlet(info)

while True:
    wait_for_keypress()

    audio_filepath = "/path/to/audio.wav"

    play_audio_and_send_marker(
        audio_filepath,
        outlet
    )</code></pre><h2 dir="auto">2.4 STEP 5 - Use LabRecorder to view and save all LSL streams</h2><ol dir="auto"><li data-preset-tag="p"><p>Open LabRecorder</p></li><li data-preset-tag="p"><p>Press <code>Update</code>. The available LSL streams should be visible in the stream list<br> You should be able to see streams from both EmotivPROs (usually called “Emotiv-<br>DataStream”) and the marker stream (called “AudioMarkers”)</p></li><li data-preset-tag="p"><p>Click <code>Browse</code> to select a location to store data (and set other parameters)</p></li><li data-preset-tag="p"><p>Select all streams and press <code>Record</code> to start recording</p></li></ol><h2 dir="auto">3.0 Working with the data</h2><p dir="auto">LabRecorder outputs an XDF file (Extensible Data Format) that contains data from all the streams. XDF files are structured into, streams, each with a different header that describes what it contains (device name, data type, sampling rate, channels, and more). You can use the below codeblock to open your XDF file and display some basic information.</p><p dir="auto"><strong>Note: Replace </strong><code><strong>/path/to/your/file.xdf</strong></code><strong> with the filepath for your LabRecorder XDF output file.</strong></p><pre data-language="JSX"><code>import pyxdf
</code></pre>
<p>import mne<br>import matplotlib.pyplot as plt<br>import numpy as np</p>
<h1>Give the path to your LSL output file here.</h1>
<p>data_path = "/path/to/your/file.xdf"</p>
<h1>Load the XDF file.</h1>
<p>streams, fileheader = pyxdf.load_xdf(data_path)</p>
<p>print("XDF File Header:", fileheader)<br>print("Number of streams found:", len(streams))</p>
<p>for i, stream in enumerate(streams):<br>print("\nStream", i + 1)<br>print("Stream Name:", stream["info"]["name"][0])<br>print("Stream Type:", stream["info"]["type"][0])<br>print("Number of Channels:", stream["info"]["channel_count"][0])</p>
<pre><code>sfreq = float(stream["info"]["nominal_srate"][0])
print("Sampling Rate:", sfreq)

print("Number of Samples:", len(stream["time_series"]))
print("First 5 data points:", stream["time_series"][:5])

channel_names = [
    chan["label"][0]
    for chan in stream["info"]["desc"][0]["channels"][0]["channel"]
]

print("Channel Names:", channel_names)

channel_types = "eeg"</code></pre><h3 dir="auto"><br></h3><h2 dir="auto">4.0 Additional Resources</h2><h4 dir="auto">Official Documentation</h4><ol dir="auto"><li data-preset-tag="p"><p>Check out the <a href="1. Check out the online documentation, including the official README file on GitHub 2. Additional resources: • Code to run LSL using Emotiv’s devices, with example scripts • Useful LSL demo on YouTube • SCCN LSL GitHub repository for all associated libraries • LSL GitHub repository for a collection a submodules and apps 3. HyPyP analysis pipeline for Hyperscanning studies" target="_blank">online documentation</a>, including the <a href="https://github.com/sccn/labstreaminglayer/" target="_blank">official README file on GitHub</a></p></li><li data-preset-tag="p"><p>Additional resources:<br> <a href="https://github.com/Emotiv/labstreaminglayer" target="_blank">Code</a> to run LSL using Emotiv’s devices, with example scripts<br> Useful <a href="https://www.youtube.com/watch?v=Y1at7yrcFW0&amp;list=PLVnr33MP5RMRhGwY36zHHDOmAaYTB138D" target="_blank">LSL demo on YouTube</a><br> <a href="https://github.com/sccn/labstreaminglayer" target="_blank">SCCN LSL GitHub repository</a> for all associated libraries<br> <a href="https://github.com/labstreaminglayer" target="_blank">LSL GitHub repository</a> for a collection a submodules and apps</p></li><li data-preset-tag="p"><p><a href="https://academic.oup.com/scan/article/16/1-2/72/5919711?login=false" target="_blank">HyPyP analysis pipeline</a> for Hyperscanning studies</p></li></ol>
</code></pre

"""
LSL Example: Play audio and send a trigger marker
<p>This script creates an LSL marker stream, waits for the user to<br>press ENTER, then plays an audio file and sends a marker that<br>can be synchronized with EEG data collected through LabRecorder.<br>"""</p>
<p>import sounddevice as sd<br>import soundfile as sf<br>from pylsl import StreamInfo, StreamOutlet</p>
<p>def wait_for_keypress():<br>print("Press ENTER to start audio playback and send an LSL marker.")<br>while True:<br>if input() == "":<br>break</p>
<p>def play_audio_and_send_marker(audio_file, outlet):<br>data, fs = sf.read(audio_file)</p>
<pre><code>print("Playing audio and sending LSL marker...")

marker_val = [1]
outlet.push_sample(marker_val)

sd.play(data, fs)
sd.wait()

print("Audio playback finished.")
</code></pre>
<p>if <strong>name</strong> == "<strong>main</strong>":</p>
<pre><code>info = StreamInfo(
    name="AudioMarkers",
    type="Markers",
    channel_count=1,
    nominal_srate=0,
    channel_format="int32",
    source_id="uniqueMarkerID12345"
)

outlet = StreamOutlet(info)

while True:
    wait_for_keypress()

    audio_filepath = "/path/to/audio.wav"

    play_audio_and_send_marker(
        audio_filepath,
        outlet
    )</code></pre><h2 dir="auto">2.4 STEP 5 - Use LabRecorder to view and save all LSL streams</h2><ol dir="auto"><li data-preset-tag="p"><p>Open LabRecorder</p></li><li data-preset-tag="p"><p>Press <code>Update</code>. The available LSL streams should be visible in the stream list<br> You should be able to see streams from both EmotivPROs (usually called “Emotiv-<br>DataStream”) and the marker stream (called “AudioMarkers”)</p></li><li data-preset-tag="p"><p>Click <code>Browse</code> to select a location to store data (and set other parameters)</p></li><li data-preset-tag="p"><p>Select all streams and press <code>Record</code> to start recording</p></li></ol><h2 dir="auto">3.0 Working with the data</h2><p dir="auto">LabRecorder outputs an XDF file (Extensible Data Format) that contains data from all the streams. XDF files are structured into, streams, each with a different header that describes what it contains (device name, data type, sampling rate, channels, and more). You can use the below codeblock to open your XDF file and display some basic information.</p><p dir="auto"><strong>Note: Replace </strong><code><strong>/path/to/your/file.xdf</strong></code><strong> with the filepath for your LabRecorder XDF output file.</strong></p><pre data-language="JSX"><code>import pyxdf
</code></pre>
<p>import mne<br>import matplotlib.pyplot as plt<br>import numpy as np</p>
<h1>Give the path to your LSL output file here.</h1>
<p>data_path = "/path/to/your/file.xdf"</p>
<h1>Load the XDF file.</h1>
<p>streams, fileheader = pyxdf.load_xdf(data_path)</p>
<p>print("XDF File Header:", fileheader)<br>print("Number of streams found:", len(streams))</p>
<p>for i, stream in enumerate(streams):<br>print("\nStream", i + 1)<br>print("Stream Name:", stream["info"]["name"][0])<br>print("Stream Type:", stream["info"]["type"][0])<br>print("Number of Channels:", stream["info"]["channel_count"][0])</p>
<pre><code>sfreq = float(stream["info"]["nominal_srate"][0])
print("Sampling Rate:", sfreq)

print("Number of Samples:", len(stream["time_series"]))
print("First 5 data points:", stream["time_series"][:5])

channel_names = [
    chan["label"][0]
    for chan in stream["info"]["desc"][0]["channels"][0]["channel"]
]

print("Channel Names:", channel_names)

channel_types = "eeg"</code></pre><h3 dir="auto"><br></h3><h2 dir="auto">4.0 Additional Resources</h2><h4 dir="auto">Official Documentation</h4><ol dir="auto"><li data-preset-tag="p"><p>Check out the <a href="1. Check out the online documentation, including the official README file on GitHub 2. Additional resources: • Code to run LSL using Emotiv’s devices, with example scripts • Useful LSL demo on YouTube • SCCN LSL GitHub repository for all associated libraries • LSL GitHub repository for a collection a submodules and apps 3. HyPyP analysis pipeline for Hyperscanning studies" target="_blank">online documentation</a>, including the <a href="https://github.com/sccn/labstreaminglayer/" target="_blank">official README file on GitHub</a></p></li><li data-preset-tag="p"><p>Additional resources:<br> <a href="https://github.com/Emotiv/labstreaminglayer" target="_blank">Code</a> to run LSL using Emotiv’s devices, with example scripts<br> Useful <a href="https://www.youtube.com/watch?v=Y1at7yrcFW0&amp;list=PLVnr33MP5RMRhGwY36zHHDOmAaYTB138D" target="_blank">LSL demo on YouTube</a><br> <a href="https://github.com/sccn/labstreaminglayer" target="_blank">SCCN LSL GitHub repository</a> for all associated libraries<br> <a href="https://github.com/labstreaminglayer" target="_blank">LSL GitHub repository</a> for a collection a submodules and apps</p></li><li data-preset-tag="p"><p><a href="https://academic.oup.com/scan/article/16/1-2/72/5919711?login=false" target="_blank">HyPyP analysis pipeline</a> for Hyperscanning studies</p></li></ol>
</code></pre

Welkom! In deze handleiding leren we hoe we Lab Streaming Layer (LSL) in Python kunnen gebruiken om Emotiv EEG-gegevens van meerdere apparaten te verzamelen en te synchroniseren. Hiervoor is een basiskennis van de programmeertaal Python vereist.

Wat u zult leren

  1. Wat Lab Streaming Layer (LSL) is en waarom onderzoekers het gebruiken

  2. Hoe u gesynchroniseerde gegevens van meerdere Emotiv EEG-apparaten kunt verzamelen

  3. Hoe u verzamelde gegevens kunt importeren en inspecteren

1.1 Wat is LSL en waar is het goed voor?

Lab streaming layer (LSL) is een open-source toolbox die kan worden gebruikt voor het verzenden, ontvangen en synchroniseren van neurale, fysiologische en gedragsmatige gegevensstromen van diverse sensorhardware. Steeds krachtigere, nauwkeurigere en mobielere hersen- en lichaamssensoren (zoals Emotiv EEG-systemen) brengen neurowetenschap buiten het lab naar de wereld van realtime gegevens. Waar hersenmetingen zoals EEG en MEG ooit beperkt waren tot onderzoekslaboratoria, stellen mobiele apparaten ons in staat om meerdere gegevensstromen te verzamelen in meer natuurlijke omgevingen, en van meerdere mensen tegelijk.

Een onderzoeker kan geïnteresseerd zijn in fysiologische synchroniciteit tussen twee mensen die naar dezelfde muziek luisteren. LSL kan ons helpen om gegevens van twee EEG-headsets afzonderlijk te verzamelen die ook gesynchroniseerd zijn met de presentatie van geluid.

Enkele voorbeelden van andere toepassingen voor LSL:

  1. Gebeurtenismarkeringen (event markers) van een experiment toevoegen aan lopende EEG-gegevens

  2. Gegevens uit meerdere bronnen in de tijd uitlijnen voor een enkele deelnemer (bijv. hartslag, EMG, EEG)

  3. Gegevens van meerdere deelnemers in de tijd uitlijnen (bijv. EEG Hyperscanning-onderzoeken)

1.2 Hoe werkt LSL?

Lab Streaming Layer is een protocol voor de realtime uitwisseling van tijdreeksgegevens tussen meerdere apparaten. LSL kan worden geïmplementeerd met behulp van open-source bibliotheken voor programmeertalen zoals Python, MATLAB, C++, Java and andere.

De kernfunctionaliteit draait om LSL-gegevensstromen:

1. Een acquisitie-apparaat/software verzamelt gegevens en creëert een gegevensstroom - Fysiologische gegevens kunnen naar LSL worden gestreamd vanaf EEG-registratieapparaten, eye-trackers, motion capture-systemen, hartslagmeters, enz., inclusief metadata (bemonsteringsfrequentie, datatype, kanaalinformatie, enz.) - Gebeurtenismarkeringen van experimenten (bijv. met PsychoPy) kunnen ook als een gegevensstroom worden verzonden met behulp van LSL

2. De gegevensstroom wordt op het netwerk gepubliceerd - Dit is hoe gegevens worden verzonden via LSL; de gegevensstroom wordt "uitgezonden" naar het netwerk - Gepubliceerde stromen zijn beschikbaar op het netwerk en vindbaar door andere LSL-ondersteunde apparaten op hetzelfde netwerk - LSL kent aan elk gegevenssegment of monster een tijdstempel toe op basis van een gemeenschappelijke klok (volgens het Network Time Protocol). - De stroom wordt monster-voor-monster (of segment-voor-segment) door een "outlet" geduwd

3. Verzamelapparaat/apparaten "abonneren" op gegevensstroom/stromen - Dit is hoe gegevens worden ontvangen met behulp van LSL - Verzamelapparaten op hetzelfde netwerk ontvangen gepubliceerde gegevensstromen via "inlets". - Elke inlet ontvangt de stroommonsters en metadata van slechts één outlet

4. Gegevens opslaan - Na het abonneren op een gegevensstroom kunt u deze opslaan in een variabele in uw favoriete programmeertaal, of de meegeleverde software LabRecorder van LSL gebruiken om deze op te slaan in een standaardformaat zoals .xdf.

2.0 Overzicht van de handleiding

In deze handleiding nemen we een voorbeeld van een experimentele opstelling en leiden we u door de nodige stappen en code om deze te implementeren met behulp van LSL in Python. We gebruiken Python om een geluid af te spelen terwijl we EEG-gegevens verzamelen van twee mensen die Emotiv-headsets dragen. We gebruiken twee computers die elk EmotivPRO draaien om de EEG-gegevens te verzamelen, en zenden elke stroom uit via een aparte LSL-outlet. We gebruiken een Python-bibliotheek om een audiobestand af te spelen en tegelijkertijd een trigger te verzenden telkens wanneer het bestand start.

STAPPEN:

1. Gebruik EmotivPRO om gegevens te streamen via LSL-outlets, inclusief EEG-gegevens (en/of beweging, contactkwaliteit, signaalkwaliteit, enz.) 2. Speel een audiotrack af met een Python-script en stuur tegelijkertijd een trigger via een andere LSL. Gebruik LabRecorder om alle drie de gegevensstromen vast te leggen en op te slaan via een LSL-inlet.

2.1 STAP 1 - Installatie en configuratie

  1. U hebt ondersteunde gegevensacquisitie-apparaten nodig om gegevens te verzamelen
    • Alle brainware-apparaten van Emotiv maken verbinding met LSL via de EmotivPRO-software

  2. Installeer EmotivPRO op uw apparaat/apparaten. U hebt een geldige EmotivPRO-licentie nodig om LSL te gebruiken.

  3. Installeer de Python LSL-bibliotheek met de volgende opdracht:
    pip install pylsl

  4. Download de LabRecorder-software. Dit is een eenvoudige, gratis app die kan worden uitgevoerd vanaf
    de opdrachtregel of met behulp van een zelfstandige download

  5. Voor ons experiment: Installeer de benodigde pakketten voor het afspelen van audio met Python
    pip install sounddevice soundfile

2.2 STAP 3 - Verzend de gegevens van EmotivPRO via een LSL-stroom

  1. Zoek de "..." in de rechterbovenhoek van de app, navigeer naar Instellingen

  2. Zoek de sectie 'Lab Streaming Layer' en de subsectie 'Outlet'

  3. Selecteer alle datatypes die u wilt uitzenden

  4. Selecteer het gegevensformaat (32-bits float of 64-bits double)

  5. Selecteer of u de gegevens monster-voor-monster of in segmenten van monsters wilt verzenden

  6. Klik op 'Start' om een LSL-gegevensstroom uit te zenden

2.3 STAP 4 - Gebruik een Python-script om audio af te spelen en triggers te verzenden

  1. Kopieer en plak het volgende codeblok in een Python-bestand en sla het op uw computer op.

  2. Zoek een audiobestand (bij voorkeur een .wav-bestand) dat u wilt afspelen en bewerk het script door de
    variabele audio_filepath te wijzigen in het bestandspad naar uw audiobestand op uw computer

  3. Open een opdrachtprompt om de opdrachtregel te gebruiken en navigeer naar de map waar
    uw Python-bestand is opgeslagen

  4. Voer in: python3 bestandsnaam.py
    • Afhankelijk van uw Python-installatie gebruikt u mogelijk python in plaats van python3

    Opmerking: Vervang /path/to/audio.wav door de locatie van het audiobestand dat u tijdens uw experiment wilt afspelen.

"""
LSL Example: Play audio and send a trigger marker
<p>This script creates an LSL marker stream, waits for the user to<br>press ENTER, then plays an audio file and sends a marker that<br>can be synchronized with EEG data collected through LabRecorder.<br>"""</p>
<p>import sounddevice as sd<br>import soundfile as sf<br>from pylsl import StreamInfo, StreamOutlet</p>
<p>def wait_for_keypress():<br>print("Press ENTER to start audio playback and send an LSL marker.")<br>while True:<br>if input() == "":<br>break</p>
<p>def play_audio_and_send_marker(audio_file, outlet):<br>data, fs = sf.read(audio_file)</p>
<pre><code>print("Playing audio and sending LSL marker...")

marker_val = [1]
outlet.push_sample(marker_val)

sd.play(data, fs)
sd.wait()

print("Audio playback finished.")
</code></pre>
<p>if <strong>name</strong> == "<strong>main</strong>":</p>
<pre><code>info = StreamInfo(
    name="AudioMarkers",
    type="Markers",
    channel_count=1,
    nominal_srate=0,
    channel_format="int32",
    source_id="uniqueMarkerID12345"
)

outlet = StreamOutlet(info)

while True:
    wait_for_keypress()

    audio_filepath = "/path/to/audio.wav"

    play_audio_and_send_marker(
        audio_filepath,
        outlet
    )</code></pre><h2 dir="auto">2.4 STEP 5 - Use LabRecorder to view and save all LSL streams</h2><ol dir="auto"><li data-preset-tag="p"><p>Open LabRecorder</p></li><li data-preset-tag="p"><p>Press <code>Update</code>. The available LSL streams should be visible in the stream list<br> You should be able to see streams from both EmotivPROs (usually called “Emotiv-<br>DataStream”) and the marker stream (called “AudioMarkers”)</p></li><li data-preset-tag="p"><p>Click <code>Browse</code> to select a location to store data (and set other parameters)</p></li><li data-preset-tag="p"><p>Select all streams and press <code>Record</code> to start recording</p></li></ol><h2 dir="auto">3.0 Working with the data</h2><p dir="auto">LabRecorder outputs an XDF file (Extensible Data Format) that contains data from all the streams. XDF files are structured into, streams, each with a different header that describes what it contains (device name, data type, sampling rate, channels, and more). You can use the below codeblock to open your XDF file and display some basic information.</p><p dir="auto"><strong>Note: Replace </strong><code><strong>/path/to/your/file.xdf</strong></code><strong> with the filepath for your LabRecorder XDF output file.</strong></p><pre data-language="JSX"><code>import pyxdf
</code></pre>
<p>import mne<br>import matplotlib.pyplot as plt<br>import numpy as np</p>
<h1>Give the path to your LSL output file here.</h1>
<p>data_path = "/path/to/your/file.xdf"</p>
<h1>Load the XDF file.</h1>
<p>streams, fileheader = pyxdf.load_xdf(data_path)</p>
<p>print("XDF File Header:", fileheader)<br>print("Number of streams found:", len(streams))</p>
<p>for i, stream in enumerate(streams):<br>print("\nStream", i + 1)<br>print("Stream Name:", stream["info"]["name"][0])<br>print("Stream Type:", stream["info"]["type"][0])<br>print("Number of Channels:", stream["info"]["channel_count"][0])</p>
<pre><code>sfreq = float(stream["info"]["nominal_srate"][0])
print("Sampling Rate:", sfreq)

print("Number of Samples:", len(stream["time_series"]))
print("First 5 data points:", stream["time_series"][:5])

channel_names = [
    chan["label"][0]
    for chan in stream["info"]["desc"][0]["channels"][0]["channel"]
]

print("Channel Names:", channel_names)

channel_types = "eeg"</code></pre><h3 dir="auto"><br></h3><h2 dir="auto">4.0 Additional Resources</h2><h4 dir="auto">Official Documentation</h4><ol dir="auto"><li data-preset-tag="p"><p>Check out the <a href="1. Check out the online documentation, including the official README file on GitHub 2. Additional resources: • Code to run LSL using Emotiv’s devices, with example scripts • Useful LSL demo on YouTube • SCCN LSL GitHub repository for all associated libraries • LSL GitHub repository for a collection a submodules and apps 3. HyPyP analysis pipeline for Hyperscanning studies" target="_blank">online documentation</a>, including the <a href="https://github.com/sccn/labstreaminglayer/" target="_blank">official README file on GitHub</a></p></li><li data-preset-tag="p"><p>Additional resources:<br> <a href="https://github.com/Emotiv/labstreaminglayer" target="_blank">Code</a> to run LSL using Emotiv’s devices, with example scripts<br> Useful <a href="https://www.youtube.com/watch?v=Y1at7yrcFW0&amp;list=PLVnr33MP5RMRhGwY36zHHDOmAaYTB138D" target="_blank">LSL demo on YouTube</a><br> <a href="https://github.com/sccn/labstreaminglayer" target="_blank">SCCN LSL GitHub repository</a> for all associated libraries<br> <a href="https://github.com/labstreaminglayer" target="_blank">LSL GitHub repository</a> for a collection a submodules and apps</p></li><li data-preset-tag="p"><p><a href="https://academic.oup.com/scan/article/16/1-2/72/5919711?login=false" target="_blank">HyPyP analysis pipeline</a> for Hyperscanning studies</p></li></ol>
</code></pre

Welkom! In deze handleiding leren we hoe we Lab Streaming Layer (LSL) in Python kunnen gebruiken om Emotiv EEG-gegevens van meerdere apparaten te verzamelen en te synchroniseren. Hiervoor is een basiskennis van de programmeertaal Python vereist.

Wat u zult leren

  1. Wat Lab Streaming Layer (LSL) is en waarom onderzoekers het gebruiken

  2. Hoe u gesynchroniseerde gegevens van meerdere Emotiv EEG-apparaten kunt verzamelen

  3. Hoe u verzamelde gegevens kunt importeren en inspecteren

1.1 Wat is LSL en waar is het goed voor?

Lab streaming layer (LSL) is een open-source toolbox die kan worden gebruikt voor het verzenden, ontvangen en synchroniseren van neurale, fysiologische en gedragsmatige gegevensstromen van diverse sensorhardware. Steeds krachtigere, nauwkeurigere en mobielere hersen- en lichaamssensoren (zoals Emotiv EEG-systemen) brengen neurowetenschap buiten het lab naar de wereld van realtime gegevens. Waar hersenmetingen zoals EEG en MEG ooit beperkt waren tot onderzoekslaboratoria, stellen mobiele apparaten ons in staat om meerdere gegevensstromen te verzamelen in meer natuurlijke omgevingen, en van meerdere mensen tegelijk.

Een onderzoeker kan geïnteresseerd zijn in fysiologische synchroniciteit tussen twee mensen die naar dezelfde muziek luisteren. LSL kan ons helpen om gegevens van twee EEG-headsets afzonderlijk te verzamelen die ook gesynchroniseerd zijn met de presentatie van geluid.

Enkele voorbeelden van andere toepassingen voor LSL:

  1. Gebeurtenismarkeringen (event markers) van een experiment toevoegen aan lopende EEG-gegevens

  2. Gegevens uit meerdere bronnen in de tijd uitlijnen voor een enkele deelnemer (bijv. hartslag, EMG, EEG)

  3. Gegevens van meerdere deelnemers in de tijd uitlijnen (bijv. EEG Hyperscanning-onderzoeken)

1.2 Hoe werkt LSL?

Lab Streaming Layer is een protocol voor de realtime uitwisseling van tijdreeksgegevens tussen meerdere apparaten. LSL kan worden geïmplementeerd met behulp van open-source bibliotheken voor programmeertalen zoals Python, MATLAB, C++, Java and andere.

De kernfunctionaliteit draait om LSL-gegevensstromen:

1. Een acquisitie-apparaat/software verzamelt gegevens en creëert een gegevensstroom - Fysiologische gegevens kunnen naar LSL worden gestreamd vanaf EEG-registratieapparaten, eye-trackers, motion capture-systemen, hartslagmeters, enz., inclusief metadata (bemonsteringsfrequentie, datatype, kanaalinformatie, enz.) - Gebeurtenismarkeringen van experimenten (bijv. met PsychoPy) kunnen ook als een gegevensstroom worden verzonden met behulp van LSL

2. De gegevensstroom wordt op het netwerk gepubliceerd - Dit is hoe gegevens worden verzonden via LSL; de gegevensstroom wordt "uitgezonden" naar het netwerk - Gepubliceerde stromen zijn beschikbaar op het netwerk en vindbaar door andere LSL-ondersteunde apparaten op hetzelfde netwerk - LSL kent aan elk gegevenssegment of monster een tijdstempel toe op basis van een gemeenschappelijke klok (volgens het Network Time Protocol). - De stroom wordt monster-voor-monster (of segment-voor-segment) door een "outlet" geduwd

3. Verzamelapparaat/apparaten "abonneren" op gegevensstroom/stromen - Dit is hoe gegevens worden ontvangen met behulp van LSL - Verzamelapparaten op hetzelfde netwerk ontvangen gepubliceerde gegevensstromen via "inlets". - Elke inlet ontvangt de stroommonsters en metadata van slechts één outlet

4. Gegevens opslaan - Na het abonneren op een gegevensstroom kunt u deze opslaan in een variabele in uw favoriete programmeertaal, of de meegeleverde software LabRecorder van LSL gebruiken om deze op te slaan in een standaardformaat zoals .xdf.

2.0 Overzicht van de handleiding

In deze handleiding nemen we een voorbeeld van een experimentele opstelling en leiden we u door de nodige stappen en code om deze te implementeren met behulp van LSL in Python. We gebruiken Python om een geluid af te spelen terwijl we EEG-gegevens verzamelen van twee mensen die Emotiv-headsets dragen. We gebruiken twee computers die elk EmotivPRO draaien om de EEG-gegevens te verzamelen, en zenden elke stroom uit via een aparte LSL-outlet. We gebruiken een Python-bibliotheek om een audiobestand af te spelen en tegelijkertijd een trigger te verzenden telkens wanneer het bestand start.

STAPPEN:

1. Gebruik EmotivPRO om gegevens te streamen via LSL-outlets, inclusief EEG-gegevens (en/of beweging, contactkwaliteit, signaalkwaliteit, enz.) 2. Speel een audiotrack af met een Python-script en stuur tegelijkertijd een trigger via een andere LSL. Gebruik LabRecorder om alle drie de gegevensstromen vast te leggen en op te slaan via een LSL-inlet.

2.1 STAP 1 - Installatie en configuratie

  1. U hebt ondersteunde gegevensacquisitie-apparaten nodig om gegevens te verzamelen
    • Alle brainware-apparaten van Emotiv maken verbinding met LSL via de EmotivPRO-software

  2. Installeer EmotivPRO op uw apparaat/apparaten. U hebt een geldige EmotivPRO-licentie nodig om LSL te gebruiken.

  3. Installeer de Python LSL-bibliotheek met de volgende opdracht:
    pip install pylsl

  4. Download de LabRecorder-software. Dit is een eenvoudige, gratis app die kan worden uitgevoerd vanaf
    de opdrachtregel of met behulp van een zelfstandige download

  5. Voor ons experiment: Installeer de benodigde pakketten voor het afspelen van audio met Python
    pip install sounddevice soundfile

2.2 STAP 3 - Verzend de gegevens van EmotivPRO via een LSL-stroom

  1. Zoek de "..." in de rechterbovenhoek van de app, navigeer naar Instellingen

  2. Zoek de sectie 'Lab Streaming Layer' en de subsectie 'Outlet'

  3. Selecteer alle datatypes die u wilt uitzenden

  4. Selecteer het gegevensformaat (32-bits float of 64-bits double)

  5. Selecteer of u de gegevens monster-voor-monster of in segmenten van monsters wilt verzenden

  6. Klik op 'Start' om een LSL-gegevensstroom uit te zenden

2.3 STAP 4 - Gebruik een Python-script om audio af te spelen en triggers te verzenden

  1. Kopieer en plak het volgende codeblok in een Python-bestand en sla het op uw computer op.

  2. Zoek een audiobestand (bij voorkeur een .wav-bestand) dat u wilt afspelen en bewerk het script door de
    variabele audio_filepath te wijzigen in het bestandspad naar uw audiobestand op uw computer

  3. Open een opdrachtprompt om de opdrachtregel te gebruiken en navigeer naar de map waar
    uw Python-bestand is opgeslagen

  4. Voer in: python3 bestandsnaam.py
    • Afhankelijk van uw Python-installatie gebruikt u mogelijk python in plaats van python3

    Opmerking: Vervang /path/to/audio.wav door de locatie van het audiobestand dat u tijdens uw experiment wilt afspelen.

"""
LSL Example: Play audio and send a trigger marker
<p>This script creates an LSL marker stream, waits for the user to<br>press ENTER, then plays an audio file and sends a marker that<br>can be synchronized with EEG data collected through LabRecorder.<br>"""</p>
<p>import sounddevice as sd<br>import soundfile as sf<br>from pylsl import StreamInfo, StreamOutlet</p>
<p>def wait_for_keypress():<br>print("Press ENTER to start audio playback and send an LSL marker.")<br>while True:<br>if input() == "":<br>break</p>
<p>def play_audio_and_send_marker(audio_file, outlet):<br>data, fs = sf.read(audio_file)</p>
<pre><code>print("Playing audio and sending LSL marker...")

marker_val = [1]
outlet.push_sample(marker_val)

sd.play(data, fs)
sd.wait()

print("Audio playback finished.")
</code></pre>
<p>if <strong>name</strong> == "<strong>main</strong>":</p>
<pre><code>info = StreamInfo(
    name="AudioMarkers",
    type="Markers",
    channel_count=1,
    nominal_srate=0,
    channel_format="int32",
    source_id="uniqueMarkerID12345"
)

outlet = StreamOutlet(info)

while True:
    wait_for_keypress()

    audio_filepath = "/path/to/audio.wav"

    play_audio_and_send_marker(
        audio_filepath,
        outlet
    )</code></pre><h2 dir="auto">2.4 STEP 5 - Use LabRecorder to view and save all LSL streams</h2><ol dir="auto"><li data-preset-tag="p"><p>Open LabRecorder</p></li><li data-preset-tag="p"><p>Press <code>Update</code>. The available LSL streams should be visible in the stream list<br> You should be able to see streams from both EmotivPROs (usually called “Emotiv-<br>DataStream”) and the marker stream (called “AudioMarkers”)</p></li><li data-preset-tag="p"><p>Click <code>Browse</code> to select a location to store data (and set other parameters)</p></li><li data-preset-tag="p"><p>Select all streams and press <code>Record</code> to start recording</p></li></ol><h2 dir="auto">3.0 Working with the data</h2><p dir="auto">LabRecorder outputs an XDF file (Extensible Data Format) that contains data from all the streams. XDF files are structured into, streams, each with a different header that describes what it contains (device name, data type, sampling rate, channels, and more). You can use the below codeblock to open your XDF file and display some basic information.</p><p dir="auto"><strong>Note: Replace </strong><code><strong>/path/to/your/file.xdf</strong></code><strong> with the filepath for your LabRecorder XDF output file.</strong></p><pre data-language="JSX"><code>import pyxdf
</code></pre>
<p>import mne<br>import matplotlib.pyplot as plt<br>import numpy as np</p>
<h1>Give the path to your LSL output file here.</h1>
<p>data_path = "/path/to/your/file.xdf"</p>
<h1>Load the XDF file.</h1>
<p>streams, fileheader = pyxdf.load_xdf(data_path)</p>
<p>print("XDF File Header:", fileheader)<br>print("Number of streams found:", len(streams))</p>
<p>for i, stream in enumerate(streams):<br>print("\nStream", i + 1)<br>print("Stream Name:", stream["info"]["name"][0])<br>print("Stream Type:", stream["info"]["type"][0])<br>print("Number of Channels:", stream["info"]["channel_count"][0])</p>
<pre><code>sfreq = float(stream["info"]["nominal_srate"][0])
print("Sampling Rate:", sfreq)

print("Number of Samples:", len(stream["time_series"]))
print("First 5 data points:", stream["time_series"][:5])

channel_names = [
    chan["label"][0]
    for chan in stream["info"]["desc"][0]["channels"][0]["channel"]
]

print("Channel Names:", channel_names)

channel_types = "eeg"</code></pre><h3 dir="auto"><br></h3><h2 dir="auto">4.0 Additional Resources</h2><h4 dir="auto">Official Documentation</h4><ol dir="auto"><li data-preset-tag="p"><p>Check out the <a href="1. Check out the online documentation, including the official README file on GitHub 2. Additional resources: • Code to run LSL using Emotiv’s devices, with example scripts • Useful LSL demo on YouTube • SCCN LSL GitHub repository for all associated libraries • LSL GitHub repository for a collection a submodules and apps 3. HyPyP analysis pipeline for Hyperscanning studies" target="_blank">online documentation</a>, including the <a href="https://github.com/sccn/labstreaminglayer/" target="_blank">official README file on GitHub</a></p></li><li data-preset-tag="p"><p>Additional resources:<br> <a href="https://github.com/Emotiv/labstreaminglayer" target="_blank">Code</a> to run LSL using Emotiv’s devices, with example scripts<br> Useful <a href="https://www.youtube.com/watch?v=Y1at7yrcFW0&amp;list=PLVnr33MP5RMRhGwY36zHHDOmAaYTB138D" target="_blank">LSL demo on YouTube</a><br> <a href="https://github.com/sccn/labstreaminglayer" target="_blank">SCCN LSL GitHub repository</a> for all associated libraries<br> <a href="https://github.com/labstreaminglayer" target="_blank">LSL GitHub repository</a> for a collection a submodules and apps</p></li><li data-preset-tag="p"><p><a href="https://academic.oup.com/scan/article/16/1-2/72/5919711?login=false" target="_blank">HyPyP analysis pipeline</a> for Hyperscanning studies</p></li></ol>
</code></pre

Basisprincipes van neurale oscillaties - EMOTIV

Lees verder

Basisprincipes van neurale oscillaties