libMuse for iOS (5.4.0) receives EEG data intermittently


#1

I am using iOS SDK (libMuse 5.4.0) to receive data from Muse EEG headband. Some code is added to the listener receiveMuseDataPacket function (in [B]MuseStatsIos[/B] project) below and dump out the log information from the console window to a text file. From the text file, we found that the average sampling rate over 5 minutes data logging is less than 100. To further analyze the logged information, it is found that from time to time, this receiveMuseDataPacket method could not receive eeg data. Using 2 seconds as a threshold, there are more than 72 times that no data is received within 2 seconds in the receiveMuseDataPacket method.

We are trying to use Muse headband to do some BCI studies. For windows, it works fine. The sampling rate is around 220.

Would appreciate that you could point out any missing part of my code or advise a better way to investigate the EEG data. Thanks.

  • (void)receiveMuseDataPacket:(IXNMuseDataPacket *)packet
    muse:(IXNMuse *)muse {
    if (packet.packetType == IXNMuseDataPacketTypeAlphaAbsolute ||
    packet.packetType == IXNMuseDataPacketTypeEeg)
    {
    NSLog(@“EEG data:
    ”);
    [self log:@"%5.2f %5.2f %5.2f %5.2f",

[packet getEegChannelValue:IXNEegEEG1],
[packet getEegChannelValue:IXNEegEEG2],
[packet getEegChannelValue:IXNEegEEG3],
[packet getEegChannelValue:IXNEegEEG4]

];

if (bFirstData) {
[NSTimer scheduledTimerWithTimeInterval:300
target:self
selector:@selector(stopLogging)
userInfo:nil
repeats:NO];
}

dataCounter ++;
NSLog(@“The current data counter: %d
”, dataCounter);
}


.CSV file from iOS app example code
#2

Hi,

It is best not to use the logging functionality on iOS for EEG packet since they’re coming in at a much faster rate than the log can handle, which leads to the behaviour you saw. I recommend you to use the MuseFileWriter class provided in the API to write the EEG data into a muse file in an async fashion. Something like the code below.

After the file has been written out, you can use MusePlayer, which is a research tool available for download on the developer’s website to convert the muse file to other formats for viewing afterwards. In order to transfer the file from the iOS device to your laptop, you must modify the info.plist file to enable file sharing, then you can open iTunes and under Apps, select MuseStatsIo then you can see the file and can drag it onto your desktop. More info is presented on this SO thread.

@interface YOURCLASS ()
@property IXNMuseFileWriter * fileWriter;
// your other stuff...
@end

// Default constructor or your own constructor
- (instancetype) init {
        // create output file
        NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
        NSString* path = paths[0];
        path = [path stringByAppendingPathComponent:@"FileNameYouWant"];
        path = [path stringByAppendingPathExtension:@"muse"];
        self.fileWriter = [IXNMuseFileFactory museFileWriterWithPathString:path];

        // your other stuff ...
}

- (void)receiveMuseDataPacket:(IXNMuseDataPacket *)packet
                         muse:(IXNMuse *)muse {
    if (packet.packetType == IXNMuseDataPacketTypeEeg) {

        // You should have a MuseFileWriter in your class and use the MuseFileFactory to create it in init method
        // First param is just some int you use to distinguish data from different muse headband
        [self.fileWriter addDataPacket:5 packet:packet];
        
        // You can also create some counter for the packets receieved and only flush
        // writer buffer to file after certain THRESHOLD (e.g. 1000). You don't have
        // to do this but it's more efficient than dispatching on every packet.
        // However, remember to flush the rest of the buffer if you disconnect/done with
        // your experiment so the remaining data will be flushed before it reaches the count.
        // You can do this in the disconnect method by simply calling flush method on the writer again.
        // Alternatively, if all you're doing is writing out to a file, then dispatching the async on every
        // packet should work also without this buffer count.
        self.buffer_count++;
        
        if(self.buffer_count > 1000) {
            id oldWriter = self.fileWriter;

            // Use iOS's GCD to run thing asynchronously so it doesn't block your UI thread
            // Choose the appropriate queue and priority for your need. If you're using
            // EEG data to update a view for example, then use the main queue instead.
            dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_LOW, 0), ^{
                [oldWriter flush];
            });

            self.buffer_count = 0;
        }
        
    }
}


#3

Hi Jack,

Thanks for your response.
Yes, you are right. We should not use the log function to check it.
It has been verified that the sampling rate is correct.