cah6/EEG

EEG code

amtah opened this issue · 2 comments

In the EEG code for sampling with a sound card I found that i was unable to actually run the program as a section seems to be missing components. I am new to coding overall and everything that I have tried has so far failed.

image

If some one could help me correct the issue in the code above that would be great and really appreciated.

I had to rewrite a couple of lines like NUM_CHANNELS isn't defined and the array myArray is one dimensional not 2 so I removed the myArray[i][j] and made it myArray[j] any mention of it. added AudioIN in to actualy get the microphone input. Removed timeSignal( and a couple of others here is my revised code
/* Reading and Visualizing EEG Data

  • by Christian Henry.
  • Reads in EEG data through the microphone input of the
  • computer, then displays the signal in time, its frequency
  • components, and then averages of frequencies that estimate
  • the concentration of different brain waves.
    *
  • For reference, the frequency bars are ordered/classified as
  • follows:
    *
  • 1 - blue -------- delta
  • 2 - blue/purple - theta
  • 3 - purple ------ alpha
  • 4 - purple/red -- low beta
  • 5 - dark red ---- mid beta
  • 6 - red --------- high beta
  • This sketch will measure all brain waves, from 0 - 30 Hz. It does
  • best, however, measuring alpha waves across the occipital lobe.
  • To view this function, play the program, click the window to
  • make sure its in "focus", and hit the "a" key to bandpass the alpha
  • waves only. The alpha wave bar is the 3rd one (purple), and should
  • increase in height by 2-3x when you close your eyes and relax
  • (you'll see it for a second or two after you open your eyes, before it
  • averages back down).
  • /
    /* One issue: when taking the FFT of the data, it seems as if
    the frequency bands have a bandwidth of 1.33 instead of 1, as
    60Hz noise peaks out at band 45. This is worked around by using
    the scaleFreq parameter, which is used frequently. /
    import processing.serial.
    ;
    import ddf.minim.;
    import ddf.minim.signals.
    ;
    import ddf.minim.analysis.;
    import ddf.minim.effects.
    ;

//Important constants that may need to be changed.
float timeScale = 50; //scales the amplitude of time-domain data, can be changed
static float normalScale = 50;
static float alphaScale = 100;
static float timeLength = 60;
static int freqAvgScale = 50; //does same for averages of frequency data
static int alphaCenter = 12;
static int alphaBandwidth = 2; //really bandwidth divided by 2
static int betaCenter = 24;
static int betaBandwidth = 2;
static int NUM_CHANNELS = 1;

//Variables used to store data functions/effects.
Minim minim;
Serial myPort;
AudioInput in;
float[] timeSignal = new float[240];
FFT fft;
NotchFilter notch;
LowPassSP lpSP;
LowPassFS lpFS;
BandPass betaFilter;
BandPass alphaFilter;

//Constants mainly used for scaling the data to readable sizes.
int windowLength = 840;
int windowHeight = 500;
int FFTheight;
float scaling[] = {.00202,.002449/2,.0075502/2,.00589,.008864,.01777};
int FFTrectWidth = 6;
float scaleFreq = 1.33f;
float timeDomainAverage = 0;

//Variables used to handle bad data
int cutoffHeight = 200; //frequency height to throw out "bad data" for averaging after
float absoluteCutoff = 1.5;
boolean absoluteBadDataFlag; //data that is bad because it's way too far out of our desired range --
// ex: shaking your head for a second
boolean averageBadDataFlag; //data that's bad because it spikes too far outside of the average for
//that second --
// ex: blinking your eyes for a split second

//Constants used to create a running average of the data.
float[][] averages;
int averageLength = 200; //averages about the last 5 seconds worth of data
int averageBins = 6; //we have 6 types of brain waves
int counter = 0;

void setup()
{
//initialize array of averages for running average calculation
averages = new float[averageBins][averageLength];
for (int i = 0; i < averageBins; i++){
for (int j = 0; j < averageLength; j++){
averages[i][j] = 0;
}
}

//set some drawing parameters
windowLength = 840;
windowHeight = 500;
FFTheight = windowHeight - 200;

size(windowLength, windowHeight, P2D);

//initialize minim, as well as some filters
minim = new Minim(this);
minim.debugOn();
notch = new NotchFilter(60, 10, 32768);
lpSP = new LowPassSP(40, 32768);
lpFS = new LowPassFS(60, 32768);
betaFilter = new BandPass(betaCenter/scaleFreq,betaBandwidth/scaleFreq,32768);
alphaFilter = new BandPass(alphaCenter/scaleFreq,alphaBandwidth/scaleFreq,32768);

// initialize values in array that will be used for input
for (int i = 0; i < 240; i++){
timeSignal[i] = 0;
}

//initialize FFT
fft = new FFT(256, 256);
fft.window(FFT.HAMMING);
rectMode(CORNERS);
println(fft.getBandWidth());
}

void draw()
{
/*badDataFlag handles any "artifacts" we may pick up while recording the data.
Artifacts are essentially imperfections in the data recording -- they can come
from muscle movements, blinking, anything that disturbs the electrodes. If the
program encounters a set of data that spikes out of a reasonable window
(controlled by the variable cutoffHeight), it won't consider that data
when computing the running average.
*/
absoluteBadDataFlag = false;
averageBadDataFlag = false;

background(0); //make sure the background color is black
stroke(255); //and that time data is drawn in white

line(0,100,windowLength,100); //line separating time and frequency data

drawSignalData();

//check for spikes relative to other data
for (int i = 0; i < windowLength - 1; i++){
if (abs(in.left.get((i+1)_round(in.bufferSize()/windowLength))) > timeDomainAverage_4)
averageBadDataFlag = true;
}

displayText();

displayFreqAverages();

counter++;
}

void keyPressed(){
if (key == 'w'){
fft.window(FFT.HAMMING);
}
if (key == 'e'){
fft.window(FFT.NONE);
}
}

void serialEvent(Serial p){
while (p.available() > 0){
shiftNtimes(timeSignal, 1);

}
}

//Shifts all elements in myArray numShifts times left, resulting in the
//[0-numShift] elements being pushed off, and the last numShift elements
//becoming zero. Does this for all data channels.
public void shiftNtimes(float[] myArray, int numShifts){
int timesShifted = 0;
while (timesShifted < numShifts){
for (int j = 0; j < timeLength - 1; j++){
myArray[j] = myArray[j + 1];
}
myArray[(int)timeLength - 1] = 0;
timesShifted++;

}
}

//Draw the signal in time and frequency.
void drawSignalData(){
timeDomainAverage = 0;
for(int i = 0; i < windowLength - 1; i++)
{
stroke(255,255,255);
//data that fills our window is normalized to +-1, so we want to throw out
//sets that have data that exceed this by the factor absoluteCutoff
if (abs(in.left.get(i_round(in.bufferSize()/windowLength)))_timeScale/normalScale > .95){
absoluteBadDataFlag = true;
fill(250,250,250);
stroke(150,150,150);
}
//Draw the time domain signal.
line(i, 50 + in.left.get(i_round(in.bufferSize()/windowLength))_timeScale,
i+1, 50 + in.left.get((i+1)_round(in.bufferSize()/windowLength))_timeScale);

  timeDomainAverage += abs(in.left.get(i*round(in.bufferSize()/windowLength)));

  //Draw un-averaged frequency bands of signal.
  if (i < (windowLength - 1)/2){
    //set colors for each type of brain wave
      if (i <= round(3/scaleFreq)){             
        fill(0,0,250);        //delta
        stroke(25,0,225);
      }
      if (i >= round(4/scaleFreq) && i <= round((alphaCenter - alphaBandwidth)/scaleFreq)-1){
        fill(50,0,200);       //theta
        stroke(75,0,175);
      }
      if (i >= round((alphaCenter - alphaBandwidth)/scaleFreq) && 
      i <= round((alphaCenter + alphaBandwidth)/scaleFreq)){  
        fill(100,0,150);      //alpha
        stroke(125,0,125);
      }
      if (i >= round((alphaCenter + alphaBandwidth)/scaleFreq)+1 && 
      i <= round((betaCenter-betaBandwidth)/scaleFreq)-1){ 
        fill(150,0,100);      //low beta
        stroke(175,0,75);
      }
      if (i >= round((betaCenter - betaBandwidth)/scaleFreq) && 
      i <= round((betaCenter + betaBandwidth)/scaleFreq)){ 
        fill(200,0,50);       //midrange beta
        stroke(225,0,25);
      }
      if (i >= round((betaCenter + betaBandwidth)/scaleFreq)+1 && i <= round(30/scaleFreq)){ 
        fill(250,0,0);        //high beta
        stroke(255,0,10);
      }
      if (i >= round(32/scaleFreq)){
        fill(240,240,240);    //rest of stuff, mainly noise
        stroke(200,200,200);
      }
      if (i == round(60/scaleFreq)){
        fill(200,200,200);    //color 60 Hz a different tone of grey,
        stroke(150,150,150);  //to see how much noise is in data
      }
    //draw the actual frequency bars
    rect(FFTrectWidth*i, FFTheight, FFTrectWidth*(i+1), FFTheight - fft.getBand(i)/10);
  }
}

//divide the average by how many time points we have
timeDomainAverage = timeDomainAverage / (windowLength - 1);
}

//Give user textual information on data being thrown out and filters we have active.
void displayText(){
//show user when data is being thrown out
text("absoluteBadDataFlag = " + absoluteBadDataFlag, windowLength - 200, 120);
if (absoluteBadDataFlag == true)
{
println("absoluteBadDataFlag = " + absoluteBadDataFlag);
println(counter);
}
text("averageBadDataFlag = " + averageBadDataFlag, windowLength - 200, 140);
if (averageBadDataFlag == true)
{
println("averageBadDataFlag = " + averageBadDataFlag);
println(counter);
}

//and when a filter is being applied to the data
text("alpha filter is " + in.hasEffect(alphaFilter),
windowLength - 200, 160);
text("beta filter is " + in.hasEffect(betaFilter),
windowLength - 200, 180);
}

//Compute and display averages for each brain wave for the past ~5 seconds.
void displayFreqAverages(){
//show averages of alpha, beta, etc. waves
for (int i = 0; i < 6; i++){
float avg = 0; //raw data for amplitude of section of frequency
int lowFreq = 0;
int hiFreq = 0;

//Set custom frequency ranges to be averaged. 
if(i == 0){
  lowFreq = 0;
  hiFreq = 3;
  fill(0,0,250);
  stroke(25,0,225);
}
if(i == 1){
  lowFreq = 3;
  hiFreq = 7;
  fill(50,0,200);
  stroke(75,0,175);
}
if(i == 2){
  lowFreq = alphaCenter - alphaBandwidth;
  hiFreq = alphaCenter + alphaBandwidth;
  fill(100,0,150);
  stroke(125,0,125);
}
if(i == 3){
  lowFreq = 12;
  hiFreq = 15;
  fill(150,0,100);
  stroke(175,0,75);
}
if(i == 4){
  lowFreq = betaCenter - betaBandwidth;
  hiFreq = betaCenter + betaBandwidth;
  fill(200,0,50);
  stroke(225,0,25);
}
if(i == 5){
  lowFreq = 20;
  hiFreq = 30;
  fill(250,0,0);
  stroke(255,0,10);
}

//Convert frequencies we want to the actual FFT bands. Because of our
//FFT parameters, these happen to be equal (each band has a 1 Hz width).
int lowBound = fft.freqToIndex(lowFreq);
int hiBound = fft.freqToIndex(hiFreq);

//Scale the band number, because of the issue outlined at very beginning of
//program.
lowBound = round(lowBound/scaleFreq);
hiBound = round(hiBound/scaleFreq);

//get average for frequencies in range
for (int j = lowBound; j <= hiBound; j++){
  avg += fft.getBand(j);
  }
avg /= (hiBound - lowBound + 1);

// Scale the bars so that it fits our window a little better.
for (int k = 0; k < 6; k++)
{
  if (i == k)
  {
    avg *= scaling[i]*freqAvgScale;
  }
}

//update our array for the moving average (only if our data is "good")
if (absoluteBadDataFlag == false && averageBadDataFlag == false){
  averages[i][counter%averageLength] = avg;
}

//calculate the running average for each frequency range
float sum = 0;
for (int k = 0; k < averageLength; k++){
  sum += averages[i][k];
}
sum = sum / averageLength;

//draw averaged/smoothed frequency ranges
rect(i*width/6, height, (i+1)*width/6, height - sum);

}
}

// always close Minim audio classes when you are done with them
void stop()
{
in.close();
minim.stop();
super.stop();
}

x37v commented

hey @devnightmare github seemed to have mangled your code a bit and I can't seem to figure it all out, some characters have been changed into underscores and what not.

Would you mind simply pasting the code onto https://pastebin.com/ or emailing me the code?

THANKS!