Introduction
Biophysics is an integral part of biology, even though it is not a standard part of the K-12 curriculum. That is why the Biophysical Society provides additional information and lesson plans. Teaching biophysics allows for a large number of demonstration experiments and laboratory work for students to complete in lessons.
We would like to present a simple approach to support teaching challenging curriculum dealing with neural tissue in hands-on experiments. Unlike electrocardiography (ECG) and electromyography (EMG) measurements, where voltages measured on the human body are in the order of millivolts, electroencephalography (EEG) is measured on the head and voltages are in the order of microvolts. This makes ECG and EMG measurements a much bigger challenge. Although the construction of an EEG amplifier is not impossible, it is challenging in a typical school environment. Therefore, experiments with a commercially available, but relatively cheap, EEG headset are described below.
EEG headset
The Neurosky MindWave Mobile headset was chosen because of the low price and Bluetooth capability. There are many instructions for interfacing with the headset, for example using Arduino. For our purposes, we used a personal computer. The headset can be paired with a computer over Bluetooth and a program called ThinkGear Connector allows other software to receive data from the headset. Of course, the measured data are not comparable to commercial medical EEG devices because only one differential electrode is used instead of the many used in medical devices. However, even this one measured curve is sufficient for demonstration in the classroom and for simple tasks that students can perform by themselves.
This particular headset have to be paired with the computer via BlueTooth (technically speaking, headset acts as a virtual serial port while data from the serial port can be handled very easily in software). We learned that if there is a problem, fresh pair of batteries efficiently solves the problem.
Software
For the lecture demonstrations and motivation purposes, MindWave Mobile Starter Kit bundled with the headset is absolutely sufficient. MindWave Mobile Core application shows not only the raw data stream in form of graph (right upper part of the picture) as well as Fast Fourier transformation (FFT) spectrum (color bars), which can be used to estimate the spectrum components of the EEG data.
Students can see how their brain activity affects the displayed values of attention and the shape of the measured EEG curve, for example, while they try to solve a mathematical problem. The program window can be presented to the classroom via a data projector and EEG curve changes representing changes in voltage, measured on the volunteer's head, can be easily seen.
Because there are more frequency components than one, left part of the appliaction window shows most prevalent EEG rythms. Bottom-right part shows calculated values of "Attenttion" and "Meditation". These values are calculated according to the FTT spectrum of the EEG data and are calculated on the headset microchip, the MindWave Mobile Core application gets them from the headset to display it on the screen.
For the junior college level, EEG data analysis can be done. For this exercise, raw data have to be obtained from the headset. There are several methods, for example, if the matlab software is available, matlab script can be used.
To further ease the data collection, we used small appliacation called ThinkGear Connector. This app runs as a background process on the computer and can direct headset data from the serial port to an open network socket. This network socket can be for example written in the Processing programming language, which is a PC counterpart of the Arduino programming language called Wiring. Processing is very easy programming language taught in a beginning high school or university computer science classes.
We have modified the Processing sketch by Yang, by adding the capability of saving the raw data to the text file. The final sketch (mindwave.pde) can be downloaded here. Data can be then visualised and analyzed in any spreadsheet editor (for example Microsfot Excel).
These data correspond to the measured electrical voltage on the head of the pupil, i.e., they are a record of the electrical activity of the brain. Even if the Fast Fourier transformation is not known to students, straightforward estimation of prevalent EEG rhythms can be made. The most significant minima (circled in the left subfigure) are approximately 100 to 200 milliseconds apart, which means that the most significant frequencies will roughly be in the 5 to 10 Hz range. This simple exercise can be done with a ruler and printed sheet of data and verified by computer calculations made by the teacher (right panel).
Lab handouts
Here you can download lab handouts and customize it for your needs. In the left panel, there is information about nerve tissue that students can fill out during a lecture. In the right panel, there is information about EEGs. Several EEG curves that students can analyze independently (normal EEG, deep sleep, and EEG during an epileptic seizure) can be downloaded here.
Conclusion
We believe that laboratory exercises like this are not beneficial only for future medical doctors, but for all students that study biology. Biophysical measurements, or laboratory exercises involving medical devices, with first-hand experience, are especially popular because the students can be direct participants. If these laboratory exercises strengthen students’ operational data processing skills, they are doubly useful. Although it may seem that these exercises are only usable at the college level, they can act as substantial motivational factors at the secondary school level. The cost of the EEG headset is within the means of most public schools.
Source code: File mindwave.pde
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 | // Sample sketch to illustrate MindWave support in Processing // for graphing import processing.serial.*; import java.util.Iterator; eegPort eeg; Serial serialPort; String portName; PFont font; String portNames[]; // for data saving output = createWriter("data.txt"); // Application state final int APP_SERIAL_SELECT = 1; final int APP_CONNECTING = 2; final int APP_CONNECTED = 3; int appState = APP_SERIAL_SELECT; int selected = -1; int width = 800, height = 600; void setup() { size(800, 600); // font = 'Arial'; // textFont(); portNames = Serial.list(); for (int i = 0; i < portNames.length; i++) { println(portNames[i]); } smooth(); } void draw() { switch (appState) { case APP_SERIAL_SELECT: drawSerialSelect(); break; case APP_CONNECTING: drawConnecting(); break; case APP_CONNECTED: drawConnected(); break; } } // Drawing when we're connected void drawConnected() { int lastEventInterval = millis() - eeg.lastEvent; background(255); if (mousePressed) { eeg.refresh(); } textAlign(LEFT); fill(0); text("Port: " + portName, 5, 20); text("Dongle state: " + eeg.portDongleState, 5, 40); text("Poor signal: " + eeg.poorSignal, 5, 60); text("Attention: " + eeg.attention, 5, 80); text("Meditation: " + eeg.meditation, 5, 100); text("Last event: " + lastEventInterval + " ms ago", 5, 120); text("Raw buffer size: " + eeg.rawDataBuffer.size(), 5, 140); text("Raw data sequence: " + eeg.rawSequence, 5, 160); text("Vector sequence: " + eeg.vectorSequence, 5, 180); text("Vector buffer size: " + eeg.vectorBuffer.size(), 5, 200); text("Serial read state: " + eeg.portReadState, 5, 220); text("Failed checksum count: " + eeg.failedChecksumCount, 5, 240); text("Click mouse for a second to reset", 5, 260); // Draw signal noStroke(); if (eeg.poorSignal < 50 && lastEventInterval < 500) { // good signal fill(0, 255, 0); ellipse(150, 320, 100, 100); } else { // bad signal fill(255, 0, 0); ellipse(150, 320, 100, 100); } textAlign(CENTER); fill(0); text("Attention", 400, 20); text("Meditation", 600, 20); if (eeg.lastAttention > 0) { text(millis() - eeg.lastAttention + " ms old", 400, 180); } if (eeg.lastMeditation > 0) { text(millis() - eeg.lastMeditation + " ms old", 600, 180); } // Draw attention noFill(); stroke(0); ellipse(400, 90, 127, 127); fill(204, 102, 0); noStroke(); ellipse(400, 90, eeg.attention, eeg.attention); // Draw meditation noFill(); stroke(0); ellipse(600, 90, 127, 127); fill(108, 102, 240); noStroke(); ellipse(600, 90, eeg.meditation, eeg.meditation); // Draw signal // Chart vector values // first get maximum value int maxValue = 0; Iterator<eegPort.vectorObs> iterator; iterator = eeg.vectorBuffer.iterator(); int vectorCount = eeg.vectorBuffer.size(); int skip = 0; if (vectorCount > 200) { skip = vectorCount - 200; } int i = -1; while (iterator.hasNext()) { eegPort.vectorObs vobs = iterator.next(); if (++i < skip) { continue; } if (vobs.vectorValue > maxValue) { maxValue = vobs.vectorValue; } } iterator = eeg.vectorBuffer.iterator(); // we are interested in the last 400 observations i = -1; int j = 0; int prevValue = 0; int x = 0, y = 0; int prevX = 0, prevY = 0; stroke(0); // we are drawing between 0 and 800 in width, and between 400 and 600 in height while (iterator.hasNext()) { eegPort.vectorObs vobs = iterator.next(); if (++i < skip) { continue; } x = j*4; y = (int)(580 - 200.0*vobs.vectorValue/maxValue); if (j > 0) { line(prevX, prevY, x, y); } prevValue = vobs.vectorValue; prevX = x; prevY = y; j++; } // save last value to file output.println(vobs.vectorValue); // chart attention int attentionCount = eeg.attentionBuffer.size(); skip = 0; if (attentionCount > 200) { skip = attentionCount - 200; } Iterator<Integer> attentionIterator = eeg.attentionBuffer.iterator(); // we are interested in the last 200 observations i = -1; j = 0; prevValue = 0; x = 0; y = 0; prevX = 0; prevY = 0; stroke(204, 102, 0); // we are drawing between 0 and 800 in width, and between 400 and 600 in height while (attentionIterator.hasNext()) { int attention = attentionIterator.next(); if (++i < skip) { continue; } x = j*4; y = (int)(580 - 200.0*attention/255); if (j > 0) { line(prevX, prevY, x, y); } prevValue = attention; prevX = x; prevY = y; j++; } // chart meditation int meditationCount = eeg.meditationBuffer.size(); skip = 0; if (meditationCount > 200) { skip = meditationCount - 200; } Iterator<Integer> meditationIterator = eeg.meditationBuffer.iterator(); // we are interested in the last 200 observations i = -1; j = 0; prevValue = 0; x = 0; y = 0; prevX = 0; prevY = 0; stroke(108, 102, 240); // we are drawing between 0 and 800 in width, and between 400 and 600 in height while (meditationIterator.hasNext()) { int meditation = meditationIterator.next(); if (++i < skip) { continue; } x = j*4; y = (int)(580 - 200.0*meditation/255); if (j > 0) { line(prevX, prevY, x, y); } prevValue = meditation; prevX = x; prevY = y; j++; } } void drawConnecting() { background(255); text("Connecting to " + portName + ", please wait...", 5, 20); } // Serial selection void drawSerialSelect() { background(255); int hover = (int)Math.round(Math.floor(mouseY/20)); if (mousePressed) { selected = hover; } for (int i = 0; i < portNames.length; i++) { if (i == selected) { fill(0); rect(0, i*20, width, 20); fill(255); portName = portNames[i]; println("selected " + portName); serialPort = new Serial(this, portName, 115200); appState = APP_CONNECTING; eeg = new eegPort(this, serialPort); delay(500); eeg.refresh(); } else if (i == hover) { fill(200, 200, 240); noStroke(); rect(0, i*20, width, 20); fill(0); } else { fill(0); } text(portNames[i], 5, (i+1)*20); } } void serialEvent(Serial p) { while (p.available() > 0) { int inByte = p.read(); eeg.serialByte(inByte); if (inByte == 170 && appState < APP_CONNECTED) { println("Connected"); appState = APP_CONNECTED; frameRate(10); } } } void keyPressed() { output.flush(); // on keypress... output.close(); // ...we close the file... exit(); // ...and terminate program. } |
If you have any questions or comments, please contact the authors at .