-
Notifications
You must be signed in to change notification settings - Fork 2
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Standardize EEG Data Model for Streaming #1
Comments
There is a lot of redundancy with this model. The only things that should be in a sample are dynamic variables i.e.: {
"buffer": [ // List of samples
{
"timestamp": Date,
"data": [ // List of channels
float,
float,
float,
float
]
}
]
} Having to send these over the wire means we need to be lean as possible. I find the best results when i minimize the amount of redundant data between sample. I think a header or start byte define what the metrics are: {
"metric": String // E.g. EEG, ACCL, etc (optional)
"source": String // E.g. Muse, OpenBCI, etc (optional)
"sampleRate": Number // E.g. 250. always in hz (optional)
"mock": Boolean // E.g. false (optional),
"topology": [ 'Pz', 'Oz', 'Cz', 'C1']
} especially with hierarchal topics we can inject and split on these exact metrics. |
Hey guys. I'm in the mountains now. I will reply on Sunday with a more
detailed answer but in short my recommendation for the data model would be
to map it to the LSL model.
1. Send only one time the rich StreamInfo, serialized to JSON. This
contains sampling rate, channel positions, channel data format etc.
2. Open a stream and the only data that is sent is Steam samples serialized
to JSON. In LSL parlance it's : `{timestamp :..., data : [..., ...]}` For
efficiency concerns when transmitting over the network we can bundle the
samples in chunks and so the JSON transmitted is:
```
[
{timestamp :..., data : [..., ...]},
...,
{timestamp :..., data : [..., ...]}
]
```
Add the quotes to make it real json (I'm writing from my phone) but that's
the gist of it. I can add more details when I'm back.
I don't think we should send anything related to the stream info (like
electrode positions, sampling rate etc) with the stream samples. It's just
inefficient. The stream info should be query-able on demand.
…On Fri, Jun 16, 2017, 10:02 PM AJ Keller ***@***.***> wrote:
There is a lot of redundancy with this model. The only things that should
be in a sample are dynamic variables i.e.:
{
"buffer": [ // List of samples
{
"timestamp": Date,
"data": [ // List of channels
{
"id": String // E.g. FP1, FP2, F3, F4, C3, C4, etc (optional)
"value": Number
},
...
]
}
]
}
Having to send these over the wire means we need to be lean as possible. I
find the best results when i minimize the amount of redundant data between
sample.
I think a header or start byte define what the metrics are:
{
"metric": String // E.g. EEG, ACCL, etc (optional)
"source": String // E.g. Muse, OpenBCI, etc (optional)
"sampleRate": Number // E.g. 250. always in hz (optional)
"mock": Boolean // E.g. false (optional)
}
especially with hierarchal topics we can inject and split on these exact
metrics.
—
You are receiving this because you were mentioned.
Reply to this email directly, view it on GitHub
<#1 (comment)>,
or mute the thread
<https://github.com/notifications/unsubscribe-auth/ACX3uy72L3IFgrIY7iCi5pBEs81_H0mBks5sE13HgaJpZM4N9H41>
.
|
Basically what AJ says. Except the streaminfo (what he calls the headers) should respect the LSL convention (really, it's the XDF format they're using) |
Out of curiosity, why not using LSL ? There is no js implementation but I might be easier to make one rather than creating a new standard from scratch. |
Thanks everyone for the feedback! Sounds like we want to go leaner and use LSL. @alexandrebarachant can you point me to an LSL implementation in other languages? Maybe a Python implementation. Maybe we can port it to JavaScript to make the communication between server/client more efficient. Best, Alex |
Have anyone used this one? https://github.com/sccn/labstreaminglayer/tree/master/LSL |
That's the one. I'm using it extensively. Now, the typical usecase is streaming on a local network, so that is why I'm asking the question. |
I've extended LSL to work outside of a lab network. It's in a private repo
right now. I will try to release it next week.
…On Sat, Jun 17, 2017, 11:16 AM alexandre barachant ***@***.***> wrote:
That's the one. I'm using it extensively.
Now, the topical usecase is streaming on a local network, so that is why
I'm asking the question.
—
You are receiving this because you were mentioned.
Reply to this email directly, view it on GitHub
<#1 (comment)>,
or mute the thread
<https://github.com/notifications/unsubscribe-auth/ACX3u8GxU-9dakYi55EClqynikHfzZAVks5sFBfvgaJpZM4N9H41>
.
|
I went ahead and created a small node program to stream Muse 2016 data to LSL: https://github.com/urish/muse-lsl Basically, it leverages muse-js over noble (BLE bindings for Node.js) using bleat (emulates Web Bluetooth for muse-js), and then uses ffi to interface with liblsl. So now I got the data streaming to LSL (I can see it in their Lab Recorder program). Do you have any good pointers for LSL compatible software that I can use to visualize the EEG data, etc.? |
This is awesome, Uri! Could we separate the lsl part into its own lib that can accept an EEG Observable? And of course, let me know how I can help. |
How do I stream to LSL from OpenBCI shield? Arduino C/C++ compatible. |
thank Alex! Basically, the LSL wrapper sits in https://github.com/urish/muse-lsl/blob/master/lsl.js, so it can be quite easily separated. I don't have much experience with LSL though - I first heard about it today :) |
I also have a muse lsl repo : https://github.com/alexandrebarachant/muse-lsl
It's in Python.
There is a lsl viewer to plot live EEG signal.
There is also something to record P300 data.
More detail here :
http://alexandre.barachant.org/blog/2017/02/05/P300-with-muse.html
Le 18 juin 2017 00:53, "Uri Shaked" <[email protected]> a écrit :
… thank Alex!
Basically, the LSL wrapper sits in https://github.com/urish/muse-
lsl/blob/master/lsl.js, so it can be quite easily separated. I don't have
much experience with LSL though - I first heard about it today :)
—
You are receiving this because you were mentioned.
Reply to this email directly, view it on GitHub
<#1 (comment)>,
or mute the thread
<https://github.com/notifications/unsubscribe-auth/ACC9thhbny9hXW2ieMZ5uw49GF8qVMqRks5sFFjmgaJpZM4N9H41>
.
|
Thank @alexandrebarachant , going to try to feed my muse-lsl into the viewer in yours! What's the best way to communicate with you? Got some questions regarding how to analyze muse data, seems like you have some practical experience with this |
@urish you can contact me by email. I'm also hanging around in the NeurotechX slack |
cool, I just joined it! Ping you there |
hey everyone, I'm just now catching up. I'm in Cape Town, which is GMT+2. I'm flying tomorrow evening and landing Tuesday afternoon. I will also poke my head into the slack. So far, I like what I am seeing :) |
Quick update: node js implementation of muse-lsl can now stream values successfully, tested with lsl-viewer. Thanks for @alexandrebarachant a few bugs were fixed :-) |
Hi everyone, This is the data structure of the cloudbrain pub/sub lib. It extends LSL beyond the lab network but is still using the LSL data structure for ease of use in other applications. LSL refresherIn the LSL model, you have 3 main objects:
I the following section, I explain the data model that we have been using in Cloudbrain to extend LSL beyond the lab network. It's basically the same as LSL, except that we serialize objects to JSON so that we can have a uniform data contract between distributed applications. Data modelYou have two main objects that are being passed:
These 2 objects ( Samples
You can send and receive chunks of samples. In this case:
StreamInfoIn LSL,
Examples
{
"chunk": [
{ "data":[ 7.056745022195285, 4.754953953750924], "timestamp": 1497479774194733.0},
{ "data":[ 7.056745022195285, 4.754953953750924], "timestamp": 1497479774194733.0},
{ "data":[ 7.056745022195285, 4.754953953750924], "timestamp": 1497479774194733.0},
{ "data":[ 7.056745022195285, 4.754953953750924], "timestamp": 1497479774194733.0},
{ "data":[ 7.056745022195285, 4.754953953750924], "timestamp": 1497479774194733.0}
]
}
{
"info": {
"name": "muse",
"type": "EEG",
"channel_count": 8,
"nominal_srate": 0,
"channel_format": "float32",
"source_id": "some_id",
"version": "1.1",
"created_at": "0",
"uid": null,
"session_id": null,
"hostname": null,
"v4address": null,
"v4data_port": 0,
"v4service_port": 0,
"v6address": null,
"v6data_port": 0,
"v6service_port": 0,
"desc": {
"channels": {
"channel": [
{
"label": "FP1",
"unit": "millivolts",
"type": "undefined"
},
{
"label": "FP1",
"unit": "millivolts",
"type": "undefined"
},
{
"label": "FP1",
"unit": "millivolts",
"type": "undefined"
},
{
"label": "FP1",
"unit": "millivolts",
"type": "undefined"
},
{
"label": "FP1",
"unit": "millivolts",
"type": "undefined"
},
{
"label": "FP1",
"unit": "millivolts",
"type": "undefined"
},
{
"label": "FP1",
"unit": "millivolts",
"type": "undefined"
},
{
"label": "FP1",
"unit": "millivolts",
"type": "undefined"
}
]
},
"cap": {
"name": "undefined",
"size": "undefined",
"labelscheme": "undefined"
},
"manufacturer": "Interaxon"
}
}
} |
@marionleborgne @urish What do you think? We could update our work to use this data format. Thanks, everyone. |
@alexcastillo glad you like it. @aj-ptw is also using this data contract when pushing samples to cloudbrain from his wifi shield. |
@alexcastillo looking forward to the charts! 👍 |
Thank you so much @marionleborgne ! I just updated muse-js to emit the sample data in this format, and muse-lsl + angular-muse to consume it. @alexcastillo - also looking forward to the charts :) |
How am I supposed to stream from Arduino to LSL? Any ideas here? |
@aj-ptw : your best chance is to ask LSL people directly. there is a C implementation, but i have no idea if you can compile it in a Arduino library. |
@aj-ptw another option, since we are in the process of adding cloudbrain connectivity to the wifi shield, is to publish data over MQTT to cloudbrain and then just start the cloudbrain module that publishes data to LSL. |
Haha, first thing that comes up when googling this question :p sccn/labstreaminglayer#52 @aj-ptw beats me to it |
@alexcastillo @alexandrebarachant @urish @teonbrooks Question from @aj-ptw and I: anyone has an objections to sending See OpenBCI/OpenBCI_WIFI#13 (comment) for background. |
That's ok with me. Any chance we can add that detail to the StreamInfo?
…On Wed, Jun 21, 2017 at 4:32 PM Marion Le Borgne ***@***.***> wrote:
@alexcastillo <https://github.com/alexcastillo> @alexandrebarachant
<https://github.com/alexandrebarachant> @urish <https://github.com/urish>
@teonbrooks <https://github.com/teonbrooks>
Question from @aj-ptw <https://github.com/aj-ptw> and I: anyone has an
objections to sending voltage values as nano volts. The channels format
will be int.
See OpenBCI/OpenBCI_WIFI#13 (comment)
<OpenBCI/OpenBCI_WIFI#13 (comment)>
for background.
—
You are receiving this because you were mentioned.
Reply to this email directly, view it on GitHub
<#1 (comment)>,
or mute the thread
<https://github.com/notifications/unsubscribe-auth/ABIH4mNcXmtVGmGIliMtHvgzbiGzQ8yvks5sGaf1gaJpZM4N9H41>
.
|
Actually, it's already in the stream info ("desc" property). See JSON
example.
… |
Perfect.
…On Wed, Jun 21, 2017 at 7:00 PM Marion Le Borgne ***@***.***> wrote:
Actually, it's already in the stream info ("desc" property). See JSON
example.
>
—
You are receiving this because you were mentioned.
Reply to this email directly, view it on GitHub
<#1 (comment)>,
or mute the thread
<https://github.com/notifications/unsubscribe-auth/ABIH4mCppcCwDdjTJ42LEsRV0tb2A0Soks5sGcqqgaJpZM4N9H41>
.
|
@urish i just looked at your muse-lsl repo. It's awesome! Thanks 👍 |
@urish it occurred to me that you could actually abstract / pull out the LSL part out of the muse-lsl repo and this would be a generic LSL lib for JS - doesn't have to be tied to muse. For example, OpenEXP (@teonbrooks ) can use it publish event markers to LSL. His app is in JS. You just created the missing JS LSL lib 😄 |
That's exactly what I told him :)
…On Thu, Jun 22, 2017 at 5:15 PM Marion Le Borgne ***@***.***> wrote:
@urish <https://github.com/urish> it occurred to me that you could
actually abstract / pull out the LSL part out of the muse-lsl repo and this
would be a generic LSL lib for JS - doesn't have to be tied to muse. For
example, OpenEXP ***@***.*** <https://github.com/teonbrooks> ) can use
it publish event markers to LSL. His app in is JS.
You just created the missing JS LSL lib 😄
—
You are receiving this because you were mentioned.
Reply to this email directly, view it on GitHub
<#1 (comment)>,
or mute the thread
<https://github.com/notifications/unsubscribe-auth/ABIH4qJ8Iydwkx0zBEMnfzC-vXzbsfJdks5sGwOpgaJpZM4N9H41>
.
|
here we go: https://www.npmjs.com/package/node-lsl |
This is great @urish. Thanks! |
Hi everyone,
I've created this repo with the purpose of discussing a data model standard for streaming EEG.
Please review the README.md file and feel free to submit PRs.
cc @aj-ptw @marionleborgne @urish @teonbrooks @andrewheusser
Best,
Alex
The text was updated successfully, but these errors were encountered: