Logging brainwave data with ShadajL's NeuroSky MindWave Scala library

Yesterday I shared a simple first example of using ShadajL’s NeuroSky MindWave Scala library. Today I’m taking that a little further to share some code for a simple brainwave data recorder.

The premise is this: You put on a MindWave headset, start the recorder, and then do whatever you want to do -- work, meditate, sleep, whatever -- and the recorder records your brainwaves while you do those things. It writes the data in a CSV format so you can graph it, or do anything else you want with it.

Here’s the source code:

package com.alvinalexander.neurosky

import me.shadaj.neuro.thinkgear._
import java.io.{File, PrintWriter}
import scala.concurrent.duration._
import scala.util.{Try, Success, Failure}

object BrainWaveRecorder extends App {

  val recorder = new NeuroRecorder

  recorder.start()
  Thread.sleep((1 minute).toMillis)

  recorder.stop  // yeah, yeah, i know ...
  println("*** STOPPED ***")

}

class NeuroRecorder extends Thread {

  import java.text.SimpleDateFormat
  import java.util.Calendar
  val timeFormat = new SimpleDateFormat("hh:mm")

  private lazy val neuroIterator: NeuroIterator = {
    Try(new NeuroIterator) match {
      case Success(v) => v
      case Failure(e) =>
        println("Please check that ThinkGearConnector is on.")
        neuroIterator
    }
  }

  override def run {
    //val printWriter = new PrintWriter(new File("/Users/Al/Projects/Scala/NeuroSky/brainwaves.txt" ))
    var lastMinute = "xx:xx"
    while (true) {
      val recording = neuroIterator.next
      // data looks like this: EEG(ESense(35,40),EEGPower(595473,17991,4579,4579,1673,2541,1370,1370),PoorSignalLevel(0))
      recording match {
        case EEG(ESense(attention, meditation), 
                 EEGPower(delta, theta, lowAlpha, highAlpha, lowBeta, highBeta, lowGamma, highGamma), 
                 PoorSignalLevel(signalLevel)) => {
                   println(s"$signalLevel, $attention, $meditation, $delta, $theta, $lowAlpha, $highAlpha, $lowBeta, $highBeta, $lowGamma, $highGamma")
                   //printWriter.write(s"$signalLevel, $attention, $meditation, $delta, $theta, $lowAlpha, $highAlpha, $lowBeta, $highBeta, $lowGamma, $highGamma\n")
                 }
        case Blink(power) => println(s"Blink($power)")
        case other => // ignore (get a lot of RawData(value)) readings here
      }
      if (currentMinute != lastMinute) {
        println(s"MINUTE: $currentMinute")
        lastMinute = currentMinute
      }
    }
    neuroIterator.neuroSocket.close()
    //printWriter.close
  }

  def currentMinute = timeFormat.format(Calendar.getInstance.getTime)

}

The big difference in the code compared to yesterday’s example is the use of the match expression in the thread. Here’s a brief description of the code:

  • Action starts in the BrainWaveRecorder.
  • Most of the meat is in the run method of the NeuroRecorder.
  • I commented-out the PrintWriter code, and so far I’ve just run my tests in Eclipse. (More on this shortly.)
  • The run method gets a new recording every second.
  • The match expression attempts to match the data it receives.
  • A normal/desired record looks like the EEG case. When one of these records is received, it’s printed. If you know the ThinkGear API, the variable names in the println statement are familiar.
  • The match expression can also handle a Blink (a recording of an eye blink). In my experiments, whenever I wanted to note an event in the log file, I’d blink once or twice. For instance, I sneezed one time during a recording, so I blinked twice after that as a reminder to myself of what had happened.
  • After the match expression, I check to see if the minute/hour has changed. If so, I print it.

Problems with the MindWave headset

The reason I haven’t implemented the PrintWriter code is that I started having problems with the MindWave headset. It seems to work okay for roughly 5-15 minutes, then it stops working properly. I can tell this because when it is working, I can move the Attention and Meditation dials on the Brainwave Visualizer app that comes with the headset very easily. When it stops working, the output values have nothing to do with what I’m doing at the moment.

I don’t know why the headset quits working, but I suspect that it’s because maybe my forehead gets a little oily and the contact quits working, or because the headset doesn’t fit very well, and the contact loses pressure. When it quits working, I take the headset off, wipe off my forehead and the contact, then put it back on and adjust the arm, and it begins to work again for a little while.

So, that problem has really foiled my plans. I was hoping to record my brainwaves for an extended meditation session, or even while sleeping at night. But with this problem, the sleep recording is totally out of the picture.

I was going to wrap a little GUI around this code using my newfound love for Scala Swing (like this Scala Swing browser), but until I can get the headset working constantly/consistently, there’s no point in that. Frankly, it’s distracting and annoying when you’re meditating and wondering if the recorder is working.

The code

Getting back to the code, the code I’ve written uses @ShadajL’s neuro-thinkgear library, and the match expression is based on code I found in his mind-snakey application. Here are relevant links for everything:

Next up, I’ll be graphing my brain waves. The first steps of how I’ll do that are shown in my JFreeChart Scala Swing article.