We are about to switch to a new forum software. Until then we have removed the registration on this forum.
Hi there,
a bit of background.
I am currently trying to send data from an EEG that i have built being processed by processing. The example shown in the link shows how to send data with a mouseclick, is there any way to constantly send data from a particular part of the code? For me i would need to send the data from the frequency of the wave and the amplitude.
http://learning.codasign.com/index.php?title=Sending_and_Receiving_OSC_Data_Using_Processing
also when i go to place this code in the sketch that processes the EEG, there seem to be errors such as "EOF expected found..."
So what im asking is:
Where should i put the osc send within the rest of the code?
Any ideas on what i would have to send in order to get the frequency and amplitude of waveforms?
How do i send a constant stream of data?
CODE FOLLOWS:
/* 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 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 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;
//Variables used to store data functions/effects.
Minim minim;
AudioInput in;
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};
float offset[] = {0,0,0,0,0,0};
float amplify[] = {1,1,1,1,1,1};
float maximum[] = {0,0,0,0,0,0};
float scaledMaximum[] = {0,0,0,0,0,0};
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);
// get a line in from Minim, default bit depth is 16
in = minim.getLineIn(Minim.MONO, 8192*4);
in.addEffect(notch);
//initialize FFT
fft = new FFT(in.bufferSize(), in.bufferSize());
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;
fft.forward(in.mix); //compute FFT
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++;
}
//Calls function to zoom into average bars when you right click on the average bars.
//Scales depending on position of click.
void mousePressed(){
if (mouseButton == RIGHT && mouseY > FFTheight){
scaleAverage(floor(mouseX/(windowLength/averageBins)), windowHeight - mouseY);
}
}
//Zooms into average bars to show small fluctuations better. New range (from original) is
//from position clicked on to a maximum height such that the previously logged maximum fills 75% of the
//current bar.
void scaleAverage(int bin, float pos){
offset[bin] += pos/amplify[bin];
println(offset[bin]);
amplify[bin] *= 200/(1.33f*(scaledMaximum[bin] - pos));
println(amplify[bin]);
maximum[bin] = 0;
scaledMaximum[bin] = 0;
}
//Hitting number keys will reset that bin of averages, hitting "`" will wipe them all.
void keyPressed(){
if (key == '1' || key == '2' || key == '3' || key == '4' || key == '5' || key == '6'){
char data[] = {key};
String str1 = new String(data);
int keyNum = Integer.parseInt(str1);
keyNum -= 1; //shift down 1 since array is zero-indexed
offset[keyNum] = 0;
amplify[keyNum] *= 1;
maximum[keyNum] = 0;
scaledMaximum[keyNum] = 0;
}
if (key == '`'){
for (int i = 0; i < offset.length; i++){
offset[i] = 0;
amplify[i] = 1;
maximum[i] = 0;
scaledMaximum[i] = 0;
}
}
if (key == 'w'){
fft.window(FFT.HAMMING);
}
if (key == 'e'){
fft.window(FFT.NONE);
}
if (key == 'a'){
toggleEffect(alphaFilter);
}
if (key == 'b'){
toggleEffect(betaFilter);
}
}
//Toggle effects such as notch or lowpass filter, not being used at
//the moment, though.
void toggleEffect(AudioEffect effect){
if(in.hasEffect(effect)){
in.removeEffect(effect);
timeScale = normalScale;
}
else{
in.addEffect(effect);
timeScale = alphaScale;
}
}
//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 filter's 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
Answers
Please format your code. (select code and press the C button left to the image button).
Ok, a short answer, hope it helps: above setup import the libraries:
And declare those 2 objects:
In setup create them:
Then if you send in draw you will have a constant stream. I hope 60 fps is not to slow, else you have to make a Thread.
Then you need something like this:
The Typetag gives info of what is incoming. So ifs means integer, float string.
I hope this helps, i started to look into osc this evening cause i need it as well. Tomorrow i will know some more :)
I moved to the topic to a proper category. I reformatted the code, although it is a bit of mess because the highlighter is confused by block comments. I deleted a duplicate thread without answer. Avoid multiplying threads on the same topic.
To newcomers in this forum: read attentively these instructions