CymatiCorp / CyKITv2

Python Data Controller for Neural EEG headsets. (Windows)
Other
46 stars 20 forks source link

Questions about CyKit2 + EPOC data stream #9

Closed teknomage closed 6 years ago

teknomage commented 6 years ago

Hi again Warren,

Got a couple of quick questions for ya, regarding CyKit's initialization as well as the accuracy of the data stream I'm seeing from EPOC. Please take your time to address these :

1) When I run the following command from a terminal in the CyKit python folder, I get a detailed list of the bluetooth/hardware devices available to me: python CyKITv2.py 127.0.0.1 55555 2 info+confirm The headset I have is one of the older EPOC developer models. And when I attempt to connect, the listings corresponding to my EPOC headset are usually the last 2 entries, listed as EPOC BCI and the last entry is simply identified as a string of 0s (see first attached screenshot). Your script seems to identify and accept only the last entry, if I attempt to type in anything else, it simply gives an error like Device not selected and then exits. I'm not sure if the selection is correct, how do I force the script to accept the EPOC BCI device/entry instead?

2) Just to test it out, I accepted the default selection and once the CyKit2 front-end comes alive, I see graphs of what seems to be data coming in from all 14 channels (plz see the 2nd screenshot). My simplest test is to blink my eyes to see if I get the corresponding artifacts from the AF sensors. However, they either come in delayed OR in some cases, I dont even see those artifacts on the graphs at all. Is there any other way for me to test if CyKit is receiving data correctly and from the correct device? Do you have a calibration routine I could probably use to test my device + CyKit2 as well??

With regards, Teknomage

warrenarea commented 6 years ago

1.

If you check the code of eeg.py around line 504 you will see a list of all of the entries recognized to be related to the USB dongles.

There are typically 2 USB entries, it is understood that only 1 of them contains any data. If I gathered them correctly, I believe I have listed in deviceList[] all of the USB entries that are actually being used for data.

You 'could' add EPOC BCI to that list.... but I believe it would yield no results for you.

  1. I am surmising you were able to get it to connect with the 0000000000 entry.

If you see data streaming in on the screen... that means you have connected successfully.

As far as the delay is concerned.... I have not experienced this. I am not sure what browser you are using. You might also try limiting it to displaying only that 1 or 2 sensors you are checking for blink data.

You will have to troubleshoot where the delay is coming from.... whether its from Python, or the web browser. I have had slightly better performance in Chrome.

It might be useful for me to add a feature to CyKIT, to have it send data from specific sockets... that could lend to 'speeding' up the software.

I do have a calibration routine I do to verify the integrity of the data.... most the time I just tap the headset, and the residual static electricity reacts enough that i can tell the latency of the data, and most the time it responds very quickly.

My more technical approach for data integrity..... is that I have hooked up a low-gauge speaker wire. the left channel i spliced in two wires, with needles attached to their end-points.... and then the right channel a single wire with a needle end-point. Then I attach the speaker to my computer.... the left channel to the 2 reference sensors, and the right channel to my data line i am testing. Sometimes I also just don't connect the reference sensors at all.... Then I use Audacity to play a .2 amplitude frequency of only a few Hertz... and this is able to show me a Sine wave in the data.... which tells us that the data was converted properly.

This is a sine wave i played into the Epoc+ but.... I also did the same test for the Epoc model, I was actually a bit skeptical the EPOC model would display properly, but surprisingly it was a perfect sine wave. I am not certain I tested 'every' single sensor, i probably should have... I suppose I could easily do that now, and verify its correct.

Note: Data is identical, but channels are mixed up... have fixed this in recent version.

warrenarea commented 6 years ago

another thing to check for, is the thread count.... if there are any 'extra' or additional threads running in the background, this can also drastically effect performance.... you might try listing all of the threads and I could take a look.

I have seen one user in the past was using some additional python software, which added more threads in the background.... issues like that, could have the potential to slow down CyKIT.

This is precisely why I do not allow that other USB device to connect, as it would create a secondary thread that has the potential to drastically reduce performance, and provides no data.

teknomage commented 6 years ago

Hey, thanks for that detailed reply, Warren! Yes, I did think of using my DAW + the soundcard for calibrating the headset but I wondered if soundcards would do justice to frequencies below the 15-20 Hz lower limit, which is why I initially thought I'd build a simple LFO just to test the headset. But from the looks of your screenshots, that's a pretty neat calibration wave! : ) So, I'm gonna give this a shot, will report back later today..

warrenarea commented 6 years ago

I would just be careful with the volume/voltage of the device. Keeping in mind that the headset is designed to be picking up 'micro voltages'

Part of the reason why I used such a fine gauge of wire to test with, and set all of my volume settings to the lowest settings possible, and even a very low amplitudes.

The amplitude .2 - .8 is i think how it is detecting quality as well... so might be keep that in mind while testing.

I would just be mindful about trying not to overload the device with too high of current from your sound card... as I said previously, these devices were meant to be handling micro voltages... why I tried to air on the side of caution when using this sort of setup.

teknomage commented 6 years ago

Sorry I took so long to respond, been out travelling over the past couple of weeks. I finally realized the problem I'm facing from my EPOC setup is that CyKit is streaming data even when the headset is OFF! As long as the bluetooth dongle is connected and is in use, CyKit shows data coming in, irrespective of whether my EPOC developer headset is on or not. That means the data that I've been seeing all this time has NOT been from the headset, which now explains why I dont see corresponding spikes when I tap the headset or when I blink my eyes! I'm almost certain that there's no other device or application using the same port# 55555, but how can I check and resolve this issue?

I'm attaching screenshots of this anomaly, any ideas how this could be happening?

Device selection: epoc - cykit2 device selection

EPOC + Cykit - normal streaming when headset is ON epoc dev - cykit2 stream

EPOC + Cykit - still streaming when headset is OFF epoc dev - cykit2 stream when switched off

And thanks for the cautionary advice about the Volume/voltage and you're absolutely right about that. In my case, whenever I'm testing EEG circuity, I apply the test signal (whether it's from a signal generator or a soundcard) across a simple voltage divider (built with a couple of 1 MOhm and 100 Ohm resistors), and tap out the scaled-down test signal in the micro-volt range, which is what I'd need for testing EEG devices. Learnt this little trick from the old OpenEEG project :) although their approach was more professional.

warrenarea commented 6 years ago

as far as i know, i haven't had any issue with data being buffered and 'repeated' in this fashion.

what might be helpful is knowing what command line flags you used.

another thing... why does the screenshot show one image as having slightly brighter colors? From what I am gathering the top one is from Chrome and the bottom image is from Firefox.

Another thing that might be helpful, is to see the list of threads running.... as I have seen other people have multiple threads running along-side that seemed to compromise CyKITs behavior.

One thing i'd like to note.... is that... the data seems like it will only 'dip' downward on its cartesian plane. This becomes very evident in the Epoc version. It doesn't mean the data is incorrect, but the way I am plotting it is not correct....

To get all the data on the same lines, I have to average out the data... which is why you will often see the plots start down low... and then "steps" up to their cartesian plane. In Xavier you can see this is also what is happening... as when you first initialize the device, you will see the data plot start down low and then smoothly ascends up on a bell curve.

The averaging out process, i call it "creating a baseline", where you are creating a baseline for that particular dataset.

That is one of the things I will be fixing next, basically i think you might only need to average out the first few seconds of the data. Currently as it stands, it is constantly creating a baseline for the data. So the 'peaks' of the datasets are being averaged into the baseline, which it shouldn't do.

Part of the reason why I set it to constantly be creating a baseline, is that at one point I think I found that the datas baseline tended to 'drift' which was probably because of the impedance changing. I think how Xavier probably got around this.... is it might be doing a more "gradual" averaging of the data.

Also, I plan to create a flag option to have Python do the baseline creation... which might be a bit faster than the Javascript method.

teknomage commented 6 years ago

Thanks for your response, Warren. The flags I used were the same as what I had mentioned in my very first post, i.e, python CyKITv2.py 127.0.0.1 55555 2 info+confirm

Both screenshots were taken from Chrome only, not sure why there would be a brightness variation.. I simply dump the screenshot to MsPaint and save it as PNG. Guess there might be a variation due to format conversion, am not sure.

Mmmm, what would be the best way to list out other possible multiple threads? If it's in python, I'm assuming I'd have to import the threading module . If you have any commands or code samples that you yourself use to check in on simultaneous threads, please do share. I mean, I could experiment on my own with the code but I really dont want to muck this up any further.

Aah, well the baseline drift is to be expected when it comes to reading real-time data from devices like these. But that doesnt worry me as much as the fact that either my device's bluetooth dongle or something else is sending bogus data to CyKit via port# 55555. I really need to solve this data issue first, more than anything else..

warrenarea commented 6 years ago

it will list the active threads in the command prompt. you can just paste that. it already imports the threading module, and prints it out by default.

In my next version, I've done a bit to improve the baseline setup. Something to expect, is that you will be able to calibrate and control the baseline yourself. After it detects data being streamed, it will automatically disable the averaging/baseline after a few seconds.

Although this works somewhat to fix the cartesian plotting, I believe I have to take it a step further with another feature.

I plan on creating a new feature... which will be used to take the newly created baseline, and then measure the "highest possible" peak of data coming from the device... then adding half of that peak to the value. which i'm thinking should put it on the proper vertical plane.

although i am wondering if i couldn't just do that manually without even finding the peak. for this, i've added a new section called "Calibration", to help users adjust the settings.

i also plan to add a tab to serve as a FAQ, and to help future researchers in understanding the data.

Emotiv calls their baseline creation a "high-pass filter", where they are filtering out the microvolt measurement of approximately 4201mV~ and then plots it to a cartesian plot.

warrenarea commented 6 years ago

when you say that you are receiving data through EEG when the device is turned off. Do you mean that you have clicked "Disconnect" and data is still being received? or is the headset itself, turned off?

Because on occasion i have run into a problem, where the disconnect feature didn't always act as intended... and data kept being displayed, for this I plan on creating a 'soft disconnect', which may remedy that.

my question is.... how long are you running CyKIT before you start receiving the bogus/duplicated data you shouldn't (when your device is off?)

teknomage commented 6 years ago

Sorry, what did you mean by "it" here, when you said:

"it will list the active threads in the command prompt."

Did you post a new command for me to try out or were you referring to the same CyKit command I pasted earlier? i.e., python CyKITv2.py 127.0.0.1 55555 2 info+confirm If so, then are there any other flags I could add that might help with troubleshooting this issue?

And to answer your other question:

when you say that you are receiving data through EEG when the device is turned off. Do you mean that you have clicked "Disconnect" and data is still being received? or is the headset itself, turned off?

Yes, I mean CyKit was still connected and receiving data even though I had physically switched OFF the headset, I had not clicked the Disconnect button.

I'll wait for your reply and give this a shot once again tomorrow, hopefully as soon as I can find some time. Thank you for taking the time to help me sort out this issue!

warrenarea commented 6 years ago
Active Threads = {
   <InputReportProcessingThread ::: Thread-1>
   <Thread ::: ioThread>
   <Thread ::: eegThread>
   <_MainThread ::: MainThread>
   <InputReportReaderThread ::: Thread-2>
}

it will list it when you run cykit.

teknomage commented 6 years ago

OK Warren, I know this comes months later but I figured out what was going wrong with my headset. It's not that the bluetooth dongle was spitting out bogus data after all.. the problem is that, for some reason there is delay between the data sent and the data displayed. It's possible that Cykit2 is displaying every single data point that comes in from my EPOC headset and obviously, from a graphical viewpoint, it looks like there is HUGE delay between a data event (such as tapping or shaking the headset) and when that event is finally displayed on the screen, sometimes MINUTES later!

I built a small Calibration circuit that uses a couple of voltage dividers that I can feed either from my soundcard or with ELF square waves from a 555 circuit. And since I designed it to take in stereo, I can test 4 separate EEG channels at the same time. I didnt take the virtual ground/reference into consideration (I'll add a terminal for that later). But for now, this is what it looks like when I hooked up the Calibration circuit to my EPOC 1.0 headset...

Headset ON, 5 secs of no signal cykit2 epoc trial3a chrome - 00 headset on 5 secs of no signal

20 seconds of Square wave Calibration signal - varied frequency (you can see the variations in pulse width below) cykit2 epoc trial3a chrome - 01 20 secs of square wave calibration signal

Last bit of the Calibration signal @ 5% resolution, then stopped square wave output for 10 secs cykit2 epoc trial3a chrome - 02 10 secs of calibration switched off

Final: Headset switched OFF after 10 secs of no Calibration signal cykit2 epoc trial3a chrome - 03 final headset switched off

What I'd like to point out here is that these are just snapshots of intermediate frames, the data kept scrolling over numerous frames between each step mentioned above, it sometimes took a minute for just 10-20 seconds worth of data (I should've timed it precisely). Anyways, what's evidently happening here is that ALL incoming data is being printed irrespective of the delay, in other words, the display is not exactly real-time for me. I noticed that reducing EEG Resolution only reduces the amplitude of the waves displayed. Dunno if anyone else has faced this same problem or is this unique to me because I'm a using a much older EPOC model?

Anyways, got a couple of questions:

1) Is there a way to decrease the number of points being displayed per frame, i.e., force CyKit2 to skip display of a few samples every second? If you could point me to the part of the CyKit code that needs to be edited, that'd be great.

2) And in skipping the display points, I hope that the data being recorded is NOT being skipped at all? Because recording the data is certainly more important to me. If it comes at the cost of the delay, then I'll just have to deal with it.

I'm close to solving this issue, so I'd appreciate any help. And thanks again Warren for putting together this fantastic project, thereby allowing us to gain full access to our EPOC raw data without having to signup for ridiculous subscriptions with Emotiv! You've done a great thing here, so take a bow! :)

warrenarea commented 6 years ago

well, i really should get everyone up to date, using my newer version... as there are improvements, but until i can finalize that, i will address your issues.

the EEG resolution, is used mainly so that the amplitude of the data can all fit on the screen, and just making a mess of the data.

it appears you are having some 'lag' issues with the data rendering... i think in my newer version, this might be dealt with more readily.... one thing you could try though, is going through the "while loops" of all the python scripts, and inserting time.sleep(0)

in python 2 i didn't have to do this, but i remembered this was a huge factor when porting to python 3, as it allowed the threads to do callbacks to other threads... allowing the scripting to breathe a little easier, and fixed all speed issues.

from the sound of it, it is likely just a threading issue that needs to be addressed.

CyKITv2 does not 'skip' rendering of data points, nor does it 'skip' in the recording of data points. so even if it appears 'slow' (which it shouldn't), everything should still be recorded, even if it takes more time.

you 'could' increase the rendering of the data points, by increasing a variable cy_x in the cyInterface.js however, i do not recommend this, because, you won't be solving the actual issue, and the data will still be equally laggy. pretty certain your issue, is a threading issue.

teknomage commented 6 years ago

Thanks for the pointers, Warren. So, I tested out my EPOC + CyKit2 on another laptop with a better config than the one I've been running Cykit on so far. The rendering is definitely faster and seems real-time on the 2nd laptop, but that's without recording enabled. The moment I click the Record button, the display slows down to a crawl and the same situation arises as before, i.e., there's a significant lag between the headset stream and the data displayed. It's understandable that the display rendering would naturally slow down as a result of logging incoming EEG data to the drive, so I guess this can't be entirely avoided after all. And I'd rather have the data logged accurately than worry about the display lag. Plz feel free to close this ticket permanently, and thanks again for your help with this issue!

warrenarea commented 6 years ago

well, i will look into the matter of recording+rendering,

i do think that if everything is working properly, there should be no lag at all though. the python 3 version (when i can finally release it...), i think deals with many lag issues, and i think it was even running faster/smoother than the Emotiv programs.

Once you know how fast it can be, then you realize that there is plenty of CPU left over for additional tasks, and that if it is programmed correctly, you should have no lag.

Python 3 is not any faster, but i think it 'does' handle threading slightly differently, i do highly recommend experimenting with "time.sleep" in the while loops... because it seemed like all of my lag issues disappeared.... at least in Python 3 it did.

I will have to look into the recording+rendering though, to be certain, and see what i can find.

If you haven't done so already, i highly recommend checking the Discord chat.

teknomage commented 6 years ago

OK, I'm using Python 2.7.9 though. I'll give the sleep mod a shot this weekend and let you know how it goes!