├── .gitattributes ├── .gitignore ├── Arduino ├── OBCI_V2_AlphaDetector │ ├── Libraries │ │ ├── ADS1299 │ │ │ ├── ADS1299.cpp │ │ │ ├── ADS1299.h │ │ │ ├── ADS1299Manager.cpp │ │ │ ├── ADS1299Manager.h │ │ │ ├── Definitions.h │ │ │ ├── README.txt │ │ │ ├── examples │ │ │ │ ├── ADS_Arduino_example_1 │ │ │ │ │ └── ADS_Arduino_example_1.ino │ │ │ │ └── ADS_Arduino_example_2 │ │ │ │ │ └── ADS_Arduino_example_2.ino │ │ │ └── keywords.txt │ │ ├── Biquad │ │ │ ├── Biquad.cpp │ │ │ ├── Biquad.h │ │ │ ├── Biquad_multiChan.cpp │ │ │ └── Biquad_multiChan.h │ │ └── readme.txt │ └── ProcessDataOnArduino_Biquad │ │ └── ProcessDataOnArduino_Biquad.ino ├── OBCI_V3_Debugging │ ├── 01-FirstCodeFromJoel │ │ ├── Device_OBCI_02 │ │ │ └── Device_OBCI_02.ino │ │ ├── Host_OBCI_02 │ │ │ └── Host_OBCI_02.ino │ │ ├── IMG_1971.jpg │ │ ├── IMG_1972.jpg │ │ ├── LIS3DH axl.pdf │ │ ├── OBCI_SD_LOG_05 │ │ │ ├── ADS1299.cpp │ │ │ ├── ADS1299.h │ │ │ ├── Definitions.h │ │ │ ├── LIS3DH.cpp │ │ │ ├── LIS3DH.h │ │ │ ├── OBCI_SD_LOG_05.ino │ │ │ ├── OpenBCI_04.cpp │ │ │ └── OpenBCI_04.h │ │ ├── READ_ME.txt │ │ └── UNO_streamCheckSum_04 │ │ │ └── UNO_streamCheckSum_04.ino │ ├── 02-OBCI_Stream │ │ ├── Device_OBCI_streamData │ │ │ └── Device_OBCI_streamData.ino │ │ ├── Host_OBCI_streamData │ │ │ └── Host_OBCI_streamData.ino │ │ ├── OBCI_UNO_streamData_02 │ │ │ ├── ADS1299.cpp │ │ │ ├── ADS1299.h │ │ │ ├── Definitions.h │ │ │ ├── LIS3DH.cpp │ │ │ ├── LIS3DH.h │ │ │ ├── OBCI_UNO_streamData_02.ino │ │ │ ├── OpenBCI_04.cpp │ │ │ └── OpenBCI_04.h │ │ ├── OBCI_UNO_streamFakeData │ │ │ └── UNO_OBCI_streamFakeData.ino │ │ └── OBCI_streamRealData │ │ │ ├── ADS1299.cpp │ │ │ ├── ADS1299.h │ │ │ ├── Definitions.h │ │ │ ├── LIS3DH.cpp │ │ │ ├── LIS3DH.h │ │ │ ├── OBCI_StreamRealData.ino │ │ │ ├── OpenBCI_04.cpp │ │ │ └── OpenBCI_04.h │ ├── 03-ThirdCodeFromJoel │ │ ├── Device_OBCI_streamData │ │ │ └── Device_OBCI_streamData.ino │ │ ├── Host_OBCI_streamData │ │ │ └── Host_OBCI_streamData.ino │ │ └── OBCI_8bit_streamData_Filter │ │ │ ├── ADS1299.cpp │ │ │ ├── ADS1299.h │ │ │ ├── Definitions.h │ │ │ ├── LIS3DH.cpp │ │ │ ├── LIS3DH.h │ │ │ ├── OBCI_8bit_streamData_Filter.ino │ │ │ ├── OpenBCI_04.cpp │ │ │ └── OpenBCI_04.h │ └── UpdatedRFDuinoLibrary │ │ ├── libRFduinoGZLL.a │ │ └── readme.txt ├── ReadPhotocellResistance │ └── ReadPhotocellResistance.ino ├── TestHexBugController │ └── TestHexBugController.ino ├── TestQuadCopterController │ ├── MCP42XXX.cpp │ ├── MCP42XXX.h │ └── TestQuadCopterController.ino └── UnoStarterPlotting │ └── UnoStarterPlotting.ino ├── Data ├── 2013-11-01a ECG with V2 │ ├── SavedData │ │ ├── data_2013-10-28_17-11-44_ECG_V2.mat │ │ ├── data_2013-10-28_17-13-46_ECG_V1.mat │ │ ├── data_2013-11-01_16-16-16.mat │ │ ├── data_2013-11-01_16-20-41_V2_allChan_wMarks.mat │ │ └── data_OpenBCI_format.zip │ ├── exploreSavedData.m │ └── exploreSavedData_ECG.m ├── 2013-11-01b Attempt2 at Mu Waves │ ├── SavedData │ │ ├── data_2013-11-01_16-46-54_V1_MuWaves.mat │ │ ├── data_2013-11-01_16-56-00_V2_MuWaves.mat │ │ └── data_OpenBCI_format.zip │ ├── convertMAT2OpenBCI.m │ └── exploreSavedData_muWaves.m ├── 2013-11-04 Homemade Electrodes │ ├── SavedData │ │ ├── data_2013-11-04_20-06-24_ECG_HomebrewElectrodes.mat │ │ ├── data_2013-11-04_20-16-06_MuWaves_HomebrewElectrodes.mat │ │ ├── data_2013-11-04_20-31-45_MuWaves2_HomebrewElectrodes.mat │ │ └── data_OpenBCI_format.zip │ ├── convertMAT2OpenBCI.m │ ├── exploreSavedData.m │ └── exploreSavedData_1Chan.m ├── 2013-11-08 EOG │ ├── SavedData.zip │ ├── convertMAT2OpenBCI.m │ ├── data_OpenBCI_format.zip │ └── exploreSavedData_1Chan.m ├── 2014-04-05 Impedance and Concentration │ ├── SavedData.zip │ ├── exploreData.m │ ├── functions │ │ ├── loopWaves.asv │ │ └── loopWaves.m │ ├── measureAlpha.m │ ├── measureBeta.m │ └── measureImpedance.m ├── 2014-04-23 OpenBCI EEG over Breakfast and Birds │ ├── 2014-04-23 Script of EEG Breakfast.xlsx │ ├── SavedData.zip │ ├── exploreCoherence.m │ ├── exploreData.m │ ├── functions │ │ ├── calcCoherece_fromTimeDomain.asv │ │ ├── calcCoherece_fromTimeDomain.m │ │ ├── calcCoherence.m │ │ ├── evalCoherence_nearbyOnly.asv │ │ ├── evalCoherence_nearbyOnly.m │ │ ├── plotSpectrograms_headshape.asv │ │ └── plotSpectrograms_headshape.m │ ├── measureAlpha.m │ ├── measureBeta.m │ └── measureBeta_multiChan.m ├── 2014-04-30 Visual Steady-State Evoked Potentials │ ├── SavedData.zip │ ├── exploreData.m │ ├── exploreSSVEP.asv │ ├── exploreSSVEP.m │ ├── functions │ │ ├── calcCoherece_fromTimeDomain.asv │ │ ├── calcCoherece_fromTimeDomain.m │ │ ├── calcCoherence.m │ │ ├── evalCoherence_nearbyOnly.asv │ │ ├── evalCoherence_nearbyOnly.m │ │ ├── plotSpectrograms_headshape.asv │ │ └── plotSpectrograms_headshape.m │ └── measureBeta_multiChan.m ├── 2014-05-08 Multi-Rate Visual Evoked Potentials │ ├── SavedData.zip │ ├── exploreData.m │ ├── exploreData_wAux.m │ └── measureBeta_multiChan.m ├── 2014-05-31 RobotControl │ ├── .picasa.ini │ ├── AnalysisResults │ │ ├── Detection Results.png │ │ ├── Detection Rules.png │ │ ├── RawDataSpectrograms.png │ │ └── RawDataSpectrum.png │ ├── BlogPics │ │ ├── DecideCommand.png │ │ ├── EEG Processing.png │ │ ├── Figures.ppt │ │ ├── Setup-Schematic.png │ │ ├── Setup-Schematic2.png │ │ ├── Setup.png │ │ ├── Spectrum-Forward.png │ │ ├── Spectrum-TurnLeft.png │ │ └── Spectrum-TurnRight.png │ ├── RobotMotionTimingRelMovie.xlsx │ ├── SavedData │ │ └── openBCI_raw_2014-05-31_20-48-01_RobotControlAll.zip │ ├── analysis.py │ ├── c2cb.py │ ├── exploreData_forRobot.m │ ├── makeBlinkingMovie │ │ ├── ThreeSpeedMovie │ │ │ └── Block1_20Hz_12Hz_15HzToggle.mp4 │ │ ├── TwoSpeedMovie │ │ │ └── MP4 │ │ │ │ └── Block1_15HzToggle_10HzToggle.mp4 │ │ ├── makeBlinkingMovie_1speed.m │ │ ├── makeBlinkingMovie_2speeds.m │ │ └── makeBlinkingMovie_3speeds.m │ ├── readme.txt │ └── trainFromRobotData.m ├── 2014-07-17 ECG Using Bluetooth and Android │ ├── SavedData │ │ └── RawDataFromAndroid.zip │ ├── ScreenShots │ │ ├── Screenshot_2014-07-17-11-20-52.png │ │ ├── Screenshot_2014-07-17-11-22-20.png │ │ └── Screenshot_2014-07-17-11-22-35.png │ └── Test Setup.pptx ├── 2014-08-17 First V3 Data │ ├── Data │ │ ├── 05-testSig_1x_Fast.bin │ │ ├── 06-normalInput.bin │ │ ├── 07-capture_bot_bot.bin │ │ ├── 08-capture_top_top.bin │ │ ├── 09-capture_bot_top.bin │ │ ├── 10-capture_top_bot.bin │ │ ├── 20-capture_8chanTestSig_died.bin │ │ ├── 21-capture_8chanTestSig_died.bin │ │ └── 22-capture_8chanTestSig_died.bin │ ├── Pics │ │ ├── ECG on OpenBCI V3.png │ │ ├── Figures.pptx │ │ ├── IMG_3039.JPG │ │ ├── IMG_3046.JPG │ │ └── TestSig.png │ ├── SavedData │ │ └── OpenBCI-2014-08-18_15-57-32_8chanTestSig.jpg │ ├── exploreData_ProcessingDump.m │ ├── exploreData_byteDump.m │ └── exploreData_byteDump_ECG.m ├── 2014-10-03 V3 Alpha │ ├── Figures │ │ ├── .picasa.ini │ │ ├── 2014-10-05_Alpha_NoCaffeine.png │ │ └── IMG_3195.JPG │ ├── SavedData │ │ └── Unzip This Data.zip │ ├── ScreenShots │ │ ├── OpenBCI-2014-10-04_18-54-52_impedanceCheck.jpg │ │ ├── OpenBCI-2014-10-04_18-57-38_alpha.jpg │ │ ├── OpenBCI-2014-10-04_18-59-54_biasFromTopRow.jpg │ │ ├── OpenBCI-2014-10-04_19-00-16_biasFromBottomRow.jpg │ │ ├── OpenBCI-2014-10-04_19-01-59_noBias.jpg │ │ ├── OpenBCI-2014-10-04_19-07-07_eyesOpen.jpg │ │ ├── OpenBCI-2014-10-04_19-07-34_eyesShut.jpg │ │ └── OpenBCI-2014-10-05_17-16-44_alpha_noCaffeine.jpg │ ├── analyzeAlpha.py │ ├── analyzeAlpha_detection.py │ ├── analyzeAlpha_detection_allFiles.py │ ├── analyzeAlpha_detection_vsNFFT.py │ ├── analyzeAlpha_detection_vsRule.py │ ├── exploreData.py │ └── helperFunctions.py ├── 2014-10-25 AF LabHack │ ├── exploreData.py │ └── exploreData_3man.py ├── 2014-11-23 Accelerometer │ ├── Pics │ │ ├── BoardWithBatteries.JPG │ │ ├── BoardZoom.JPG │ │ └── Figures.pptx │ ├── SavedData │ │ └── OpenBCI-RAW-2014-11-23_18-54-57.zip │ ├── exploreAccelData.html │ ├── exploreAccelData.ipynb │ ├── exploreAccelData.py │ └── readme.txt ├── 2015-01-24 Auditory Steady State │ ├── 2015-01-24 ASSR Figures.pptx │ ├── SavedData.zip │ ├── SavedData │ │ ├── OpenBCI-2015-01-24_12-19-36.jpg │ │ ├── OpenBCI-2015-01-24_12-19-47.jpg │ │ ├── OpenBCI-2015-01-25_18-30-11.jpg │ │ ├── OpenBCI-2015-01-25_18-31-17.jpg │ │ ├── OpenBCI-2015-01-25_19-17-30.jpg │ │ └── OpenBCI-2015-01-25_19-17-53.jpg │ ├── SavedData_Day2.zip │ ├── TestTones │ │ ├── 1000Hz_37HzSine.mp3 │ │ ├── 1000Hz_38Hz.mp3 │ │ ├── 1000Hz_40Hz.mp3 │ │ ├── 1000Hz_40HzSine.mp3 │ │ ├── 1000Hz_42Hz.mp3 │ │ ├── 1000Hz_43HzSine.mp3 │ │ ├── 2500Hz_38Hz.mp3 │ │ ├── 2500Hz_40Hz.mp3 │ │ ├── 2500Hz_42Hz.mp3 │ │ ├── 2500_37HzSine.mp3 │ │ ├── 2500_40HzSine.mp3 │ │ ├── 2500_43HzSine.mp3 │ │ └── L-1000-37Hz_R-2500-43Hz.mp3 │ ├── exploreData-Day2.ipynb │ ├── exploreData-checkBiasBehavior.ipynb │ ├── exploreData.ipynb │ ├── exploreData.py │ └── readme.txt ├── 2015-01-30 Test on Human at Dartmouth │ ├── EEGHacker_Analysis │ │ ├── exploreData-checkBiasBehavior.ipynb │ │ └── exploreData.ipynb │ ├── elec_locations.csv │ ├── elec_locations.xls │ └── elec_positions.txt └── 2015-02-07 OpenBCI Hack Weekend NYC │ └── exploreData_teamAlpha.ipynb ├── Matlab └── makeBlinkingMovie │ ├── makeBlinkingMovie_1speed.m │ ├── makeBlinkingMovie_2speeds.m │ └── makeBlinkingMovie_3speeds.m ├── Processing └── OBCI_V3_Debugging │ ├── OBCI_Verify_PacketCount │ ├── OBCI_Verify_PacketCount.pde │ ├── OBCI_packetCount_verification │ │ └── 9_29_7_25_35.txt │ ├── data │ │ └── Dialog-24.vlw │ ├── folderStuff.pde │ ├── mouseButtonSuff.pde │ └── sketch.properties │ ├── OpenBCI_GUI │ ├── AndroidManifest.xml │ ├── Button.pde │ ├── ControlPanel.pde │ ├── EEG_Processing.pde │ ├── Gui_Manager.pde │ ├── HeadPlot.pde │ ├── OpenBCI_ADS1299.pde │ ├── OpenBCI_GUI.pde │ ├── ScatterTrace.pde │ ├── Spectrogram.pde │ ├── data │ │ ├── CourierNewPSMT-24.vlw │ │ ├── electrode_positions_12elec_scalp9.txt │ │ ├── electrode_positions_default.txt │ │ └── electrode_positions_maker_faire_2013.txt │ ├── dataFiles.pde │ ├── dataTypes.pde │ └── math.pde │ └── serialCommToOpenBCI │ ├── dataFiles.pde │ ├── dataTypes.pde │ ├── serialCommToOpenBCI.pde │ └── sketch.properties ├── Python ├── 2015-01-17 Missing Even Channels │ └── exploreData.ipynb ├── FilterDesign │ └── explore_notchFilters.py └── Scalp4x2Model │ ├── LVA Data.xlsx │ ├── ResistorNetwork.png │ ├── ResistorNetwork.pptx │ ├── ScalpTest-ResistorNetwork-MultiDrive.ipynb │ ├── ScalpTest-ResistorNetwork.ipynb │ └── ScalpTest-SolveForResistances.ipynb └── readme.txt /.gitattributes: -------------------------------------------------------------------------------- 1 | # Auto detect text files and perform LF normalization 2 | * text=auto 3 | 4 | # Custom for Visual Studio 5 | *.cs diff=csharp 6 | *.sln merge=union 7 | *.csproj merge=union 8 | *.vbproj merge=union 9 | *.fsproj merge=union 10 | *.dbproj merge=union 11 | 12 | # Standard to msysgit 13 | *.doc diff=astextplain 14 | *.DOC diff=astextplain 15 | *.docx diff=astextplain 16 | *.DOCX diff=astextplain 17 | *.dot diff=astextplain 18 | *.DOT diff=astextplain 19 | *.pdf diff=astextplain 20 | *.PDF diff=astextplain 21 | *.rtf diff=astextplain 22 | *.RTF diff=astextplain 23 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | 2 | ## added by Chip 3 | *.asv 4 | *.avi 5 | *.mov 6 | *.mat 7 | *.asc 8 | openBCI*.txt 9 | OpenBCI_GUI\OpenBCI*.jpg 10 | openBCI*.wav 11 | *\.ipynb_checkpoints 12 | *\.ipynb_checkpoints\* 13 | 14 | Processing\OBCI_V3_Debugging\OBCI_Verify_PacketCount\OBCI_packetCount_verification\* 15 | Processing\OBCI_V3_Debugging\OpenBCI_GUI\SavedData\* 16 | 17 | ################# 18 | ## Eclipse 19 | ################# 20 | 21 | *.pydevproject 22 | .project 23 | .metadata 24 | bin/ 25 | tmp/ 26 | *.tmp 27 | *.bak 28 | *.swp 29 | *~.nib 30 | local.properties 31 | .classpath 32 | .settings/ 33 | .loadpath 34 | 35 | # External tool builders 36 | .externalToolBuilders/ 37 | 38 | # Locally stored "Eclipse launch configurations" 39 | *.launch 40 | 41 | # CDT-specific 42 | .cproject 43 | 44 | # PDT-specific 45 | .buildpath 46 | 47 | 48 | ################# 49 | ## Visual Studio 50 | ################# 51 | 52 | ## Ignore Visual Studio temporary files, build results, and 53 | ## files generated by popular Visual Studio add-ons. 54 | 55 | # User-specific files 56 | *.suo 57 | *.user 58 | *.sln.docstates 59 | 60 | # Build results 61 | 62 | [Dd]ebug/ 63 | [Rr]elease/ 64 | x64/ 65 | build/ 66 | [Bb]in/ 67 | [Oo]bj/ 68 | 69 | # MSTest test Results 70 | [Tt]est[Rr]esult*/ 71 | [Bb]uild[Ll]og.* 72 | 73 | *_i.c 74 | *_p.c 75 | *.ilk 76 | *.meta 77 | *.obj 78 | *.pch 79 | *.pdb 80 | *.pgc 81 | *.pgd 82 | *.rsp 83 | *.sbr 84 | *.tlb 85 | *.tli 86 | *.tlh 87 | *.tmp 88 | *.tmp_proj 89 | *.log 90 | *.vspscc 91 | *.vssscc 92 | .builds 93 | *.pidb 94 | *.log 95 | *.scc 96 | 97 | # Visual C++ cache files 98 | ipch/ 99 | *.aps 100 | *.ncb 101 | *.opensdf 102 | *.sdf 103 | *.cachefile 104 | 105 | # Visual Studio profiler 106 | *.psess 107 | *.vsp 108 | *.vspx 109 | 110 | # Guidance Automation Toolkit 111 | *.gpState 112 | 113 | # ReSharper is a .NET coding add-in 114 | _ReSharper*/ 115 | *.[Rr]e[Ss]harper 116 | 117 | # TeamCity is a build add-in 118 | _TeamCity* 119 | 120 | # DotCover is a Code Coverage Tool 121 | *.dotCover 122 | 123 | # NCrunch 124 | *.ncrunch* 125 | .*crunch*.local.xml 126 | 127 | # Installshield output folder 128 | [Ee]xpress/ 129 | 130 | # DocProject is a documentation generator add-in 131 | DocProject/buildhelp/ 132 | DocProject/Help/*.HxT 133 | DocProject/Help/*.HxC 134 | DocProject/Help/*.hhc 135 | DocProject/Help/*.hhk 136 | DocProject/Help/*.hhp 137 | DocProject/Help/Html2 138 | DocProject/Help/html 139 | 140 | # Click-Once directory 141 | publish/ 142 | 143 | # Publish Web Output 144 | *.Publish.xml 145 | *.pubxml 146 | 147 | # NuGet Packages Directory 148 | ## TODO: If you have NuGet Package Restore enabled, uncomment the next line 149 | #packages/ 150 | 151 | # Windows Azure Build Output 152 | csx 153 | *.build.csdef 154 | 155 | # Windows Store app package directory 156 | AppPackages/ 157 | 158 | # Others 159 | sql/ 160 | *.Cache 161 | ClientBin/ 162 | [Ss]tyle[Cc]op.* 163 | ~$* 164 | *~ 165 | *.dbmdl 166 | *.[Pp]ublish.xml 167 | *.pfx 168 | *.publishsettings 169 | 170 | # RIA/Silverlight projects 171 | Generated_Code/ 172 | 173 | # Backup & report files from converting an old project file to a newer 174 | # Visual Studio version. Backup files are not needed, because we have git ;-) 175 | _UpgradeReport_Files/ 176 | Backup*/ 177 | UpgradeLog*.XML 178 | UpgradeLog*.htm 179 | 180 | # SQL Server files 181 | App_Data/*.mdf 182 | App_Data/*.ldf 183 | 184 | ############# 185 | ## Windows detritus 186 | ############# 187 | 188 | # Windows image file caches 189 | Thumbs.db 190 | ehthumbs.db 191 | 192 | # Folder config file 193 | Desktop.ini 194 | 195 | # Recycle Bin used on file shares 196 | $RECYCLE.BIN/ 197 | 198 | # Mac crap 199 | .DS_Store 200 | 201 | 202 | ############# 203 | ## Python 204 | ############# 205 | 206 | *.py[co] 207 | 208 | # Packages 209 | *.egg 210 | *.egg-info 211 | dist/ 212 | build/ 213 | eggs/ 214 | parts/ 215 | var/ 216 | sdist/ 217 | develop-eggs/ 218 | .installed.cfg 219 | 220 | # Installer logs 221 | pip-log.txt 222 | 223 | # Unit test / coverage reports 224 | .coverage 225 | .tox 226 | 227 | #Translations 228 | *.mo 229 | 230 | #Mr Developer 231 | .mr.developer.cfg 232 | -------------------------------------------------------------------------------- /Arduino/OBCI_V2_AlphaDetector/Libraries/ADS1299/ADS1299.h: -------------------------------------------------------------------------------- 1 | // 2 | // ADS1299.h 3 | // Part of the Arduino Library 4 | // Created by Conor Russomanno, Luke Travis, and Joel Murphy. Summer 2013. 5 | // 6 | // Modified by Chip Audette through April 2014 7 | // 8 | 9 | #ifndef ____ADS1299__ 10 | #define ____ADS1299__ 11 | 12 | #include 13 | #include 14 | #include 15 | #include "Definitions.h" 16 | 17 | 18 | class ADS1299 { 19 | public: 20 | 21 | void initialize(int _DRDY, int _RST, int _CS, int _FREQ, boolean _isDaisy); 22 | 23 | //ADS1299 SPI Command Definitions (Datasheet, p35) 24 | //System Commands 25 | void WAKEUP(); 26 | void STANDBY(); 27 | void RESET(); 28 | void START(); 29 | void STOP(); 30 | 31 | //Data Read Commands 32 | void RDATAC(); 33 | void SDATAC(); 34 | void RDATA(); 35 | 36 | //Register Read/Write Commands 37 | byte getDeviceID(); 38 | byte RREG(byte _address); 39 | void RREGS(byte _address, byte _numRegistersMinusOne); 40 | void printRegisterName(byte _address); 41 | void WREG(byte _address, byte _value); 42 | void WREGS(byte _address, byte _numRegistersMinusOne); 43 | void printHex(byte _data); 44 | void updateChannelData(); 45 | 46 | //SPI Transfer function 47 | byte transfer(byte _data); 48 | 49 | //configuration 50 | int DRDY, CS; // pin numbers for DRDY and CS 51 | int DIVIDER; // select SPI SCK frequency 52 | int stat_1, stat_2; // used to hold the status register for boards 1 and 2 53 | byte regData [24]; // array is used to mirror register data 54 | long channelData [16]; // array used when reading channel data board 1+2 55 | boolean verbose; // turn on/off Serial feedback 56 | boolean isDaisy; // does this have a daisy chain board? 57 | 58 | 59 | }; 60 | 61 | #endif -------------------------------------------------------------------------------- /Arduino/OBCI_V2_AlphaDetector/Libraries/ADS1299/Definitions.h: -------------------------------------------------------------------------------- 1 | // 2 | // Definitions.h 3 | // 4 | // 5 | // Created by Conor Russomanno, Luke Travis, and Joel Murphy. Summer 2013. 6 | // 7 | // 8 | 9 | #ifndef _Definitions_h 10 | #define _Definitions_h 11 | 12 | 13 | #define SPI_DATA_MODE 0x04 //CPOL = 0; CPHA = 1 (Datasheet, p8) 14 | #define SPI_MODE_MASK 0x0C // mask of CPOL and CPHA on SPCR 15 | #define SPI_CLOCK_MASK 0x03 // SPR1 = bit 1, SPR0 = bit 0 on SPCR 16 | #define SPI_2XCLOCK_MASK 0x01 // SPI2X = bit 0 on SPSR 17 | #define SPI_CLOCK_DIV_2 0X04 // 8MHz SPI SCK 18 | #define SPI_CLOCK_DIV_4 0X00 // 4MHz SPI SCK 19 | #define SPI_CLOCK_DIV_16 0x01 // 1MHz SPI SCK 20 | 21 | //SPI Command Definition Byte Assignments (Datasheet, p35) 22 | #define _WAKEUP 0x02 // Wake-up from standby mode 23 | #define _STANDBY 0x04 // Enter Standby mode 24 | #define _RESET 0x06 // Reset the device registers to default 25 | #define _START 0x08 // Start and restart (synchronize) conversions 26 | #define _STOP 0x0A // Stop conversion 27 | #define _RDATAC 0x10 // Enable Read Data Continuous mode (default mode at power-up) 28 | #define _SDATAC 0x11 // Stop Read Data Continuous mode 29 | #define _RDATA 0x12 // Read data by command; supports multiple read back 30 | 31 | 32 | //Register Addresses 33 | #define ID 0x00 34 | #define CONFIG1 0x01 35 | #define CONFIG2 0x02 36 | #define CONFIG3 0x03 37 | #define LOFF 0x04 38 | #define CH1SET 0x05 39 | #define CH2SET 0x06 40 | #define CH3SET 0x07 41 | #define CH4SET 0x08 42 | #define CH5SET 0x09 43 | #define CH6SET 0x0A 44 | #define CH7SET 0x0B 45 | #define CH8SET 0x0C 46 | #define BIAS_SENSP 0x0D 47 | #define BIAS_SENSN 0x0E 48 | #define LOFF_SENSP 0x0F 49 | #define LOFF_SENSN 0x10 50 | #define LOFF_FLIP 0x11 51 | #define LOFF_STATP 0x12 52 | #define LOFF_STATN 0x13 53 | #define GPIO 0x14 54 | #define MISC1 0x15 55 | #define MISC2 0x16 56 | #define CONFIG4 0x17 57 | 58 | #endif 59 | -------------------------------------------------------------------------------- /Arduino/OBCI_V2_AlphaDetector/Libraries/ADS1299/examples/ADS_Arduino_example_1/ADS_Arduino_example_1.ino: -------------------------------------------------------------------------------- 1 | /*Developed by Joel Murphy and Conor Russomanno (Summer 2013) 2 | This example uses the ADS1299 Arduino Library, a software bridge between the ADS1299 chip and 3 | Arduino. See http://www.ti.com/product/ads1299 for more information about the device and the README 4 | folder in the ADS1299 directory for more information about the library. 5 | 6 | This program reads all the ADS1299 registers, modifies CONFIG3, then modifies all 8 channel registers. 7 | Yup, it's a simple SPI link hello world functional test. When verbose is true, there will be Serial feedback. 8 | NOTE: the datasheet will tell you that the Channel Set Registers (0x05 to 0x0C) default to 0x60. Don't believe it. 9 | The default value for these locations is 0x61. 10 | 11 | 12 | Arduino Uno - Pin Assignments 13 | SCK = 13 14 | MISO [DOUT] = 12 15 | MOSI [DIN] = 11 16 | CS = 10; 17 | RESET = 9; 18 | DRDY = 8; 19 | 20 | */ 21 | 22 | #include 23 | 24 | ADS1299 ADS; 25 | 26 | void setup() { 27 | // don't put anything before the initialization routine for recommended POR 28 | ADS.initialize(8,9,10,4); // (DRDY pin, RST pin, CS pin, SCK frequency in MHz); 29 | 30 | Serial.begin(115200); 31 | Serial.println("ADS1299-Arduion UNO Example 1"); 32 | delay(1000); 33 | 34 | ADS.verbose = true; // when verbose is true, there will be Serial feedback 35 | ADS.RESET(); // all registers set to default 36 | ADS.SDATAC(); // stop Read Data Continuous mode to communicate with ADS 37 | ADS.RREGS(0x00,0x17); // read ADS registers starting at 0x00 and ending at 0x17 38 | ADS.WREG(CONFIG3,0xE0); // enable internal reference buffer 39 | ADS.RREG(CONFIG3); // verify write 40 | for(byte i=CH1SET; i<=CH8SET; i++){ // set up to modify the 8 channel setting registers 41 | ADS.regData[i] = 0x60; // the regData array mirrors the ADS1299 register addresses 42 | } 43 | ADS.WREGS(CH1SET,7); // write new channel settings 44 | ADS.RREGS(CH1SET,7); // read out what we just did to verify the write 45 | ADS.RDATAC(); // enter Read Data Continuous mode 46 | 47 | } // end of setup 48 | 49 | void loop(){ 50 | } // end of loop 51 | -------------------------------------------------------------------------------- /Arduino/OBCI_V2_AlphaDetector/Libraries/ADS1299/keywords.txt: -------------------------------------------------------------------------------- 1 | ADS1299 KEYWORD1 2 | ADS1299Manager KEYWORD1 3 | getDeviceID KEYWORD2 4 | -------------------------------------------------------------------------------- /Arduino/OBCI_V2_AlphaDetector/Libraries/Biquad/Biquad.h: -------------------------------------------------------------------------------- 1 | // 2 | // Biquad.h 3 | // 4 | // Created by Nigel Redmon on 11/24/12 5 | // EarLevel Engineering: earlevel.com 6 | // Copyright 2012 Nigel Redmon 7 | // 8 | // For a complete explanation of the Biquad code: 9 | // http://www.earlevel.com/main/2012/11/25/biquad-c-source-code/ 10 | // 11 | // License: 12 | // 13 | // This source code is provided as is, without warranty. 14 | // You may copy and distribute verbatim copies of this document. 15 | // You may modify and use this source code to create binary code 16 | // for your own purposes, free or commercial. 17 | // 18 | 19 | #ifndef Biquad_h 20 | #define Biquad_h 21 | 22 | enum { 23 | bq_type_lowpass = 0, 24 | bq_type_highpass, 25 | bq_type_bandpass, 26 | bq_type_notch, 27 | bq_type_peak, 28 | bq_type_lowshelf, 29 | bq_type_highshelf 30 | }; 31 | 32 | class Biquad { 33 | public: 34 | Biquad(); 35 | Biquad(int type, double Fc, double Q, double peakGainDB); 36 | ~Biquad(); 37 | void setType(int type); 38 | void setQ(double Q); 39 | void setFc(double Fc); 40 | void setPeakGain(double peakGainDB); 41 | void setBiquad(int type, double Fc, double Q, double peakGain); 42 | float process(float in); 43 | 44 | protected: 45 | void calcBiquad(void); 46 | 47 | int type; 48 | double a0, a1, a2, b1, b2; 49 | double Fc, Q, peakGain; 50 | double z1, z2; 51 | }; 52 | 53 | inline float Biquad::process(float in) { 54 | double out = in * a0 + z1; 55 | z1 = in * a1 + z2 - b1 * out; 56 | z2 = in * a2 - b2 * out; 57 | return out; 58 | } 59 | 60 | #endif // Biquad_h 61 | -------------------------------------------------------------------------------- /Arduino/OBCI_V2_AlphaDetector/Libraries/Biquad/Biquad_multiChan.h: -------------------------------------------------------------------------------- 1 | // 2 | // Biquad_multiChan.h 3 | // 4 | // Created by Nigel Redmon on 11/24/12 5 | // EarLevel Engineering: earlevel.com 6 | // Copyright 2012 Nigel Redmon 7 | // 8 | // For a complete explanation of the Biquad code: 9 | // http://www.earlevel.com/main/2012/11/25/biquad-c-source-code/ 10 | // 11 | // License: 12 | // 13 | // This source code is provided as is, without warranty. 14 | // You may copy and distribute verbatim copies of this document. 15 | // You may modify and use this source code to create binary code 16 | // for your own purposes, free or commercial. 17 | // 18 | // Extended by Chip Audette (Nov 2013) to handle multiple channels of data 19 | // that are being filtered by the same coefficients 20 | // 21 | 22 | #ifndef Biquad_multiChan_h 23 | #define Biquad_multiChan_h 24 | 25 | enum { 26 | bq_type_lowpass = 0, 27 | bq_type_highpass, 28 | bq_type_bandpass, 29 | bq_type_notch, 30 | bq_type_peak, 31 | bq_type_lowshelf, 32 | bq_type_highshelf 33 | }; 34 | 35 | class Biquad_multiChan { 36 | public: 37 | //Biquad_multiChan(); 38 | Biquad_multiChan(int Nchan, int type, double Fc, double Q, double peakGainDB); 39 | ~Biquad_multiChan(); 40 | void setType(int type); 41 | void setQ(double Q); 42 | void setFc(double Fc); 43 | void setPeakGain(double peakGainDB); 44 | void setBiquad(int type, double Fc, double Q, double peakGain); 45 | float process(float in,int Ichan); 46 | 47 | protected: 48 | void calcBiquad(void); 49 | 50 | int Nchan; 51 | int type; 52 | double a0, a1, a2, b1, b2; 53 | double Fc, Q, peakGain; 54 | double *z1, *z2; 55 | }; 56 | 57 | inline float Biquad_multiChan::process(float in,int Ichan) { 58 | double out = in * a0 + z1[Ichan]; 59 | z1[Ichan] = in * a1 + z2[Ichan] - b1 * out; 60 | z2[Ichan] = in * a2 - b2 * out; 61 | return out; 62 | } 63 | 64 | #endif // Biquad_multiChan_h 65 | -------------------------------------------------------------------------------- /Arduino/OBCI_V2_AlphaDetector/Libraries/readme.txt: -------------------------------------------------------------------------------- 1 | 2 | ARDUINO LIBRARIES 3 | ------------------ 4 | 5 | These are libraries that are used by the various OpenBCI Arduino sketches. 6 | 7 | 8 | ** ADS1299: This is the core library for servicing the OpenBCI shield (V1 and V2). It contains the base ADS1299 Class as well as the ADS1299Manager class. This library was developed and tested using Arduino 1.0.5. 9 | 10 | ** Biquad: This is a library used in some sketches to perform time-domain filtering of the EEG data on the Arduino itself. This library was last developed and tested in Arduino 1.0.5. This code is a slightly modified version of the code originally found at http://www.earlevel.com/main/2012/11/25/biquad-c-source-code/ 11 | 12 | 13 | 14 | Instructions 15 | ------------ 16 | 17 | Download these libraries, unzip them, and put the contents into your Arduino "libraries" directory. On a Windows PC, I liked to put them in "My Documents\Arduino\Libraries\". 18 | -------------------------------------------------------------------------------- /Arduino/OBCI_V3_Debugging/01-FirstCodeFromJoel/IMG_1971.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/chipaudette/EEGHacker/f72cc121d51fb5ea2f9176ebc0bb821aef05e64e/Arduino/OBCI_V3_Debugging/01-FirstCodeFromJoel/IMG_1971.jpg -------------------------------------------------------------------------------- /Arduino/OBCI_V3_Debugging/01-FirstCodeFromJoel/IMG_1972.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/chipaudette/EEGHacker/f72cc121d51fb5ea2f9176ebc0bb821aef05e64e/Arduino/OBCI_V3_Debugging/01-FirstCodeFromJoel/IMG_1972.jpg -------------------------------------------------------------------------------- /Arduino/OBCI_V3_Debugging/01-FirstCodeFromJoel/LIS3DH axl.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/chipaudette/EEGHacker/f72cc121d51fb5ea2f9176ebc0bb821aef05e64e/Arduino/OBCI_V3_Debugging/01-FirstCodeFromJoel/LIS3DH axl.pdf -------------------------------------------------------------------------------- /Arduino/OBCI_V3_Debugging/01-FirstCodeFromJoel/OBCI_SD_LOG_05/ADS1299.h: -------------------------------------------------------------------------------- 1 | 2 | 3 | #ifndef ____ADS1299__ 4 | #define ____ADS1299__ 5 | 6 | #include 7 | #include 8 | #include 9 | #include "pins_arduino.h" 10 | #include "Definitions.h" 11 | 12 | class ADS1299 { 13 | public: 14 | 15 | void initialize(int _DRDY, int _RST, int _CS); 16 | 17 | //ADS1299 SPI Command Definitions (Datasheet, p35) 18 | //System Commands 19 | void WAKEUP(); 20 | void STANDBY(); 21 | void RESET(); 22 | void START(); 23 | void STOP(); 24 | 25 | //Data Read Commands 26 | void RDATAC(); 27 | void SDATAC(); 28 | void RDATA(); 29 | 30 | //Register Read/Write Commands 31 | 32 | byte RREG(byte _address); 33 | void RREGS(byte _address, byte _numRegistersMinusOne); 34 | void WREG(byte _address, byte _value); 35 | void WREGS(byte _address, byte _numRegistersMinusOne); 36 | byte getDeviceID(); 37 | void printRegisterName(byte _address); 38 | void printHex(byte _data); 39 | void updateChannelData(); 40 | 41 | //SPI Transfer function 42 | byte xfer(byte _data); 43 | 44 | int DRDY, CS, RST; // pin numbers for DataRead ChipSelect Reset pins 45 | int DIVIDER; // select SPI SCK frequency 46 | int stat; // used to hold the status register 47 | byte regData [24]; // array is used to mirror register data 48 | long channelData [9]; // array used when reading channel data 49 | boolean verbosity; // turn on/off Serial feedback 50 | 51 | void resetADS(void); //reset all the ADS1299's settings. Call however you'd like 52 | void startADS(void); 53 | void stopADS(void); 54 | 55 | 56 | void activateChannel(int N, byte gainCode,byte inputCode); //setup the channel 1-8 57 | void activateChannel(int, byte, byte, boolean); 58 | void deactivateChannel(int N); //disable given channel 1-8 59 | 60 | void configureInternalTestSignal(byte amplitudeCode, byte freqCode); 61 | 62 | boolean isDataAvailable(void); 63 | void printChannelDataAsText(int N, long int sampleNumber); 64 | void writeChannelDataAsBinary(int N, uint16_t sampleNumber); 65 | void writeChannelDataAsOpenEEG_P2(long int sampleNumber); 66 | void printAllRegisters(void); 67 | void setSRB1(boolean desired_state); 68 | void printDeviceID(void); 69 | 70 | private: 71 | byte old_SPCR; 72 | byte old_SPSR; 73 | boolean _OpenBCI_03; 74 | boolean use_N_inputs; 75 | boolean use_SRB2[OPENBCI_NCHAN]; 76 | boolean isRunning; 77 | boolean use_SRB1(void); 78 | void csLow(); 79 | void csHigh(); 80 | 81 | }; 82 | 83 | #endif 84 | -------------------------------------------------------------------------------- /Arduino/OBCI_V3_Debugging/01-FirstCodeFromJoel/OBCI_SD_LOG_05/LIS3DH.cpp: -------------------------------------------------------------------------------- 1 | 2 | 3 | #include "LIS3DH.h" 4 | 5 | void LIS3DH::initialize(){ // ADD ABILITY TO SET RESOLUTION 6 | pinMode(LIS3DH_SS,OUTPUT); digitalWrite(LIS3DH_SS,HIGH); 7 | pinMode(LIS3DH_DRDY,INPUT); // setup dataReady interupt from accelerometer 8 | DRDYpinValue = lastDRDYpinValue = digitalRead(LIS3DH_DRDY); // take a reading to seed these variables 9 | LIS3DH_write(TMP_CFG_REG, 0x40); // disable ADC inputs, enable temperature sensor 10 | LIS3DH_write(CTRL_REG4, 0x18); // set scale to +/-4g, high resolution 11 | LIS3DH_write(CTRL_REG3, 0x10); // enable DRDY1 on INT1 (tied to Arduino pin3, LIS3DH_DRDY) 12 | } 13 | 14 | void LIS3DH::enable_accel(){ // ADD ABILITY TO SET FREQUENCY 15 | LIS3DH_write(CTRL_REG1, 0x37); // set freq to 50Hz and enable all axis in normal mode 16 | } 17 | 18 | void LIS3DH::disable_accel(){ 19 | LIS3DH_write(CTRL_REG1, 0x08); // power down, low power mode 20 | } 21 | 22 | byte LIS3DH::getDeviceID(){ 23 | return LIS3DH_read(0x0F); 24 | } 25 | 26 | boolean LIS3DH::LIS3DH_DataReady(){ 27 | boolean r = false; 28 | DRDYpinValue = digitalRead(LIS3DH_DRDY); // take a look at LIS3DH_DRDY pin 29 | if(DRDYpinValue != lastDRDYpinValue){ // if the value has changed since last looking 30 | if(DRDYpinValue == HIGH){ // see if this is the rising edge 31 | r = true; // if so, there is fresh data! 32 | } 33 | lastDRDYpinValue = DRDYpinValue; // keep track of the changing pin 34 | } 35 | return r; 36 | } 37 | 38 | byte LIS3DH::LIS3DH_read(byte reg){ 39 | reg |= READ_REG; // add the READ_REG bit 40 | csLow(); // take spi 41 | SPI.transfer(reg); // send reg to read 42 | byte inByte = SPI.transfer(0x00); // retrieve data 43 | csHigh(); // release spi 44 | return inByte; 45 | } 46 | 47 | void LIS3DH::LIS3DH_write(byte reg, byte value){ 48 | csLow(); // take spi 49 | SPI.transfer(reg); // send reg to write 50 | SPI.transfer(value); // write value 51 | csHigh(); // release spi 52 | } 53 | 54 | int LIS3DH::LIS3DH_read16(byte reg){ // use for reading axis data. 55 | int inData; 56 | reg |= READ_REG | READ_MULTI; // add the READ_REG and READ_MULTI bits 57 | csLow(); // take spi 58 | SPI.transfer(reg); // send reg to start reading from 59 | inData = SPI.transfer(0x00) | (SPI.transfer(0x00) << 8); // get the data and arrange it 60 | csHigh(); // release spi 61 | return inData; 62 | } 63 | 64 | int LIS3DH::getX(){ 65 | return LIS3DH_read16(OUT_X_L); 66 | } 67 | 68 | int LIS3DH::getY(){ 69 | return LIS3DH_read16(OUT_Y_L); 70 | } 71 | 72 | int LIS3DH::getZ(){ 73 | return LIS3DH_read16(OUT_Z_L); 74 | } 75 | 76 | void LIS3DH::readAllRegs(){ 77 | 78 | byte inByte; 79 | 80 | for (int i = STATUS_REG_AUX; i <= WHO_AM_I; i++){ 81 | inByte = LIS3DH_read(i); 82 | Serial.print("0x0");Serial.print(i,HEX); 83 | Serial.print("\t");Serial.println(inByte,HEX); 84 | delay(20); 85 | } 86 | Serial.println(); 87 | 88 | for (int i = OUT_X_L; i <= INT1_DURATION; i++){ 89 | inByte = LIS3DH_read(i); 90 | Serial.print("0x");Serial.print(i,HEX); 91 | Serial.print("\t");Serial.println(inByte,HEX); 92 | delay(20); 93 | } 94 | Serial.println(); 95 | 96 | for (int i = CLICK_CFG; i <= TIME_WINDOW; i++){ 97 | inByte = LIS3DH_read(i); 98 | Serial.print("0x");Serial.print(i,HEX); 99 | Serial.print("\t");Serial.println(inByte,HEX); 100 | delay(20); 101 | } 102 | 103 | } 104 | 105 | void LIS3DH::csLow(void) 106 | { 107 | SPI.setDataMode(SPI_MODE3); // switch modes 108 | digitalWrite(LIS3DH_SS, LOW); // drop Slave Select 109 | } 110 | 111 | void LIS3DH::csHigh(void) 112 | { 113 | digitalWrite(LIS3DH_SS, HIGH); // raise select 114 | SPI.setDataMode(SPI_MODE0); 115 | } 116 | -------------------------------------------------------------------------------- /Arduino/OBCI_V3_Debugging/01-FirstCodeFromJoel/OBCI_SD_LOG_05/LIS3DH.h: -------------------------------------------------------------------------------- 1 | 2 | 3 | #ifndef ____LIS3DH__ 4 | #define ____LIS3DH__ 5 | 6 | #include 7 | #include 8 | #include 9 | #include "pins_arduino.h" 10 | #include "Definitions.h" 11 | 12 | class LIS3DH { 13 | public: 14 | void initialize(void); 15 | void enable_accel(void); 16 | void disable_accel(void); 17 | byte getDeviceID(void); 18 | byte LIS3DH_read(byte); 19 | void LIS3DH_write(byte,byte); 20 | int LIS3DH_read16(byte); 21 | int getX(void); 22 | int getY(void); 23 | int getZ(void); 24 | boolean LIS3DH_DataReady(void); 25 | void readAllRegs(void); 26 | 27 | private: 28 | void csLow(); 29 | void csHigh(); 30 | int DRDYpinValue; 31 | int lastDRDYpinValue; 32 | 33 | }; 34 | 35 | #endif 36 | -------------------------------------------------------------------------------- /Arduino/OBCI_V3_Debugging/01-FirstCodeFromJoel/OBCI_SD_LOG_05/OpenBCI_04.cpp: -------------------------------------------------------------------------------- 1 | 2 | 3 | #include "OpenBCI_04.h" 4 | 5 | void OpenBCI::initialize_ads(void) { 6 | ads.initialize(PIN_DRDY, PIN_RST, ADS_SS); // adjust here to test daisy module! 7 | } 8 | 9 | void OpenBCI::initialize_accel(void) { 10 | accel.initialize(); 11 | } 12 | 13 | void OpenBCI::enable_accel(void) { 14 | accel.enable_accel(); 15 | } 16 | 17 | void OpenBCI::disable_accel(void){ 18 | accel.disable_accel(); 19 | } 20 | 21 | byte OpenBCI::getAccelID(void){ 22 | return accel.getDeviceID(); 23 | } 24 | 25 | boolean OpenBCI::LIS3DH_DataReady(void){ 26 | return (accel.LIS3DH_DataReady()); 27 | } 28 | 29 | 30 | int OpenBCI::getX(void){ return accel.getX(); } 31 | int OpenBCI::getY(void){ return accel.getY(); } 32 | int OpenBCI::getZ(void){ return accel.getZ(); } 33 | 34 | 35 | 36 | // ADS FUNCTIONS 37 | void OpenBCI::printAllRegisters(void) { 38 | ads.printAllRegisters(); 39 | delay(100); 40 | Serial.println("LIS3DH Registers:"); 41 | delay(100); 42 | accel.readAllRegs(); 43 | } 44 | 45 | void OpenBCI::getADS_ID(void){ 46 | ads.getDeviceID(); 47 | } 48 | 49 | void OpenBCI::activateChannel(byte chan, byte gainCode, byte inputType){ 50 | ads.activateChannel(chan, gainCode, inputType); 51 | } 52 | 53 | void OpenBCI::start_ads(void){ 54 | ads.startADS(); 55 | } 56 | 57 | void OpenBCI::stop_ads(void){ 58 | ads.stopADS(); 59 | } 60 | 61 | void OpenBCI::reset_ads(void){ 62 | ads.resetADS(); 63 | } 64 | 65 | boolean OpenBCI::isDataAvailable(void){ 66 | return ads.isDataAvailable(); 67 | } 68 | 69 | void OpenBCI::updateChannelData(void){ 70 | ads.updateChannelData(); 71 | // channelData = ads.channelData; 72 | } 73 | 74 | void OpenBCI::setSRB1(boolean desired_state){ 75 | ads.setSRB1(desired_state); 76 | } 77 | 78 | -------------------------------------------------------------------------------- /Arduino/OBCI_V3_Debugging/01-FirstCodeFromJoel/OBCI_SD_LOG_05/OpenBCI_04.h: -------------------------------------------------------------------------------- 1 | 2 | 3 | #ifndef _____OpenBCI_04__ 4 | #define _____OpenBCI_04__ 5 | 6 | #include 7 | #include 8 | 9 | #include "ADS1299.h" 10 | #include "LIS3DH.h" 11 | #include "Definitions.h" 12 | 13 | class OpenBCI { 14 | 15 | public: 16 | 17 | ADS1299 ads; 18 | LIS3DH accel; 19 | SdFat card; 20 | 21 | // VARIABLES 22 | long channelData[9]; 23 | 24 | 25 | 26 | // ADS1299 FUNCITONS 27 | void initialize_ads(void); 28 | void printAllRegisters(void); 29 | void activateChannel(byte,byte,byte); 30 | void start_ads(void); 31 | void stop_ads(void); 32 | void reset_ads(void); 33 | boolean isDataAvailable(void); 34 | void updateChannelData(void); 35 | void setSRB1(boolean); 36 | //void printChannelDataAsText(int N, long int sampleNumber); 37 | //void writeChannelDataAsBinary(int N, uint16_t sampleNumber); 38 | //void writeChannelDataAsOpenEEG_P2(long int sampleNumber); 39 | //void setSRB1(boolean desired_state); 40 | void getADS_ID(void); 41 | 42 | // ACCELEROMETER FUNCIONS 43 | void initialize_accel(void); 44 | void disable_accel(void); 45 | void enable_accel(void); 46 | byte getAccelID(void); 47 | boolean LIS3DH_DataReady(void); 48 | int getX(void); 49 | int getY(void); 50 | int getZ(void); 51 | 52 | 53 | 54 | }; 55 | 56 | #endif 57 | -------------------------------------------------------------------------------- /Arduino/OBCI_V3_Debugging/02-OBCI_Stream/OBCI_UNO_streamData_02/ADS1299.h: -------------------------------------------------------------------------------- 1 | 2 | 3 | #ifndef ____ADS1299__ 4 | #define ____ADS1299__ 5 | 6 | #include 7 | #include 8 | #include 9 | #include "pins_arduino.h" 10 | #include "Definitions.h" 11 | 12 | class ADS1299 { 13 | public: 14 | 15 | void initialize(int _DRDY, int _RST, int _CS); 16 | 17 | //ADS1299 SPI Command Definitions (Datasheet, p35) 18 | //System Commands 19 | void WAKEUP(); 20 | void STANDBY(); 21 | void RESET(); 22 | void START(); 23 | void STOP(); 24 | 25 | //Data Read Commands 26 | void RDATAC(); 27 | void SDATAC(); 28 | void RDATA(); 29 | 30 | //Register Read/Write Commands 31 | 32 | byte RREG(byte _address); 33 | void RREGS(byte _address, byte _numRegistersMinusOne); 34 | void WREG(byte _address, byte _value); 35 | void WREGS(byte _address, byte _numRegistersMinusOne); 36 | byte getDeviceID(); 37 | void printRegisterName(byte _address); 38 | void printHex(byte _data); 39 | void updateChannelData(); 40 | 41 | //SPI Transfer function 42 | byte xfer(byte _data); 43 | 44 | int DRDY, CS, RST; // pin numbers for DataRead ChipSelect Reset pins 45 | int DIVIDER; // select SPI SCK frequency 46 | int stat; // used to hold the status register 47 | byte regData [24]; // array is used to mirror register data 48 | long channelData [9]; // array used when reading channel data as ints 49 | byte rawChannelData[24]; // array to hold raw channel data 50 | boolean verbosity; // turn on/off Serial feedback 51 | 52 | void resetADS(void); //reset all the ADS1299's settings. Call however you'd like 53 | void startADS(void); 54 | void stopADS(void); 55 | 56 | 57 | void activateChannel(int N, byte gainCode,byte inputCode); //setup the channel 1-8 58 | void activateChannel(int, byte, byte, boolean); 59 | void deactivateChannel(int N); //disable given channel 1-8 60 | 61 | void configureInternalTestSignal(byte amplitudeCode, byte freqCode); 62 | 63 | boolean isDataAvailable(void); 64 | void writeADSchannelData(void); 65 | void printAllRegisters(void); 66 | void setSRB1(boolean desired_state); 67 | void printDeviceID(void); 68 | 69 | private: 70 | byte old_SPCR; 71 | byte old_SPSR; 72 | boolean _OpenBCI_03; 73 | boolean use_N_inputs; 74 | boolean use_SRB2[OPENBCI_NCHAN]; 75 | boolean isRunning; 76 | boolean use_SRB1(void); 77 | void csLow(); 78 | void csHigh(); 79 | 80 | }; 81 | 82 | #endif 83 | -------------------------------------------------------------------------------- /Arduino/OBCI_V3_Debugging/02-OBCI_Stream/OBCI_UNO_streamData_02/LIS3DH.h: -------------------------------------------------------------------------------- 1 | 2 | 3 | #ifndef ____LIS3DH__ 4 | #define ____LIS3DH__ 5 | 6 | #include 7 | #include 8 | #include 9 | #include "pins_arduino.h" 10 | #include "Definitions.h" 11 | 12 | class LIS3DH { 13 | public: 14 | int axisData[3]; 15 | void initialize(void); 16 | void enable_accel(void); 17 | void disable_accel(void); 18 | byte getDeviceID(void); 19 | byte LIS3DH_read(byte); 20 | void LIS3DH_write(byte,byte); 21 | int LIS3DH_read16(byte); 22 | int getX(void); 23 | int getY(void); 24 | int getZ(void); 25 | boolean LIS3DH_DataReady(void); 26 | void readAllRegs(void); 27 | void writeLIS3DHdata(void); 28 | void LIS3DH_updateAxisData(void); 29 | 30 | private: 31 | void csLow(); 32 | void csHigh(); 33 | int DRDYpinValue; 34 | int lastDRDYpinValue; 35 | 36 | }; 37 | 38 | #endif 39 | -------------------------------------------------------------------------------- /Arduino/OBCI_V3_Debugging/02-OBCI_Stream/OBCI_UNO_streamData_02/OpenBCI_04.cpp: -------------------------------------------------------------------------------- 1 | 2 | 3 | #include "OpenBCI_04.h" 4 | 5 | void OpenBCI::initialize(void){ 6 | initialize_ads(); 7 | initialize_accel(); 8 | } 9 | 10 | void OpenBCI::initialize_ads(void) { 11 | ads.initialize(PIN_DRDY, PIN_RST, ADS_SS); // adjust here to test daisy module! 12 | } 13 | 14 | void OpenBCI::initialize_accel(void) { 15 | accel.initialize(); 16 | } 17 | 18 | void OpenBCI::enable_accel(void) { 19 | accel.enable_accel(); 20 | } 21 | 22 | void OpenBCI::disable_accel(void){ 23 | accel.disable_accel(); 24 | } 25 | 26 | byte OpenBCI::getAccelID(void){ 27 | return accel.getDeviceID(); 28 | } 29 | 30 | boolean OpenBCI::LIS3DH_DataReady(void){ 31 | return (accel.LIS3DH_DataReady()); 32 | } 33 | 34 | void OpenBCI::getAccelData(void){ 35 | accel.LIS3DH_updateAxisData(); 36 | } 37 | 38 | 39 | int OpenBCI::getX(void){ return accel.getX(); } 40 | int OpenBCI::getY(void){ return accel.getY(); } 41 | int OpenBCI::getZ(void){ return accel.getZ(); } 42 | 43 | 44 | 45 | // ADS FUNCTIONS 46 | void OpenBCI::printAllRegisters(void) { 47 | Serial.println("\nADS Registers:"); 48 | ads.printAllRegisters(); 49 | delay(100); 50 | Serial.println("LIS3DH Registers:"); 51 | delay(100); 52 | accel.readAllRegs(); 53 | } 54 | 55 | byte OpenBCI::getADS_ID(void){ 56 | return ads.getDeviceID(); 57 | } 58 | 59 | void OpenBCI::activateChannel(int chan, byte gainCode, byte inputType){ 60 | ads.activateChannel(chan, gainCode, inputType); 61 | } 62 | 63 | void OpenBCI::activateChannel(int chan, byte gainCode, byte inputType, boolean useInBias){ 64 | ads.activateChannel(chan, gainCode, inputType, useInBias); 65 | } 66 | 67 | void OpenBCI::deactivateChannel(int N){ 68 | ads.deactivateChannel(N); 69 | } 70 | 71 | void OpenBCI::startStreaming(void){ 72 | ads.startADS(); 73 | if(useAccel){accel.enable_accel();} 74 | } 75 | 76 | void OpenBCI::stopStreaming(void){ 77 | ads.stopADS(); 78 | accel.disable_accel(); 79 | } 80 | 81 | void OpenBCI::reset_ads(void){ 82 | ads.resetADS(); 83 | } 84 | 85 | boolean OpenBCI::isDataAvailable(void){ 86 | return ads.isDataAvailable(); 87 | } 88 | 89 | void OpenBCI::updateChannelData(void){ 90 | ads.updateChannelData(); 91 | } 92 | 93 | void OpenBCI::setSRB1(boolean desired_state){ 94 | ads.setSRB1(desired_state); 95 | } 96 | 97 | void OpenBCI::writeDataToDongle(byte sampleNumber){ 98 | Serial.write(sampleNumber); // 1 byte 99 | ads.writeADSchannelData(); // 24 bytes 100 | accel.writeLIS3DHdata(); // 6 bytes 101 | } 102 | 103 | //Configure the test signals that can be inernally generated by the ADS1299 104 | void OpenBCI::configureInternalTestSignal(byte amplitudeCode, byte freqCode) 105 | { 106 | ads.configureInternalTestSignal(amplitudeCode, freqCode); 107 | } 108 | 109 | -------------------------------------------------------------------------------- /Arduino/OBCI_V3_Debugging/02-OBCI_Stream/OBCI_UNO_streamData_02/OpenBCI_04.h: -------------------------------------------------------------------------------- 1 | 2 | 3 | #ifndef _____OpenBCI_04__ 4 | #define _____OpenBCI_04__ 5 | 6 | #include 7 | #include 8 | 9 | #include "ADS1299.h" 10 | #include "LIS3DH.h" 11 | #include "Definitions.h" 12 | 13 | class OpenBCI { 14 | 15 | public: 16 | 17 | ADS1299 ads; 18 | LIS3DH accel; 19 | // SdFat card; 20 | ADS1299 daisy; 21 | 22 | // VARIABLES 23 | long channelData[9]; 24 | boolean useAccel; 25 | int outputType; // we have a few output types 26 | 27 | // BOARD WIDE FUNCTIONS 28 | void initialize(void); 29 | void writeDataToDongle(byte); 30 | void startStreaming(void); 31 | void stopStreaming(void); 32 | 33 | // ADS1299 FUNCITONS 34 | void initialize_ads(void); 35 | void printAllRegisters(void); 36 | void activateChannel(int,byte,byte); 37 | void activateChannel(int,byte,byte,boolean); 38 | void deactivateChannel(int); 39 | void configureInternalTestSignal(byte,byte); 40 | void reset_ads(void); 41 | boolean isDataAvailable(void); 42 | void updateChannelData(void); 43 | void setSRB1(boolean); 44 | byte getADS_ID(void); 45 | 46 | // ACCELEROMETER FUNCIONS 47 | void initialize_accel(void); 48 | void disable_accel(void); 49 | void enable_accel(void); 50 | byte getAccelID(void); 51 | void getAccelData(void); 52 | boolean LIS3DH_DataReady(void); 53 | int getX(void); 54 | int getY(void); 55 | int getZ(void); 56 | 57 | 58 | 59 | }; 60 | 61 | #endif 62 | -------------------------------------------------------------------------------- /Arduino/OBCI_V3_Debugging/02-OBCI_Stream/OBCI_UNO_streamFakeData/UNO_OBCI_streamFakeData.ino: -------------------------------------------------------------------------------- 1 | /* 2 | This sketch is written for OBCI_V3 hardware. It sends dummy data for testing through-put. 3 | 4 | UNO waits to receive 'b' then sends a string of dummy data 5 | sampleCounter: 1 byte 6 | dummy ADS data: 8x3 bytes 7 | dummy accel data 3x2 bytes 8 | 31 bytes all day 9 | 10 | Dummy data transfer is stopped when UNO receives 's' 11 | 12 | When not streamingData, UNO echos bytes received 13 | 14 | 15 | 16 | */ 17 | 18 | const int dataLength = 31; 19 | char dummyData[dataLength] = { // use ascii hex for verbosity 20 | 'a','1','2','3','4','5','6','7','8','9','A','B','C','D','E','F', 21 | '1','2','3','4','5','6','7','8','9','A','B','C','D','E','F' 22 | }; 23 | 24 | char sampleCounter = 'a'; // sample counter 25 | boolean streamingData = false; // streamingData flag is set when 'b' is received 26 | 27 | unsigned long timeBetweenSamples; // used to generate sample freqeuncy 28 | unsigned long benchWriteTime = 0; // ditto 29 | 30 | const int ADS_SS = 10; // all the slave selects on 8bit OBCI board 31 | const int DAISY_SS = 7; 32 | const int SD_SS = 6; 33 | const int LIS3DH_SS = 5; 34 | const int ADS_RST = 9; 35 | 36 | void setup() { 37 | Serial.begin(115200); 38 | 39 | pinMode(SD_SS, OUTPUT); digitalWrite(SD_SS, HIGH); // disable the slaves 40 | pinMode(DAISY_SS,OUTPUT); digitalWrite(DAISY_SS,HIGH); 41 | pinMode(ADS_SS,OUTPUT); digitalWrite(ADS_SS,HIGH); 42 | pinMode(LIS3DH_SS,OUTPUT); digitalWrite(LIS3DH_SS,HIGH); 43 | pinMode(ADS_RST,OUTPUT); digitalWrite(ADS_RST,LOW); // put the ADS in reset for fun 44 | delay(500); 45 | Serial.println("send 'b' to start send 's' to stop"); 46 | } 47 | 48 | void loop() { 49 | 50 | if(streamingData){ // receive 'b' on serial to set this 51 | benchWriteTime = millis(); // start bench mark timer 52 | dummyData[0] = sampleCounter; // update sampleCounter to send 53 | for (int i=0; i 'z'){sampleCounter = 'a';} // roll-over sampleCounter 58 | benchWriteTime = millis() - benchWriteTime; // stop bench mark timer 59 | timeBetweenSamples = 4000 - benchWriteTime; // set sample frequency 60 | delayMicroseconds(timeBetweenSamples); 61 | } 62 | 63 | } 64 | 65 | void serialEvent(){ 66 | char token = Serial.read(); 67 | 68 | switch (token) { 69 | case 'b': 70 | streamingData = true; 71 | break; 72 | case 's': 73 | streamingData = false; 74 | break; 75 | 76 | default: 77 | break; 78 | } 79 | 80 | if(!streamingData){ // echo serial 81 | Serial.print("got the "); 82 | Serial.println(token); 83 | } 84 | 85 | 86 | } 87 | 88 | -------------------------------------------------------------------------------- /Arduino/OBCI_V3_Debugging/02-OBCI_Stream/OBCI_streamRealData/ADS1299.h: -------------------------------------------------------------------------------- 1 | 2 | 3 | #ifndef ____ADS1299__ 4 | #define ____ADS1299__ 5 | 6 | #include 7 | #include 8 | #include 9 | #include "pins_arduino.h" 10 | #include "Definitions.h" 11 | 12 | class ADS1299 { 13 | public: 14 | 15 | void initialize(int _DRDY, int _RST, int _CS); 16 | 17 | //ADS1299 SPI Command Definitions (Datasheet, p35) 18 | //System Commands 19 | void WAKEUP(); 20 | void STANDBY(); 21 | void RESET(); 22 | void START(); 23 | void STOP(); 24 | 25 | //Data Read Commands 26 | void RDATAC(); 27 | void SDATAC(); 28 | void RDATA(); 29 | 30 | //Register Read/Write Commands 31 | 32 | byte RREG(byte _address); 33 | void RREGS(byte _address, byte _numRegistersMinusOne); 34 | void WREG(byte _address, byte _value); 35 | void WREGS(byte _address, byte _numRegistersMinusOne); 36 | byte getDeviceID(); 37 | void printRegisterName(byte _address); 38 | void printHex(byte _data); 39 | void updateChannelData(); 40 | 41 | //SPI Transfer function 42 | byte xfer(byte _data); 43 | 44 | int DRDY, CS, RST; // pin numbers for DataRead ChipSelect Reset pins 45 | int DIVIDER; // select SPI SCK frequency 46 | int stat; // used to hold the status register 47 | byte regData[24]; // array is used to mirror register data 48 | byte rawChannelData[24]; // place to store the raw bytes received from the ADS1299 49 | long channelData [9]; // array used when reading channel data 50 | boolean verbosity; // turn on/off Serial feedback 51 | 52 | void resetADS(void); //reset all the ADS1299's settings. Call however you'd like 53 | void startADS(void); 54 | void stopADS(void); 55 | 56 | 57 | void activateChannel(int N, byte gainCode,byte inputCode); //setup the channel 1-8 58 | void activateChannel(int, byte, byte, boolean); 59 | void deactivateChannel(int N); //disable given channel 1-8 60 | 61 | void configureInternalTestSignal(byte amplitudeCode, byte freqCode); 62 | 63 | boolean isDataAvailable(void); 64 | void printChannelDataAsText(int N, long int sampleNumber); 65 | void writeChannelDataAsBinary(int N, uint16_t sampleNumber); 66 | void writeChannelDataAsOpenEEG_P2(long int sampleNumber); 67 | void printAllRegisters(void); 68 | void setSRB1(boolean desired_state); 69 | void printDeviceID(void); 70 | 71 | 72 | private: 73 | byte old_SPCR; 74 | byte old_SPSR; 75 | boolean _OpenBCI_03; 76 | boolean use_N_inputs; 77 | boolean use_SRB2[OPENBCI_NCHAN]; 78 | boolean isRunning; 79 | boolean use_SRB1(void); 80 | void csLow(); 81 | void csHigh(); 82 | 83 | }; 84 | 85 | #endif 86 | -------------------------------------------------------------------------------- /Arduino/OBCI_V3_Debugging/02-OBCI_Stream/OBCI_streamRealData/LIS3DH.cpp: -------------------------------------------------------------------------------- 1 | 2 | 3 | #include "LIS3DH.h" 4 | 5 | void LIS3DH::initialize(){ // ADD ABILITY TO SET RESOLUTION 6 | pinMode(LIS3DH_SS,OUTPUT); digitalWrite(LIS3DH_SS,HIGH); 7 | pinMode(LIS3DH_DRDY,INPUT); // setup dataReady interupt from accelerometer 8 | DRDYpinValue = lastDRDYpinValue = digitalRead(LIS3DH_DRDY); // take a reading to seed these variables 9 | LIS3DH_write(TMP_CFG_REG, 0x40); // disable ADC inputs, enable temperature sensor 10 | LIS3DH_write(CTRL_REG4, 0x18); // set scale to +/-4g, high resolution 11 | LIS3DH_write(CTRL_REG3, 0x10); // enable DRDY1 on INT1 (tied to Arduino pin3, LIS3DH_DRDY) 12 | } 13 | 14 | void LIS3DH::enable_accel(){ // ADD ABILITY TO SET FREQUENCY 15 | LIS3DH_write(CTRL_REG1, 0x37); // set freq to 50Hz and enable all axis in normal mode 16 | } 17 | 18 | void LIS3DH::disable_accel(){ 19 | LIS3DH_write(CTRL_REG1, 0x08); // power down, low power mode 20 | } 21 | 22 | byte LIS3DH::getDeviceID(){ 23 | return LIS3DH_read(0x0F); 24 | } 25 | 26 | boolean LIS3DH::LIS3DH_DataReady(){ 27 | boolean r = false; 28 | DRDYpinValue = digitalRead(LIS3DH_DRDY); // take a look at LIS3DH_DRDY pin 29 | if(DRDYpinValue != lastDRDYpinValue){ // if the value has changed since last looking 30 | if(DRDYpinValue == HIGH){ // see if this is the rising edge 31 | r = true; // if so, there is fresh data! 32 | } 33 | lastDRDYpinValue = DRDYpinValue; // keep track of the changing pin 34 | } 35 | return r; 36 | } 37 | 38 | byte LIS3DH::LIS3DH_read(byte reg){ 39 | reg |= READ_REG; // add the READ_REG bit 40 | csLow(); // take spi 41 | SPI.transfer(reg); // send reg to read 42 | byte inByte = SPI.transfer(0x00); // retrieve data 43 | csHigh(); // release spi 44 | return inByte; 45 | } 46 | 47 | void LIS3DH::LIS3DH_write(byte reg, byte value){ 48 | csLow(); // take spi 49 | SPI.transfer(reg); // send reg to write 50 | SPI.transfer(value); // write value 51 | csHigh(); // release spi 52 | } 53 | 54 | int LIS3DH::LIS3DH_read16(byte reg){ // use for reading axis data. 55 | int inData; 56 | reg |= READ_REG | READ_MULTI; // add the READ_REG and READ_MULTI bits 57 | csLow(); // take spi 58 | SPI.transfer(reg); // send reg to start reading from 59 | inData = SPI.transfer(0x00) | (SPI.transfer(0x00) << 8); // get the data and arrange it 60 | csHigh(); // release spi 61 | return inData; 62 | } 63 | 64 | int LIS3DH::getX(){ 65 | return LIS3DH_read16(OUT_X_L); 66 | } 67 | 68 | int LIS3DH::getY(){ 69 | return LIS3DH_read16(OUT_Y_L); 70 | } 71 | 72 | int LIS3DH::getZ(){ 73 | return LIS3DH_read16(OUT_Z_L); 74 | } 75 | 76 | void LIS3DH::readAllRegs(){ 77 | 78 | byte inByte; 79 | 80 | for (int i = STATUS_REG_AUX; i <= WHO_AM_I; i++){ 81 | inByte = LIS3DH_read(i); 82 | Serial.print("0x0");Serial.print(i,HEX); 83 | Serial.print("\t");Serial.println(inByte,HEX); 84 | delay(20); 85 | } 86 | Serial.println(); 87 | 88 | for (int i = OUT_X_L; i <= INT1_DURATION; i++){ 89 | inByte = LIS3DH_read(i); 90 | Serial.print("0x");Serial.print(i,HEX); 91 | Serial.print("\t");Serial.println(inByte,HEX); 92 | delay(20); 93 | } 94 | Serial.println(); 95 | 96 | for (int i = CLICK_CFG; i <= TIME_WINDOW; i++){ 97 | inByte = LIS3DH_read(i); 98 | Serial.print("0x");Serial.print(i,HEX); 99 | Serial.print("\t");Serial.println(inByte,HEX); 100 | delay(20); 101 | } 102 | 103 | } 104 | 105 | void LIS3DH::csLow(void) 106 | { 107 | SPI.setDataMode(SPI_MODE3); // switch modes 108 | digitalWrite(LIS3DH_SS, LOW); // drop Slave Select 109 | } 110 | 111 | void LIS3DH::csHigh(void) 112 | { 113 | digitalWrite(LIS3DH_SS, HIGH); // raise select 114 | SPI.setDataMode(SPI_MODE0); 115 | } 116 | -------------------------------------------------------------------------------- /Arduino/OBCI_V3_Debugging/02-OBCI_Stream/OBCI_streamRealData/LIS3DH.h: -------------------------------------------------------------------------------- 1 | 2 | 3 | #ifndef ____LIS3DH__ 4 | #define ____LIS3DH__ 5 | 6 | #include 7 | #include 8 | #include 9 | #include "pins_arduino.h" 10 | #include "Definitions.h" 11 | 12 | class LIS3DH { 13 | public: 14 | void initialize(void); 15 | void enable_accel(void); 16 | void disable_accel(void); 17 | byte getDeviceID(void); 18 | byte LIS3DH_read(byte); 19 | void LIS3DH_write(byte,byte); 20 | int LIS3DH_read16(byte); 21 | int getX(void); 22 | int getY(void); 23 | int getZ(void); 24 | boolean LIS3DH_DataReady(void); 25 | void readAllRegs(void); 26 | 27 | private: 28 | void csLow(); 29 | void csHigh(); 30 | int DRDYpinValue; 31 | int lastDRDYpinValue; 32 | 33 | }; 34 | 35 | #endif 36 | -------------------------------------------------------------------------------- /Arduino/OBCI_V3_Debugging/02-OBCI_Stream/OBCI_streamRealData/OpenBCI_04.cpp: -------------------------------------------------------------------------------- 1 | 2 | 3 | #include "OpenBCI_04.h" 4 | 5 | void OpenBCI::initialize_ads(void) { 6 | ads.initialize(PIN_DRDY, PIN_RST, ADS_SS); // adjust here to test daisy module! 7 | } 8 | 9 | void OpenBCI::initialize_accel(void) { 10 | accel.initialize(); 11 | } 12 | 13 | void OpenBCI::enable_accel(void) { 14 | accel.enable_accel(); 15 | } 16 | 17 | void OpenBCI::disable_accel(void){ 18 | accel.disable_accel(); 19 | } 20 | 21 | byte OpenBCI::getAccelID(void){ 22 | return accel.getDeviceID(); 23 | } 24 | 25 | boolean OpenBCI::LIS3DH_DataReady(void){ 26 | return (accel.LIS3DH_DataReady()); 27 | } 28 | 29 | 30 | int OpenBCI::getX(void){ return accel.getX(); } 31 | int OpenBCI::getY(void){ return accel.getY(); } 32 | int OpenBCI::getZ(void){ return accel.getZ(); } 33 | 34 | 35 | 36 | // ADS FUNCTIONS 37 | void OpenBCI::printAllRegisters(void) { 38 | ads.printAllRegisters(); 39 | delay(100); 40 | Serial.println("LIS3DH Registers:"); 41 | delay(100); 42 | accel.readAllRegs(); 43 | } 44 | 45 | void OpenBCI::getADS_ID(void){ 46 | ads.getDeviceID(); 47 | } 48 | 49 | void OpenBCI::activateChannel(byte chan, byte gainCode, byte inputType){ 50 | ads.activateChannel(chan, gainCode, inputType); 51 | } 52 | 53 | void OpenBCI::start_ads(void){ 54 | ads.startADS(); 55 | } 56 | 57 | void OpenBCI::stop_ads(void){ 58 | ads.stopADS(); 59 | } 60 | 61 | void OpenBCI::reset_ads(void){ 62 | ads.resetADS(); 63 | } 64 | 65 | boolean OpenBCI::isDataAvailable(void){ 66 | return ads.isDataAvailable(); 67 | } 68 | 69 | void OpenBCI::updateChannelData(void){ 70 | ads.updateChannelData(); 71 | // channelData = ads.channelData; 72 | } 73 | 74 | void OpenBCI::setSRB1(boolean desired_state){ 75 | ads.setSRB1(desired_state); 76 | } 77 | 78 | 79 | -------------------------------------------------------------------------------- /Arduino/OBCI_V3_Debugging/02-OBCI_Stream/OBCI_streamRealData/OpenBCI_04.h: -------------------------------------------------------------------------------- 1 | 2 | 3 | #ifndef _____OpenBCI_04__ 4 | #define _____OpenBCI_04__ 5 | 6 | #include 7 | #include 8 | 9 | #include "ADS1299.h" 10 | #include "LIS3DH.h" 11 | #include "Definitions.h" 12 | 13 | class OpenBCI { 14 | 15 | public: 16 | 17 | ADS1299 ads; 18 | LIS3DH accel; 19 | //SdFat card; 20 | 21 | // VARIABLES 22 | long channelData[9]; 23 | 24 | 25 | 26 | // ADS1299 FUNCITONS 27 | void initialize_ads(void); 28 | void printAllRegisters(void); 29 | void activateChannel(byte,byte,byte); 30 | void start_ads(void); 31 | void stop_ads(void); 32 | void reset_ads(void); 33 | boolean isDataAvailable(void); 34 | void updateChannelData(void); 35 | void setSRB1(boolean); 36 | //void printChannelDataAsText(int N, long int sampleNumber); 37 | //void writeChannelDataAsBinary(int N, uint16_t sampleNumber); 38 | //void writeChannelDataAsOpenEEG_P2(long int sampleNumber); 39 | //void setSRB1(boolean desired_state); 40 | void getADS_ID(void); 41 | 42 | 43 | // ACCELEROMETER FUNCIONS 44 | void initialize_accel(void); 45 | void disable_accel(void); 46 | void enable_accel(void); 47 | byte getAccelID(void); 48 | boolean LIS3DH_DataReady(void); 49 | int getX(void); 50 | int getY(void); 51 | int getZ(void); 52 | 53 | 54 | 55 | }; 56 | 57 | #endif 58 | -------------------------------------------------------------------------------- /Arduino/OBCI_V3_Debugging/03-ThirdCodeFromJoel/OBCI_8bit_streamData_Filter/ADS1299.h: -------------------------------------------------------------------------------- 1 | 2 | 3 | #ifndef ____ADS1299__ 4 | #define ____ADS1299__ 5 | 6 | #include 7 | #include 8 | #include 9 | #include "pins_arduino.h" 10 | #include "Definitions.h" 11 | 12 | class ADS1299 { 13 | public: 14 | 15 | void initialize(int _DRDY, int _RST, int _CS); 16 | 17 | //ADS1299 SPI Command Definitions (Datasheet, p35) 18 | //System Commands 19 | void WAKEUP(); 20 | void STANDBY(); 21 | void RESET(); 22 | void START(); 23 | void STOP(); 24 | 25 | //Data Read Commands 26 | void RDATAC(); 27 | void SDATAC(); 28 | void RDATA(); 29 | 30 | //Register Read/Write Commands 31 | 32 | byte RREG(byte _address); 33 | void RREGS(byte _address, byte _numRegistersMinusOne); 34 | void WREG(byte _address, byte _value); 35 | void WREGS(byte _address, byte _numRegistersMinusOne); 36 | byte getDeviceID(); 37 | void printRegisterName(byte _address); 38 | void printHex(byte _data); 39 | void updateChannelData(); 40 | 41 | //SPI Transfer function 42 | byte xfer(byte _data); 43 | 44 | int DRDY, CS, RST; // pin numbers for DataRead ChipSelect Reset pins 45 | int DIVIDER; // select SPI SCK frequency 46 | int stat; // used to hold the status register 47 | byte regData [24]; // array is used to mirror register data 48 | long channelData [9]; // array used when reading channel data as ints 49 | byte bit24ChannelData[24]; // array to hold raw channel data 50 | boolean verbosity; // turn on/off Serial feedback 51 | 52 | void resetADS(void); //reset all the ADS1299's settings. Call however you'd like 53 | void startADS(void); 54 | void stopADS(void); 55 | 56 | 57 | void activateChannel(int N, byte gainCode,byte inputCode); //setup the channel 1-8 58 | void activateChannel(int, byte, byte, boolean); 59 | void deactivateChannel(int N); //disable given channel 1-8 60 | 61 | void configureInternalTestSignal(byte amplitudeCode, byte freqCode); 62 | 63 | boolean isDataAvailable(void); 64 | void writeADSchannelData(void); 65 | void printAllRegisters(void); 66 | void setSRB1(boolean desired_state); 67 | void printDeviceID(void); 68 | 69 | private: 70 | byte old_SPCR; 71 | byte old_SPSR; 72 | boolean _OpenBCI_03; 73 | boolean use_N_inputs; 74 | boolean use_SRB2[OPENBCI_NCHAN]; 75 | boolean isRunning; 76 | boolean use_SRB1(void); 77 | void csLow(); 78 | void csHigh(); 79 | 80 | }; 81 | 82 | #endif 83 | -------------------------------------------------------------------------------- /Arduino/OBCI_V3_Debugging/03-ThirdCodeFromJoel/OBCI_8bit_streamData_Filter/LIS3DH.h: -------------------------------------------------------------------------------- 1 | 2 | 3 | #ifndef ____LIS3DH__ 4 | #define ____LIS3DH__ 5 | 6 | #include 7 | #include 8 | #include 9 | #include "pins_arduino.h" 10 | #include "Definitions.h" 11 | 12 | class LIS3DH { 13 | public: 14 | int axisData[3]; 15 | void initialize(void); 16 | void enable_accel(void); 17 | void disable_accel(void); 18 | byte getDeviceID(void); 19 | byte LIS3DH_read(byte); 20 | void LIS3DH_write(byte,byte); 21 | int LIS3DH_read16(byte); 22 | int getX(void); 23 | int getY(void); 24 | int getZ(void); 25 | boolean LIS3DH_DataReady(void); 26 | void readAllRegs(void); 27 | void writeLIS3DHdata(void); 28 | void LIS3DH_updateAxisData(void); 29 | 30 | private: 31 | void csLow(); 32 | void csHigh(); 33 | int DRDYpinValue; 34 | int lastDRDYpinValue; 35 | 36 | }; 37 | 38 | #endif 39 | -------------------------------------------------------------------------------- /Arduino/OBCI_V3_Debugging/03-ThirdCodeFromJoel/OBCI_8bit_streamData_Filter/OpenBCI_04.cpp: -------------------------------------------------------------------------------- 1 | 2 | 3 | #include "OpenBCI_04.h" 4 | 5 | void OpenBCI::initialize(void){ 6 | initialize_ads(); 7 | initialize_accel(); 8 | } 9 | 10 | void OpenBCI::initialize_ads(void) { 11 | ads.initialize(PIN_DRDY, PIN_RST, ADS_SS); // adjust here to test daisy module! 12 | } 13 | 14 | void OpenBCI::initialize_accel(void) { 15 | accel.initialize(); 16 | } 17 | 18 | void OpenBCI::enable_accel(void) { 19 | accel.enable_accel(); 20 | } 21 | 22 | void OpenBCI::disable_accel(void){ 23 | accel.disable_accel(); 24 | } 25 | 26 | byte OpenBCI::getAccelID(void){ 27 | return accel.getDeviceID(); 28 | } 29 | 30 | boolean OpenBCI::LIS3DH_DataReady(void){ 31 | return (accel.LIS3DH_DataReady()); 32 | } 33 | 34 | void OpenBCI::getAccelData(void){ 35 | accel.LIS3DH_updateAxisData(); 36 | } 37 | 38 | 39 | int OpenBCI::getX(void){ return accel.getX(); } 40 | int OpenBCI::getY(void){ return accel.getY(); } 41 | int OpenBCI::getZ(void){ return accel.getZ(); } 42 | 43 | 44 | 45 | // ADS FUNCTIONS 46 | void OpenBCI::printAllRegisters(void) { 47 | Serial.println("\nADS Registers:"); 48 | ads.printAllRegisters(); 49 | delay(100); 50 | Serial.println("LIS3DH Registers:"); 51 | delay(100); 52 | accel.readAllRegs(); 53 | } 54 | 55 | byte OpenBCI::getADS_ID(void){ 56 | return ads.getDeviceID(); 57 | } 58 | 59 | void OpenBCI::activateChannel(int chan, byte gainCode, byte inputType){ 60 | ads.activateChannel(chan, gainCode, inputType); 61 | } 62 | 63 | void OpenBCI::activateChannel(int chan, byte gainCode, byte inputType, boolean useInBias){ 64 | ads.activateChannel(chan, gainCode, inputType, useInBias); 65 | } 66 | 67 | void OpenBCI::deactivateChannel(int N){ 68 | ads.deactivateChannel(N); 69 | } 70 | 71 | void OpenBCI::startStreaming(void){ 72 | ads.startADS(); 73 | if(useAccel){accel.enable_accel();} 74 | } 75 | 76 | void OpenBCI::stopStreaming(void){ 77 | ads.stopADS(); 78 | accel.disable_accel(); 79 | } 80 | 81 | void OpenBCI::reset_ads(void){ 82 | ads.resetADS(); 83 | } 84 | 85 | boolean OpenBCI::isDataAvailable(void){ 86 | return ads.isDataAvailable(); 87 | } 88 | 89 | void OpenBCI::updateChannelData(void){ 90 | ads.updateChannelData(); 91 | } 92 | 93 | void OpenBCI::setSRB1(boolean desired_state){ 94 | ads.setSRB1(desired_state); 95 | } 96 | 97 | void OpenBCI::writeDataToDongle(byte sampleNumber){ 98 | Serial.write(sampleNumber); // 1 byte 99 | ads.writeADSchannelData(); // 24 bytes 100 | accel.writeLIS3DHdata(); // 6 bytes 101 | } 102 | 103 | long OpenBCI::getChannel(int chan){ 104 | return ads.channelData[chan]; 105 | } 106 | 107 | 108 | void OpenBCI::putChannel(int chan, long val){ 109 | ads.channelData[chan] = val; 110 | } 111 | 112 | void OpenBCI::update24bitData(){ 113 | int indexCounter = 0; 114 | for(int i=0; i<8; i++){ 115 | for(int j=2; j>=0; j--){ 116 | ads.bit24ChannelData[indexCounter] = byte(ads.channelData[i] >> (8*j)); 117 | indexCounter++; 118 | } 119 | } 120 | } 121 | 122 | //Configure the test signals that can be inernally generated by the ADS1299 123 | void OpenBCI::configureInternalTestSignal(byte amplitudeCode, byte freqCode) 124 | { 125 | ads.configureInternalTestSignal(amplitudeCode, freqCode); 126 | } 127 | 128 | -------------------------------------------------------------------------------- /Arduino/OBCI_V3_Debugging/03-ThirdCodeFromJoel/OBCI_8bit_streamData_Filter/OpenBCI_04.h: -------------------------------------------------------------------------------- 1 | 2 | 3 | #ifndef _____OpenBCI_04__ 4 | #define _____OpenBCI_04__ 5 | 6 | #include 7 | #include 8 | 9 | #include "ADS1299.h" 10 | #include "LIS3DH.h" 11 | #include "Definitions.h" 12 | 13 | class OpenBCI { 14 | 15 | public: 16 | 17 | ADS1299 ads; 18 | LIS3DH accel; 19 | // SdFat card; 20 | ADS1299 daisy; 21 | 22 | // VARIABLES 23 | // long channelData[9]; 24 | boolean useAccel; 25 | int outputType; // we have a few output types 26 | 27 | // BOARD WIDE FUNCTIONS 28 | void initialize(void); 29 | void writeDataToDongle(byte); 30 | void startStreaming(void); 31 | void stopStreaming(void); 32 | 33 | // ADS1299 FUNCITONS 34 | void initialize_ads(void); 35 | void printAllRegisters(void); 36 | void activateChannel(int,byte,byte); 37 | void activateChannel(int,byte,byte,boolean); 38 | void deactivateChannel(int); 39 | void configureInternalTestSignal(byte,byte); 40 | void reset_ads(void); 41 | boolean isDataAvailable(void); 42 | void updateChannelData(void); 43 | void setSRB1(boolean); 44 | byte getADS_ID(void); 45 | long getChannel(int); 46 | void putChannel(int, long); 47 | void update24bitData(void); 48 | 49 | // ACCELEROMETER FUNCIONS 50 | void initialize_accel(void); 51 | void disable_accel(void); 52 | void enable_accel(void); 53 | byte getAccelID(void); 54 | void getAccelData(void); 55 | boolean LIS3DH_DataReady(void); 56 | int getX(void); 57 | int getY(void); 58 | int getZ(void); 59 | 60 | 61 | 62 | }; 63 | 64 | #endif 65 | -------------------------------------------------------------------------------- /Arduino/OBCI_V3_Debugging/UpdatedRFDuinoLibrary/libRFduinoGZLL.a: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/chipaudette/EEGHacker/f72cc121d51fb5ea2f9176ebc0bb821aef05e64e/Arduino/OBCI_V3_Debugging/UpdatedRFDuinoLibrary/libRFduinoGZLL.a -------------------------------------------------------------------------------- /Arduino/OBCI_V3_Debugging/UpdatedRFDuinoLibrary/readme.txt: -------------------------------------------------------------------------------- 1 | Put this file in: 2 | 3 | Arduino_1.5.x\hardware\arduino\RFduino\variants\RFduino 4 | 5 | -------------------------------------------------------------------------------- /Arduino/ReadPhotocellResistance/ReadPhotocellResistance.ino: -------------------------------------------------------------------------------- 1 | /* 2 | Program: ReadPhotoCellResistance 3 | By: Chip Audette May 2014 4 | Based on: Arduino example program "AnalogInOutSerial" 5 | 6 | The Circuit: Assumes the photocell is wired with one end plugged into +5V 7 | and the other end has a 10K resistor to ground. The Arduino AnalogIn pin 8 | is measuring at the junction between the photocell and the resistor. 9 | 10 | This example code is in the public domain. 11 | */ 12 | 13 | const int analogInPin = A0; // Analog input pin that the potentiometer is attached to 14 | int sensorValue = 0; // value read from the pot 15 | 16 | float V_ref = 5.000; //this is the voltage reference of the Arduino ADC 17 | float V_total = 5.000; //this is the voltage that we're applying to the photocell+resistor 18 | float R_bot_ohm = 10000.0; //this is the value of the resistor 19 | 20 | void setup() { 21 | // initialize serial communications at 9600 bps: 22 | Serial.begin(115200); 23 | 24 | // set the analog pin as an input 25 | pinMode(analogInPin,INPUT); 26 | } 27 | 28 | void loop() { 29 | // read the analog in value: 30 | sensorValue = analogRead(analogInPin); 31 | 32 | // compute the voltage at the analog input pin 33 | float V= ((float)sensorValue)/((float)1023)*V_ref; 34 | 35 | // compute the voltage across the photocell 36 | float R_ohm = R_bot_ohm*(V_total / V) - R_bot_ohm; 37 | 38 | // print the results to the serial monitor: 39 | Serial.print("sensor = " ); 40 | Serial.print(sensorValue); 41 | Serial.print("\t, R (kOhm) = "); 42 | Serial.println(R_ohm/1000.0); 43 | 44 | // wait XXX milliseconds before the next loop 45 | delay(1000); 46 | } 47 | -------------------------------------------------------------------------------- /Arduino/TestHexBugController/TestHexBugController.ino: -------------------------------------------------------------------------------- 1 | /* 2 | TextHexBugController 3 | 4 | Created: Chip Audette, May 2014 5 | http://eeghacker.blogspot.com 6 | 7 | Purpose: This code assumes that you've hacked the IR remote control of a hex bug 8 | to allow the Arduino to "push" the remote control's buttons. You issue serial commands 9 | from the PC, which are received by the Arduino, when then interacts with the remote control. 10 | 11 | Hex Bug IR Remote: There are four buttons on the Hex Bug IR remote. The high side of 12 | each button attached to the remote control's microcontroller, which must use a pull-up 13 | to hold the pin at 3.3V. The low side of each button is connected to ground so that, 14 | when the button is pressed, the pin goes low by conducting through the now-closed button. 15 | 16 | Hack: I soldered a wire to the high side of each button and to the remote's "ground". 17 | I connect these wires to the Arduino. 18 | 19 | Software Approach: Normally, the Arduino pins are set to "INPUT" because that makes 20 | the pins hae a high input impedance, which means that they do not affect the voltage 21 | at the pin to the microcontroller. When I want the Arduino to "push" one of the 22 | buttons for me, I command the Arduino to change the pin to "OUTPUT" and "LOW", 23 | which gives a low-resistance path to ground. As a result, it pulls the remote's 24 | microcontroller pin low, which makes the remote think that a button was pressed. 25 | 26 | License: MIT License 2014 27 | 28 | */ 29 | 30 | #define PIN_GROUND A1 31 | int pins[]= {A2, A3, A4, A5}; 32 | #define NPINS 4 33 | #define COMMAND_FOREWARD 3 34 | #define COMMAND_LEFT 1 35 | #define COMMAND_RIGHT 2 36 | #define COMMAND_FIRE 0 37 | 38 | volatile char inChar; 39 | unsigned long lastCommand_millis = 0; 40 | int commndDuration_millis = 500; 41 | 42 | 43 | void setup() { 44 | // initialize serial: 45 | Serial.begin(115200); 46 | 47 | // print help 48 | Serial.println("TestHexBugController: starting..."); 49 | Serial.println("Commands Include: "); 50 | Serial.println(" 'P' = Forward"); 51 | Serial.println(" '{' = Left"); 52 | Serial.println(" '}' = Right"); 53 | Serial.println(" '|' = Fire"); 54 | 55 | //initialize the pins 56 | pinMode(PIN_GROUND,OUTPUT); digitalWrite(PIN_GROUND,LOW); 57 | stopAllPins(); 58 | } 59 | 60 | void stopAllPins() { 61 | //stopping all pins means putting them into a high impedance state 62 | //Serial.println("Stopping All Pins..."); 63 | for (int Ipin=0; Ipin < NPINS; Ipin++) { 64 | digitalWrite(pins[Ipin],LOW); 65 | pinMode(pins[Ipin],INPUT); 66 | } 67 | } 68 | 69 | void loop() { 70 | // print the string when a newline arrives: 71 | if (millis() > lastCommand_millis+commndDuration_millis) { 72 | lastCommand_millis = millis()+10000; //don't do this branch for a while 73 | stopAllPins(); 74 | } 75 | } 76 | 77 | void issueCommand(int command_pin_ind) { 78 | if (command_pin_ind < NPINS) { 79 | stopAllPins(); 80 | pinMode(pins[command_pin_ind],OUTPUT); 81 | digitalWrite(pins[command_pin_ind],LOW); 82 | lastCommand_millis = millis(); //time the command was received 83 | } 84 | } 85 | 86 | 87 | /* 88 | SerialEvent occurs whenever a new data comes in the 89 | hardware serial RX. This routine is run between each 90 | time loop() runs, so using delay inside loop can delay 91 | response. Multiple bytes of data may be available. 92 | */ 93 | void serialEvent() { 94 | while (Serial.available()) { 95 | char inChar = (char)Serial.read(); 96 | Serial.print("Received "); Serial.println(inChar); 97 | switch (inChar) { 98 | case 'P': 99 | issueCommand(COMMAND_FOREWARD); break; 100 | case '{': 101 | issueCommand(COMMAND_LEFT); break; 102 | case '}': 103 | issueCommand(COMMAND_RIGHT); break; 104 | case '|': 105 | issueCommand(COMMAND_FIRE); break; 106 | } 107 | } 108 | } 109 | 110 | 111 | -------------------------------------------------------------------------------- /Arduino/TestQuadCopterController/MCP42XXX.cpp: -------------------------------------------------------------------------------- 1 | 2 | #include "MCP42XXX.h" 3 | 4 | 5 | MCP42XXX::MCP42XXX(int SSpin,boolean start_SPI_bus, int chanPerDevice) { 6 | chan_per_device= chanPerDevice; 7 | 8 | //configure the slave select pin on the Arduino (ie, the pin that connects to *CS) 9 | SS_pin = SSpin; 10 | digitalWrite(SS_pin,HIGH); 11 | pinMode(SS_pin, OUTPUT); 12 | 13 | //start the SPI bus 14 | if (start_SPI_bus) { 15 | SPI.begin(); 16 | SPI.setDataMode(SPI_MODE0); 17 | SPI.setBitOrder(MSBFIRST); 18 | } 19 | } 20 | 21 | //Assume that the values are chan 0 then chan 1. 22 | //If more values are included assume it is for additional daisy-chained devices. 23 | //Assume the values for the last device are first and the values for the first deivce are last 24 | void MCP42XXX::setValues(byte values[], int n_values) { 25 | 26 | //prepare command byte 27 | byte command; 28 | int ind; 29 | int n_devices = n_values / chan_per_device; 30 | for (int Ichan = 0; Ichan < chan_per_device; Ichan++) { 31 | //set chip select low to begin data transfer for this set of channels 32 | // Serial.println(F("MCP42XXX: setting SS_pin LOW")); 33 | digitalWrite(SS_pin,LOW); 34 | delayMicroseconds(10); 35 | 36 | for (int Idevice = 0; Idevice < n_devices; Idevice++) { 37 | 38 | command = 0b00010000; //write data 39 | if (Ichan==0) { 40 | //potentiometer 0 41 | command = bitSet(command,0); 42 | } else { 43 | //potentiometer 1 44 | command = bitSet(command,1); 45 | } 46 | 47 | //transmit data 48 | ind = (Idevice*chan_per_device)+Ichan; 49 | if (ind < n_values) { 50 | // Serial.print("MCP42XXX: Transfering "); 51 | // Serial.print(command,BIN); 52 | // Serial.print(" "); 53 | // Serial.println(values[ind]); 54 | SPI.transfer(command); 55 | SPI.transfer(values[ind]); 56 | } 57 | } 58 | 59 | //set chip select hight to close the data transfer 60 | // Serial.println(F("MCP42XXX: setting SS_pin HIGH")); 61 | digitalWrite(SS_pin,HIGH); 62 | delayMicroseconds(10); 63 | } 64 | } 65 | 66 | -------------------------------------------------------------------------------- /Arduino/TestQuadCopterController/MCP42XXX.h: -------------------------------------------------------------------------------- 1 | 2 | /* 3 | MCP41XXX / MCP42XXX Dual Digital Poteniometer with SPI Interface. 4 | * 8-Bit Potentiometer 5 | * 41XXX is one channel, 42XXX is two channel and can be daisy chained 6 | * Relies upon the Arduino SPI library 7 | 8 | Created: Chip Audette, Sept 2014 9 | License: MIT 10 | */ 11 | 12 | 13 | #include "Arduino.h" 14 | #include "SPI.h" 15 | 16 | #ifndef MCP42XXX_h 17 | #define MCP42XXX_h 18 | 19 | class MCP42XXX { 20 | public: 21 | MCP42XXX(int SSpin,boolean start_SPI_bus,int chanPerDevice); 22 | void setValues(byte values[], int n_values); //last device first, chan 0 then chan 1 23 | 24 | private: 25 | int SS_pin; 26 | int chan_per_device; 27 | }; 28 | 29 | #endif 30 | -------------------------------------------------------------------------------- /Data/2013-11-01a ECG with V2/SavedData/data_2013-10-28_17-11-44_ECG_V2.mat: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/chipaudette/EEGHacker/f72cc121d51fb5ea2f9176ebc0bb821aef05e64e/Data/2013-11-01a ECG with V2/SavedData/data_2013-10-28_17-11-44_ECG_V2.mat -------------------------------------------------------------------------------- /Data/2013-11-01a ECG with V2/SavedData/data_2013-10-28_17-13-46_ECG_V1.mat: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/chipaudette/EEGHacker/f72cc121d51fb5ea2f9176ebc0bb821aef05e64e/Data/2013-11-01a ECG with V2/SavedData/data_2013-10-28_17-13-46_ECG_V1.mat -------------------------------------------------------------------------------- /Data/2013-11-01a ECG with V2/SavedData/data_2013-11-01_16-16-16.mat: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/chipaudette/EEGHacker/f72cc121d51fb5ea2f9176ebc0bb821aef05e64e/Data/2013-11-01a ECG with V2/SavedData/data_2013-11-01_16-16-16.mat -------------------------------------------------------------------------------- /Data/2013-11-01a ECG with V2/SavedData/data_2013-11-01_16-20-41_V2_allChan_wMarks.mat: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/chipaudette/EEGHacker/f72cc121d51fb5ea2f9176ebc0bb821aef05e64e/Data/2013-11-01a ECG with V2/SavedData/data_2013-11-01_16-20-41_V2_allChan_wMarks.mat -------------------------------------------------------------------------------- /Data/2013-11-01a ECG with V2/SavedData/data_OpenBCI_format.zip: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/chipaudette/EEGHacker/f72cc121d51fb5ea2f9176ebc0bb821aef05e64e/Data/2013-11-01a ECG with V2/SavedData/data_OpenBCI_format.zip -------------------------------------------------------------------------------- /Data/2013-11-01a ECG with V2/exploreSavedData.m: -------------------------------------------------------------------------------- 1 | 2 | %given_amp_counts = 4.5/2.4e-3; 3 | 4 | 5 | pname2 = 'SavedData\'; 6 | fname2 = 'data_2013-10-28_17-13-46_ECG_V1'; 7 | scale_fac_volts_per_count = (4.5/24/2^24); 8 | 9 | 10 | %% load data 11 | data2 = load([pname2 fname2]); %this is scaled to "full scale" (ie +/- 1.0) 12 | fs = data2.fs_Hz; 13 | try 14 | buff_data_FS = data2.buff_data_FS; %should be [-1.0 to +1.0] 15 | catch 16 | buff_data_FS = data2.buff_data; %should be [-1.0 to +1.0] 17 | end 18 | data2_counts = buff_data_FS * 2^(24-1); %this converts back to counts...+/- 2^23 19 | data2_V = data2_counts * scale_fac_volts_per_count; %apply the scale factor to get "volts" 20 | 21 | %% analyze data 22 | mean_data2_V = mean(data2_V); 23 | median_data2_V = median(data2_V); 24 | std_data2_V = std(data2_V); 25 | spread_data2_V = diff(xpercentile(data2_V,0.5+(0.68-0.5)*[-1 1]))/2; 26 | %spread_data2_V = median(spread_data2_V)*ones(size(spread_data2_V)); 27 | 28 | %% plot data 29 | %len = min([length(data1_V) length(data2_V) length(data3_V)]); 30 | %len = size(data2_V; 31 | t_sec = ([1:size(data2_V,1)]-1)/fs; 32 | n_per_page = 3;loc1 = [1 2 3];loc2 = [4 5 6];nrow = 2; ncol=3; 33 | count=0; 34 | for Ichan=1:size(data2_V,2); 35 | count = rem(count,n_per_page); 36 | if count==0; 37 | figure;setFigureTallestWidest; 38 | end 39 | count = count+1; 40 | 41 | %time-domain plot 42 | subplot(nrow,ncol,loc1(count)); 43 | plot(t_sec,data2_V(:,Ichan)*1e6); 44 | xlim(t_sec([1 end])); 45 | ylim(1e6*(median_data2_V(Ichan)+3*[-1 1]*spread_data2_V(Ichan))); 46 | weaText({['Mean = ' num2str(mean(data2_V(:,Ichan))*1e6,3) ' uV']; 47 | ['Std = ' num2str(std(data2_V(:,Ichan))*1e6,3) ' uV']},2); 48 | title(['Channel ' num2str(Ichan)]); 49 | xlabel(['Time (sec)']); 50 | ylabel(['Signal (uV)']); 51 | 52 | %spectrogram 53 | subplot(nrow,ncol,loc2(count)); 54 | N=256;overlap = 1-1/16;plots=0; 55 | [pD,wT,f]=windowedFFTPlot_spectragram(data2_V(:,Ichan),N,overlap,fs,plots); 56 | wT = wT + (N/2)/fs; 57 | 58 | imagesc(wT,f,10*log10(pD)); 59 | set(gca,'Ydir','normal'); 60 | xlabel('Time (sec)'); 61 | ylabel('Frequency (Hz)'); 62 | %title(tt); 63 | %cl=get(gca,'Clim');set(gca,'Clim',cl(2)+[-60 0]); 64 | set(gca,'Clim',-80+[-80 0]); 65 | ylim([0 65]); 66 | xlim(t_sec([1 end])); 67 | cl=get(gca,'Clim'); 68 | weaText(['Clim = [' num2str(cl(1)) ' ' num2str(cl(2)) '] dB'],1); 69 | 70 | end 71 | 72 | 73 | return 74 | 75 | all_data = [data1_V(1:len) data2_V(1:len) data3_V(1:len)]; 76 | bp_Hz = [3 40]; 77 | [b,a]=weaFIR(fs,bp_Hz/(fs/2)); 78 | f_all_data = filter(b,a,all_data); 79 | 80 | I=find((t_sec>t_zoom_sec(1)) & (t_sec < t_zoom_sec(2))); 81 | t_sec = t_sec(I); 82 | all_data = all_data(I,:); 83 | f_all_data = f_all_data(I,:); 84 | 85 | 86 | subplot(3,3,2*3+2); 87 | %plot(t_sec,(all_data-ones(size(all_data,1),1)*median(all_data))*1e6,'linewidth',2); 88 | plot(t_sec,f_all_data*1e6,'linewidth',2); 89 | xlabel(['Time (sec)']); 90 | ylabel(['Value (uvolts, ' num2str(bp_Hz(1)) ' - ' num2str(bp_Hz(2)) 'Hz)']); 91 | xlim(t_zoom_sec); 92 | %ylim([-250 250]); 93 | legend('TI Dev Kit','Creare','Olimex'); 94 | title(sname); 95 | weaText(['Creare = ' num2str(scale_fac_volts_per_count,3) ' V/count'],4); 96 | 97 | subplot(3,3,2*3+3); 98 | %[pD,freqs,N,h]=fftplot(all_data(1:N,:),fs,'hanning'); 99 | all_pD = []; 100 | for I=1:size(all_data,2) 101 | foo = all_data(:,I); 102 | [foo,wT,freq_Hz] = windowedFFTPlot_spectragram(foo-mean(foo),N,overlap,fs,0); 103 | all_pD(:,I) = mean(foo')'; 104 | end 105 | Hz_per_bin = fs / N; 106 | pD_per_Hz = all_pD / Hz_per_bin; 107 | semilogy(freq_Hz,sqrt(pD_per_Hz)*1e6,'linewidth',2); 108 | ylabel(['uVolts / sqrt(Hz)']); 109 | xlabel(['Frequency (Hz)']); 110 | xlim([0 65]); 111 | ylim([0.01 100]); 112 | legend('TI Dev Kit','Creare','Olimex',4); 113 | title(sname); 114 | 115 | -------------------------------------------------------------------------------- /Data/2013-11-01a ECG with V2/exploreSavedData_ECG.m: -------------------------------------------------------------------------------- 1 | 2 | %given_amp_counts = 4.5/2.4e-3; 3 | 4 | 5 | pname2 = 'SavedData\'; 6 | fname2 = 'data_2013-10-28_17-13-46_ECG_V1'; 7 | fname2 = 'data_2013-11-01_16-16-16'; 8 | fname2 = 'data_2013-11-01_16-20-41_V2_allChan_wMarks'; 9 | scale_fac_volts_per_count = (4.5/24/2^24); 10 | 11 | 12 | %% load data 13 | data2 = load([pname2 fname2]); %this is scaled to "full scale" (ie +/- 1.0) 14 | fs = data2.fs_Hz; 15 | try 16 | buff_data_FS = data2.buff_data_FS; %should be [-1.0 to +1.0] 17 | catch 18 | buff_data_FS = data2.buff_data; %should be [-1.0 to +1.0] 19 | end 20 | data2_counts = buff_data_FS * 2^(24-1); %this converts back to counts...+/- 2^23 21 | data2_V = data2_counts * scale_fac_volts_per_count; %apply the scale factor to get "volts" 22 | 23 | %% analyze data 24 | mean_data2_V = mean(data2_V); 25 | median_data2_V = median(data2_V); 26 | std_data2_V = std(data2_V); 27 | spread_data2_V = diff(xpercentile(data2_V,0.5+(0.68-0.5)*[-1 1]))/2; 28 | %spread_data2_V = median(spread_data2_V)*ones(size(spread_data2_V)); 29 | 30 | %% plot data 31 | %len = min([length(data1_V) length(data2_V) length(data3_V)]); 32 | %len = size(data2_V; 33 | t_sec = ([1:size(data2_V,1)]-1)/fs; 34 | n_per_page = 3;loc1 = [1 2 3];loc2 = [4 5 6];nrow = 2; ncol=3; 35 | count=0; 36 | for Ichan=1:size(data2_V,2); 37 | count = rem(count,n_per_page); 38 | if count==0; 39 | figure;setFigureTallestWidest; 40 | end 41 | count = count+1; 42 | 43 | %time-domain plot 44 | subplot(nrow,ncol,loc1(count)); 45 | plot(t_sec,data2_V(:,Ichan)*1e6); 46 | xlim(t_sec([1 end])); 47 | %ylim(1e6*(median_data2_V(Ichan)+3*[-1 1]*spread_data2_V(Ichan))); 48 | ylim(100*[-1 1]); 49 | weaText({['Mean = ' num2str(mean(data2_V(:,Ichan))*1e6,3) ' uV']; 50 | ['Std = ' num2str(std(data2_V(:,Ichan))*1e6,3) ' uV']},2); 51 | title(['Channel ' num2str(Ichan)]); 52 | xlabel(['Time (sec)']); 53 | ylabel(['Signal (uV)']); 54 | 55 | %spectrogram 56 | subplot(nrow,ncol,loc2(count)); 57 | N=256;overlap = 1-1/16;plots=0; 58 | [pD,wT,f]=windowedFFTPlot_spectragram(data2_V(:,Ichan),N,overlap,fs,plots); 59 | wT = wT + (N/2)/fs; 60 | 61 | imagesc(wT,f,10*log10(pD)); 62 | set(gca,'Ydir','normal'); 63 | xlabel('Time (sec)'); 64 | ylabel('Frequency (Hz)'); 65 | %title(tt); 66 | %cl=get(gca,'Clim');set(gca,'Clim',cl(2)+[-60 0]); 67 | set(gca,'Clim',-80+[-80 0]); 68 | ylim([0 65]); 69 | xlim(t_sec([1 end])); 70 | cl=get(gca,'Clim'); 71 | weaText(['Clim = [' num2str(cl(1)) ' ' num2str(cl(2)) '] dB'],1); 72 | 73 | end 74 | 75 | 76 | return 77 | 78 | all_data = [data1_V(1:len) data2_V(1:len) data3_V(1:len)]; 79 | bp_Hz = [3 40]; 80 | [b,a]=weaFIR(fs,bp_Hz/(fs/2)); 81 | f_all_data = filter(b,a,all_data); 82 | 83 | I=find((t_sec>t_zoom_sec(1)) & (t_sec < t_zoom_sec(2))); 84 | t_sec = t_sec(I); 85 | all_data = all_data(I,:); 86 | f_all_data = f_all_data(I,:); 87 | 88 | 89 | subplot(3,3,2*3+2); 90 | %plot(t_sec,(all_data-ones(size(all_data,1),1)*median(all_data))*1e6,'linewidth',2); 91 | plot(t_sec,f_all_data*1e6,'linewidth',2); 92 | xlabel(['Time (sec)']); 93 | ylabel(['Value (uvolts, ' num2str(bp_Hz(1)) ' - ' num2str(bp_Hz(2)) 'Hz)']); 94 | xlim(t_zoom_sec); 95 | %ylim([-250 250]); 96 | legend('TI Dev Kit','Creare','Olimex'); 97 | title(sname); 98 | weaText(['Creare = ' num2str(scale_fac_volts_per_count,3) ' V/count'],4); 99 | 100 | subplot(3,3,2*3+3); 101 | %[pD,freqs,N,h]=fftplot(all_data(1:N,:),fs,'hanning'); 102 | all_pD = []; 103 | for I=1:size(all_data,2) 104 | foo = all_data(:,I); 105 | [foo,wT,freq_Hz] = windowedFFTPlot_spectragram(foo-mean(foo),N,overlap,fs,0); 106 | all_pD(:,I) = mean(foo')'; 107 | end 108 | Hz_per_bin = fs / N; 109 | pD_per_Hz = all_pD / Hz_per_bin; 110 | semilogy(freq_Hz,sqrt(pD_per_Hz)*1e6,'linewidth',2); 111 | ylabel(['uVolts / sqrt(Hz)']); 112 | xlabel(['Frequency (Hz)']); 113 | xlim([0 65]); 114 | ylim([0.01 100]); 115 | legend('TI Dev Kit','Creare','Olimex',4); 116 | title(sname); 117 | 118 | -------------------------------------------------------------------------------- /Data/2013-11-01b Attempt2 at Mu Waves/SavedData/data_2013-11-01_16-46-54_V1_MuWaves.mat: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/chipaudette/EEGHacker/f72cc121d51fb5ea2f9176ebc0bb821aef05e64e/Data/2013-11-01b Attempt2 at Mu Waves/SavedData/data_2013-11-01_16-46-54_V1_MuWaves.mat -------------------------------------------------------------------------------- /Data/2013-11-01b Attempt2 at Mu Waves/SavedData/data_2013-11-01_16-56-00_V2_MuWaves.mat: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/chipaudette/EEGHacker/f72cc121d51fb5ea2f9176ebc0bb821aef05e64e/Data/2013-11-01b Attempt2 at Mu Waves/SavedData/data_2013-11-01_16-56-00_V2_MuWaves.mat -------------------------------------------------------------------------------- /Data/2013-11-01b Attempt2 at Mu Waves/SavedData/data_OpenBCI_format.zip: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/chipaudette/EEGHacker/f72cc121d51fb5ea2f9176ebc0bb821aef05e64e/Data/2013-11-01b Attempt2 at Mu Waves/SavedData/data_OpenBCI_format.zip -------------------------------------------------------------------------------- /Data/2013-11-01b Attempt2 at Mu Waves/convertMAT2OpenBCI.m: -------------------------------------------------------------------------------- 1 | 2 | scale_fac = 1; 3 | pname = '2013-11-01a ECG with V2\SavedData\'; scale_fac = 1e5; 4 | pname = '2013-11-01b Attempt2 at Mu Waves\SavedData\';scale_fac = 1e5; 5 | pname = '2013-11-04 Homemade Electrodes\SavedData\'; scale_fac = 1e5; 6 | pname = '2013-11-08 EOG\'; scale_fac = 1e5; 7 | fnames = dir([pname '*.mat']); 8 | for Ifname = 1:length(fnames); 9 | fname = fnames(Ifname).name; 10 | 11 | %load data 12 | disp(['loading ' pname fname]); 13 | data = load([pname fname]); 14 | 15 | %show the fields 16 | data 17 | 18 | %extract data 19 | fs = data.fs_Hz; 20 | if isfield(data,'buff_data'); 21 | units = 'microvolts'; 22 | data = data.buff_data; 23 | outfname = fname(1:end-4); 24 | output_precision = '%.1f'; 25 | yl = [-30 30]; 26 | else 27 | units = 'unknown scale'; 28 | data = data.buff_data_FS*scale_fac; 29 | outfname = [fname(1:end-4) '_arbitraryScale' num2str(scale_fac)]; 30 | output_precision = '%.1f'; 31 | yl = []; 32 | end 33 | 34 | % plot data 35 | figure; setFigureTall;ax = []; 36 | t_sec = ([1:size(data,1)]-1)/fs; 37 | dec_fac = 4; 38 | 39 | subplot(2,1,1); 40 | plot(t_sec(1:dec_fac:end),data(1:dec_fac:end,:)); 41 | title(fname,'interpreter','none'); 42 | xlabel('Time (sec)'); 43 | ylabel(['EEG (' units ')']); 44 | ax(end+1)=gca; 45 | 46 | subplot(2,1,2); 47 | bp_Hz = [0.5 40]; 48 | [b,a]=butter(2,bp_Hz/(fs/2)); 49 | fdata = filter(b,a,data); 50 | notch_Hz = [57 63]; 51 | [b,a]=butter(2,notch_Hz/(fs/2),'stop'); 52 | fdata = filter(b,a,fdata); 53 | plot(t_sec(1:dec_fac:end),fdata(1:dec_fac:end,:)); 54 | title(['BP Filtered [' num2str(bp_Hz) '] Hz'],'interpreter','none'); 55 | xlabel('Time (sec)'); 56 | ylabel(['EEG (' units ')']); 57 | if isempty(yl); foo=fdata(:); std_data = std(foo); I=find(abs(foo) < 2*std_data); std_data = std(foo(I)); yl = std_data*[-3 3];end 58 | ylim(yl); 59 | ax(end+1) = gca; 60 | 61 | linkaxes(ax,'x'); 62 | drawnow 63 | 64 | %the OpenBCI format needs a counter for the first column...increments 0->255 65 | sample_ind = rem(([1:size(data,1)]' - 1),256); 66 | 67 | %write the data 68 | outfname = [outfname '.csv']; 69 | disp(['writing to ' outfname]); 70 | dlmwrite(outfname,[sample_ind(:) data],'precision',output_precision); 71 | 72 | end -------------------------------------------------------------------------------- /Data/2013-11-04 Homemade Electrodes/SavedData/data_2013-11-04_20-06-24_ECG_HomebrewElectrodes.mat: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/chipaudette/EEGHacker/f72cc121d51fb5ea2f9176ebc0bb821aef05e64e/Data/2013-11-04 Homemade Electrodes/SavedData/data_2013-11-04_20-06-24_ECG_HomebrewElectrodes.mat -------------------------------------------------------------------------------- /Data/2013-11-04 Homemade Electrodes/SavedData/data_2013-11-04_20-16-06_MuWaves_HomebrewElectrodes.mat: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/chipaudette/EEGHacker/f72cc121d51fb5ea2f9176ebc0bb821aef05e64e/Data/2013-11-04 Homemade Electrodes/SavedData/data_2013-11-04_20-16-06_MuWaves_HomebrewElectrodes.mat -------------------------------------------------------------------------------- /Data/2013-11-04 Homemade Electrodes/SavedData/data_2013-11-04_20-31-45_MuWaves2_HomebrewElectrodes.mat: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/chipaudette/EEGHacker/f72cc121d51fb5ea2f9176ebc0bb821aef05e64e/Data/2013-11-04 Homemade Electrodes/SavedData/data_2013-11-04_20-31-45_MuWaves2_HomebrewElectrodes.mat -------------------------------------------------------------------------------- /Data/2013-11-04 Homemade Electrodes/SavedData/data_OpenBCI_format.zip: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/chipaudette/EEGHacker/f72cc121d51fb5ea2f9176ebc0bb821aef05e64e/Data/2013-11-04 Homemade Electrodes/SavedData/data_OpenBCI_format.zip -------------------------------------------------------------------------------- /Data/2013-11-04 Homemade Electrodes/convertMAT2OpenBCI.m: -------------------------------------------------------------------------------- 1 | 2 | scale_fac = 1; 3 | pname = '2013-11-01a ECG with V2\SavedData\'; scale_fac = 1e5; 4 | pname = '2013-11-01b Attempt2 at Mu Waves\SavedData\';scale_fac = 1e5; 5 | pname = '2013-11-04 Homemade Electrodes\SavedData\'; scale_fac = 1e5; 6 | pname = '2013-11-08 EOG\'; scale_fac = 1e5; 7 | fnames = dir([pname '*.mat']); 8 | for Ifname = 1:length(fnames); 9 | fname = fnames(Ifname).name; 10 | 11 | %load data 12 | disp(['loading ' pname fname]); 13 | data = load([pname fname]); 14 | 15 | %show the fields 16 | data 17 | 18 | %extract data 19 | fs = data.fs_Hz; 20 | if isfield(data,'buff_data'); 21 | units = 'microvolts'; 22 | data = data.buff_data; 23 | outfname = fname(1:end-4); 24 | output_precision = '%.1f'; 25 | yl = [-30 30]; 26 | else 27 | units = 'unknown scale'; 28 | data = data.buff_data_FS*scale_fac; 29 | outfname = [fname(1:end-4) '_arbitraryScale' num2str(scale_fac)]; 30 | output_precision = '%.1f'; 31 | yl = []; 32 | end 33 | 34 | % plot data 35 | figure; setFigureTall;ax = []; 36 | t_sec = ([1:size(data,1)]-1)/fs; 37 | dec_fac = 4; 38 | 39 | subplot(2,1,1); 40 | plot(t_sec(1:dec_fac:end),data(1:dec_fac:end,:)); 41 | title(fname,'interpreter','none'); 42 | xlabel('Time (sec)'); 43 | ylabel(['EEG (' units ')']); 44 | ax(end+1)=gca; 45 | 46 | subplot(2,1,2); 47 | bp_Hz = [0.5 40]; 48 | [b,a]=butter(2,bp_Hz/(fs/2)); 49 | fdata = filter(b,a,data); 50 | notch_Hz = [57 63]; 51 | [b,a]=butter(2,notch_Hz/(fs/2),'stop'); 52 | fdata = filter(b,a,fdata); 53 | plot(t_sec(1:dec_fac:end),fdata(1:dec_fac:end,:)); 54 | title(['BP Filtered [' num2str(bp_Hz) '] Hz'],'interpreter','none'); 55 | xlabel('Time (sec)'); 56 | ylabel(['EEG (' units ')']); 57 | if isempty(yl); foo=fdata(:); std_data = std(foo); I=find(abs(foo) < 2*std_data); std_data = std(foo(I)); yl = std_data*[-3 3];end 58 | ylim(yl); 59 | ax(end+1) = gca; 60 | 61 | linkaxes(ax,'x'); 62 | drawnow 63 | 64 | %the OpenBCI format needs a counter for the first column...increments 0->255 65 | sample_ind = rem(([1:size(data,1)]' - 1),256); 66 | 67 | %write the data 68 | outfname = [outfname '.csv']; 69 | disp(['writing to ' outfname]); 70 | dlmwrite(outfname,[sample_ind(:) data],'precision',output_precision); 71 | 72 | end -------------------------------------------------------------------------------- /Data/2013-11-08 EOG/SavedData.zip: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/chipaudette/EEGHacker/f72cc121d51fb5ea2f9176ebc0bb821aef05e64e/Data/2013-11-08 EOG/SavedData.zip -------------------------------------------------------------------------------- /Data/2013-11-08 EOG/convertMAT2OpenBCI.m: -------------------------------------------------------------------------------- 1 | 2 | scale_fac = 1; 3 | pname = '2013-11-01a ECG with V2\SavedData\'; scale_fac = 1e5; 4 | pname = '2013-11-01b Attempt2 at Mu Waves\SavedData\';scale_fac = 1e5; 5 | pname = '2013-11-04 Homemade Electrodes\SavedData\'; scale_fac = 1e5; 6 | pname = '2013-11-08 EOG\'; scale_fac = 1e5; 7 | fnames = dir([pname '*.mat']); 8 | for Ifname = 1:length(fnames); 9 | fname = fnames(Ifname).name; 10 | 11 | %load data 12 | disp(['loading ' pname fname]); 13 | data = load([pname fname]); 14 | 15 | %show the fields 16 | data 17 | 18 | %extract data 19 | fs = data.fs_Hz; 20 | if isfield(data,'buff_data'); 21 | units = 'microvolts'; 22 | data = data.buff_data; 23 | outfname = fname(1:end-4); 24 | output_precision = '%.1f'; 25 | yl = [-30 30]; 26 | else 27 | units = 'unknown scale'; 28 | data = data.buff_data_FS*scale_fac; 29 | outfname = [fname(1:end-4) '_arbitraryScale' num2str(scale_fac)]; 30 | output_precision = '%.1f'; 31 | yl = []; 32 | end 33 | 34 | % plot data 35 | figure; setFigureTall;ax = []; 36 | t_sec = ([1:size(data,1)]-1)/fs; 37 | dec_fac = 4; 38 | 39 | subplot(2,1,1); 40 | plot(t_sec(1:dec_fac:end),data(1:dec_fac:end,:)); 41 | title(fname,'interpreter','none'); 42 | xlabel('Time (sec)'); 43 | ylabel(['EEG (' units ')']); 44 | ax(end+1)=gca; 45 | 46 | subplot(2,1,2); 47 | bp_Hz = [0.5 40]; 48 | [b,a]=butter(2,bp_Hz/(fs/2)); 49 | fdata = filter(b,a,data); 50 | notch_Hz = [57 63]; 51 | [b,a]=butter(2,notch_Hz/(fs/2),'stop'); 52 | fdata = filter(b,a,fdata); 53 | plot(t_sec(1:dec_fac:end),fdata(1:dec_fac:end,:)); 54 | title(['BP Filtered [' num2str(bp_Hz) '] Hz'],'interpreter','none'); 55 | xlabel('Time (sec)'); 56 | ylabel(['EEG (' units ')']); 57 | if isempty(yl); foo=fdata(:); std_data = std(foo); I=find(abs(foo) < 2*std_data); std_data = std(foo(I)); yl = std_data*[-3 3];end 58 | ylim(yl); 59 | ax(end+1) = gca; 60 | 61 | linkaxes(ax,'x'); 62 | drawnow 63 | 64 | %the OpenBCI format needs a counter for the first column...increments 0->255 65 | sample_ind = rem(([1:size(data,1)]' - 1),256); 66 | 67 | %write the data 68 | outfname = [outfname '.csv']; 69 | disp(['writing to ' outfname]); 70 | dlmwrite(outfname,[sample_ind(:) data],'precision',output_precision); 71 | 72 | end -------------------------------------------------------------------------------- /Data/2013-11-08 EOG/data_OpenBCI_format.zip: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/chipaudette/EEGHacker/f72cc121d51fb5ea2f9176ebc0bb821aef05e64e/Data/2013-11-08 EOG/data_OpenBCI_format.zip -------------------------------------------------------------------------------- /Data/2014-04-05 Impedance and Concentration/SavedData.zip: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/chipaudette/EEGHacker/f72cc121d51fb5ea2f9176ebc0bb821aef05e64e/Data/2014-04-05 Impedance and Concentration/SavedData.zip -------------------------------------------------------------------------------- /Data/2014-04-05 Impedance and Concentration/exploreData.m: -------------------------------------------------------------------------------- 1 | 2 | %given_amp_counts = 4.5/2.4e-3; 3 | 4 | 5 | pname = 'SavedData\'; 6 | fname = 'openBCI_raw_2014-04-05_16-25-11_countBackAfterLastAlpha_filt.txt';nchan=1; 7 | %fname = 'openBCI_raw_2014-04-05_16-31-37_ECGelec_impedanceChecks_filt.txt';nchan=2; 8 | %fname = 'openBCI_raw_2014-04-05_16-36-34_ECGelec_countBackBy3_noFilt.txt';nchan=2; 9 | %fname = 'openBCI_raw_2014-04-05_17-13-48_GoldCup_countBackBy3_afterLastAlpa.txt';nchan=2; 10 | fname = '10-openBCI_raw_2014-04-19_10-23-36_EyesClosed_8secBreaths.txt';nchan=2; 11 | fname = '11-openBCI_raw_2014-04-19_10-32-36_StartedBackBy3s.txt';nchan=2; 12 | % fname = '12-openBCI_raw_2014-04-19_10-40-38_countbackwardsby3.txt';nchan=2; 13 | % fname = '13-openBCI_raw_2014-04-19_10-54-51_bothOnForehead_countback.txt';nchan=2; 14 | 15 | scale_fac_volts_count=2.23e-8; 16 | 17 | 18 | 19 | 20 | %% load data 21 | data_uV = load([pname fname]); %loads data as microvolts 22 | data_uV = data_uV(:,[1:nchan+1]); 23 | %fs = data2.fs_Hz; 24 | fs = 250; 25 | count = data_uV(:,1); %first column is a packet counter (though it's broken) 26 | data_V = data_uV(:,2:end) * 1e-6; %other columns are data 27 | clear data_uV; 28 | 29 | %% filter data 30 | data_V = data_V - ones(size(data_V,1),1)*mean(data_V); 31 | %[b,a]=butter(2,[0.2 50]/(fs/2)); 32 | [b,a]=butter(2,0.2/(fs/2),'high'); 33 | data_V = filter(b,a,data_V); 34 | [b,a]=butter(3,[55 65]/(fs/2),'stop'); 35 | data_V = filter(b,a,data_V); 36 | [b,a]=butter(3,[65 75]/(fs/2),'stop'); 37 | data_V = filter(b,a,data_V); 38 | 39 | %% write to WAV 40 | fs_dec = fs;foo_V = data_V; 41 | %foo_V = resample(data_V,1,2); fs_dec = fs / 2; %decimate 42 | outfname = ['WAVs\' fname(1:end-4) '.wav']; 43 | disp(['writing to ' outfname]); 44 | wavwrite(foo_V(:,1:min([size(data_V,2) 2]))*1e6/500,fs_dec,16,outfname); 45 | 46 | 47 | %% analyze data 48 | mean_data_V = mean(data_V); 49 | median_data_V = median(data_V); 50 | std_data_V = std(data_V); 51 | spread_data_V = diff(xpercentile(data_V,0.5+(0.68-0.5)*[-1 1]))/2; 52 | spread_data_V = median(spread_data_V)*ones(size(spread_data_V)); 53 | 54 | %% plot data 55 | t_sec = ([1:size(data_V,1)]-1)/fs; 56 | nrow = max([2 size(data_V,2)]); ncol=2; 57 | ax=[]; 58 | figure;setFigureTallestWidest; 59 | for Ichan=1:size(data_V,2); 60 | 61 | %time-domain plot 62 | subplotTightBorder(nrow,ncol,(Ichan-1)*2+1); 63 | plot(t_sec,data_V(:,Ichan)*1e6); 64 | xlim(t_sec([1 end])); 65 | %ylim(1e6*(median_data_V(Ichan)+3*[-1 1]*spread_data_V(Ichan))); 66 | ylim([-200 200]); 67 | weaText({['Mean = ' num2str(mean(data_V(:,Ichan))*1e6,3) ' uV']; 68 | ['Std = ' num2str(std(data_V(:,Ichan))*1e6,3) ' uV']},2); 69 | title(['Channel ' num2str(Ichan)]); 70 | xlabel(['Time (sec)']); 71 | ylabel(['Signal (uV)']); 72 | ax(end+1)=gca; 73 | 74 | %spectrogram 75 | subplotTightBorder(nrow,ncol,(Ichan-1)*2+2); 76 | %N=1024; 77 | %N=1200;overlap = 1-1/32;plots=0; 78 | %N = 2400;overlap = 1-1/64;plots=0; yl=[0 15]; 79 | N=500;overlap = 1-1/16;plots=0;yl=[0 fs/2]; 80 | [pD,wT,f]=windowedFFTPlot_spectragram(data_V(:,Ichan),N,overlap,fs,plots); 81 | wT = wT + (N/2)/fs; 82 | 83 | %smooth in time 84 | n_ave = 1; 85 | b = 1/n_ave* ones(n_ave,1);a=1; 86 | pD = filter(b,a,pD')'; 87 | 88 | imagesc(wT,f,10*log10(pD)); 89 | set(gca,'Ydir','normal'); 90 | if (Ichan > 6); xlabel('Time (sec)');end 91 | ylabel('Frequency (Hz)'); 92 | title([fname ', Channel ' num2str(Ichan)],'interpreter','none'); 93 | %cl=get(gca,'Clim');set(gca,'Clim',cl(2)+[-60 0]); 94 | set(gca,'Clim',-86+[-50 0]+10*log10(256)-10*log10(N)); 95 | ylim(yl); 96 | xlim(t_sec([1 end])); 97 | %cl=get(gca,'Clim'); 98 | %weaText(['Clim = [' num2str(cl(1)) ' ' num2str(cl(2)) '] dB'],1); 99 | ax(end+1)=gca; 100 | end 101 | 102 | linkaxes(ax,'x'); 103 | -------------------------------------------------------------------------------- /Data/2014-04-05 Impedance and Concentration/functions/loopWaves.asv: -------------------------------------------------------------------------------- 1 | function looop_wav = loopWave -------------------------------------------------------------------------------- /Data/2014-04-05 Impedance and Concentration/functions/loopWaves.m: -------------------------------------------------------------------------------- 1 | function [loop_wav,end_phase_frac] = loopWaves(wav,npoints,init_phase_frac); 2 | 3 | if (nargin < 3) 4 | init_phase_frac = 0; 5 | end 6 | 7 | %loop the wave and put it in the new signal 8 | new_inds = [1:npoints]; 9 | ind_into_wav = (new_inds - new_inds(1)); 10 | ind_into_wav = round(ind_into_wav + init_phase_frac*length(wav)); %make it start at the same place the last one left off 11 | ind_into_wav = (ind_into_wav - floor(ind_into_wav/length(wav))*length(wav))+1; 12 | loop_wav = wav(ind_into_wav); 13 | 14 | end_phase_frac = ind_into_wav(end) / length(wav); -------------------------------------------------------------------------------- /Data/2014-04-23 OpenBCI EEG over Breakfast and Birds/2014-04-23 Script of EEG Breakfast.xlsx: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/chipaudette/EEGHacker/f72cc121d51fb5ea2f9176ebc0bb821aef05e64e/Data/2014-04-23 OpenBCI EEG over Breakfast and Birds/2014-04-23 Script of EEG Breakfast.xlsx -------------------------------------------------------------------------------- /Data/2014-04-23 OpenBCI EEG over Breakfast and Birds/SavedData.zip: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/chipaudette/EEGHacker/f72cc121d51fb5ea2f9176ebc0bb821aef05e64e/Data/2014-04-23 OpenBCI EEG over Breakfast and Birds/SavedData.zip -------------------------------------------------------------------------------- /Data/2014-04-23 OpenBCI EEG over Breakfast and Birds/exploreData.m: -------------------------------------------------------------------------------- 1 | 2 | %given_amp_counts = 4.5/2.4e-3; 3 | 4 | 5 | pname = 'SavedData\'; 6 | fname = 'openBCI_raw_2014-04-05_16-25-11_countBackAfterLastAlpha_filt.txt';nchan=1; 7 | %fname = 'openBCI_raw_2014-04-05_16-31-37_ECGelec_impedanceChecks_filt.txt';nchan=2; 8 | %fname = 'openBCI_raw_2014-04-05_16-36-34_ECGelec_countBackBy3_noFilt.txt';nchan=2; 9 | %fname = 'openBCI_raw_2014-04-05_17-13-48_GoldCup_countBackBy3_afterLastAlpa.txt';nchan=2; 10 | fname = '10-openBCI_raw_2014-04-19_10-23-36_EyesClosed_8secBreaths.txt';nchan=2; 11 | fname = '11-openBCI_raw_2014-04-19_10-32-36_StartedBackBy3s.txt';nchan=2; 12 | % fname = '12-openBCI_raw_2014-04-19_10-40-38_countbackwardsby3.txt';nchan=2; 13 | % fname = '13-openBCI_raw_2014-04-19_10-54-51_bothOnForehead_countback.txt';nchan=2; 14 | fname = 'openBCI_raw_2014-04-23_06-52-48_Breakfast_Birds_CountBack.txt';nchan=1; 15 | 16 | scale_fac_volts_count=2.23e-8; 17 | 18 | 19 | 20 | 21 | %% load data 22 | data_uV = load([pname fname]); %loads data as microvolts 23 | data_uV = data_uV(:,[1:nchan+1]); 24 | %fs = data2.fs_Hz; 25 | fs = 250; 26 | count = data_uV(:,1); %first column is a packet counter (though it's broken) 27 | data_V = data_uV(:,2:end) * 1e-6; %other columns are data 28 | clear data_uV; 29 | 30 | %% filter data 31 | data_V = data_V - ones(size(data_V,1),1)*mean(data_V); 32 | %[b,a]=butter(2,[0.2 50]/(fs/2)); 33 | [b,a]=butter(2,0.2/(fs/2),'high'); 34 | data_V = filter(b,a,data_V); 35 | [b,a]=butter(3,[55 65]/(fs/2),'stop'); 36 | data_V = filter(b,a,data_V); 37 | [b,a]=butter(3,[65 75]/(fs/2),'stop'); 38 | data_V = filter(b,a,data_V); 39 | 40 | %% write to WAV 41 | fs_dec = fs;foo_V = data_V; 42 | %foo_V = resample(data_V,1,2); fs_dec = fs / 2; %decimate 43 | outfname = ['WAVs\' fname(1:end-4) '.wav']; 44 | disp(['writing to ' outfname]); 45 | wavwrite(foo_V(:,1:min([size(data_V,2) 2]))*1e6/500,fs_dec,16,outfname); 46 | 47 | 48 | %% analyze data 49 | mean_data_V = mean(data_V); 50 | median_data_V = median(data_V); 51 | std_data_V = std(data_V); 52 | spread_data_V = diff(xpercentile(data_V,0.5+(0.68-0.5)*[-1 1]))/2; 53 | spread_data_V = median(spread_data_V)*ones(size(spread_data_V)); 54 | 55 | %% plot data 56 | t_sec = ([1:size(data_V,1)]-1)/fs; 57 | nrow = max([2 size(data_V,2)]); ncol=2; 58 | ax=[]; 59 | figure;setFigureTallestWidest; 60 | for Ichan=1:size(data_V,2); 61 | 62 | %time-domain plot 63 | subplotTightBorder(nrow,ncol,(Ichan-1)*2+1); 64 | plot(t_sec,data_V(:,Ichan)*1e6); 65 | xlim(t_sec([1 end])); 66 | %ylim(1e6*(median_data_V(Ichan)+3*[-1 1]*spread_data_V(Ichan))); 67 | ylim([-200 200]); 68 | weaText({['Mean = ' num2str(mean(data_V(:,Ichan))*1e6,3) ' uV']; 69 | ['Std = ' num2str(std(data_V(:,Ichan))*1e6,3) ' uV']},2); 70 | title(['Channel ' num2str(Ichan)]); 71 | xlabel(['Time (sec)']); 72 | ylabel(['Signal (uV)']); 73 | ax(end+1)=gca; 74 | 75 | %spectrogram 76 | subplotTightBorder(nrow,ncol,(Ichan-1)*2+2); 77 | %N=1024; 78 | %N=1200;overlap = 1-1/32;plots=0; 79 | %N = 2400;overlap = 1-1/64;plots=0; yl=[0 15]; 80 | N=500;overlap = 1-1/16;plots=0;yl=[0 fs/2]; 81 | [pD,wT,f]=windowedFFTPlot_spectragram(data_V(:,Ichan),N,overlap,fs,plots); 82 | wT = wT + (N/2)/fs; 83 | 84 | %smooth in time 85 | n_ave = 1; 86 | b = 1/n_ave* ones(n_ave,1);a=1; 87 | pD = filter(b,a,pD')'; 88 | 89 | imagesc(wT,f,10*log10(pD)); 90 | set(gca,'Ydir','normal'); 91 | if (Ichan > 6); xlabel('Time (sec)');end 92 | ylabel('Frequency (Hz)'); 93 | title([fname ', Channel ' num2str(Ichan)],'interpreter','none'); 94 | %cl=get(gca,'Clim');set(gca,'Clim',cl(2)+[-60 0]); 95 | set(gca,'Clim',-86+[-50 0]+10*log10(256)-10*log10(N)); 96 | ylim(yl); 97 | xlim(t_sec([1 end])); 98 | %cl=get(gca,'Clim'); 99 | %weaText(['Clim = [' num2str(cl(1)) ' ' num2str(cl(2)) '] dB'],1); 100 | ax(end+1)=gca; 101 | end 102 | 103 | linkaxes(ax,'x'); 104 | -------------------------------------------------------------------------------- /Data/2014-04-23 OpenBCI EEG over Breakfast and Birds/functions/calcCoherece_fromTimeDomain.asv: -------------------------------------------------------------------------------- 1 | function [mean_cohere,wT,f,coherence] = calcCoherece_fromTimeDomain(t_sec,data_V,fs,N,overlap,nave,t_analyze_sec,flim,plots); 2 | 3 | data_V = data_V(:,1:2); %only examine the first two channels 4 | 5 | 6 | %fig=figure;setFigureTallestWide;ax=[]; 7 | %plot_count=0; 8 | noise = 0; 9 | %t_sec = ([1:size(data_V,1)]-1)/fs; 10 | mean_cohere = []; 11 | %for Icompare = 1:size(compare_chan,1); 12 | % Ichan1 = compare_chan(Icompare,1); 13 | % Ichan2 = compare_chan(Icompare,2); 14 | 15 | Ichan1 = 1; 16 | Ichan2 = 2; 17 | 18 | %compute spectra 19 | [fftx,wT,f]=windowedFFT2(t_sec,data_V(:,Ichan1),N,overlap,'hanning'); 20 | wT = wT + (N/2)/fs; 21 | inds = find(f <= fs/2); 22 | 23 | foo = data_V(:,Ichan2) + noise ; 24 | [ffty,wT,f]=windowedFFT2(t_sec,foo,N,overlap,'hanning'); 25 | wT = wT + (N/2)/fs; 26 | 27 | %compute coherence 28 | %nave = round(4*(1/(1 - overlap))); 29 | [coherence,yx_raw,yx_filt]=calcCoherence(fftx,ffty,nave); 30 | wT = wT - (0.75*nave*(1-overlap)*N)/fs; %adjust apparent timing of coherence estimates 31 | 32 | if plots 33 | 34 | % figure(fig); 35 | % plot_count = plot_count+1; 36 | % nrow=5;ncol=12;plotwidth=3; 37 | % %nrow=5;ncol=12;plotwidth=4; 38 | % subplotTightBorder(nrow,ncol,getPosition(ncol,plotwidth,Icompare)); 39 | imagesc(wT,f(inds),coherence(inds,:)); 40 | set(gca,'Ydir','normal'); 41 | %if (Icompare >= (size(compare_chan,1)-2)); xlabel('Time (sec)');end 42 | ylabel('Frequency (Hz)'); 43 | %title(['Coherence, Ch ' num2str(Ichan1) ' to Ch ' num2str(Ichan2)]); 44 | title(Coherence); 45 | set(gca,'Clim',[0 1]); 46 | %ylim([0 80]); 47 | ylim(flim); 48 | %xlim(t_sec([1 end])); 49 | xlim(t_sec([1 end])); 50 | % if ~isempty(t_analyze_sec) 51 | % xlim(t_analyze_sec); 52 | % end 53 | % cl=get(gca,'Clim'); 54 | %weaText(['Clim = [' num2str(cl(1)) ' ' num2str(cl(2)) '] dB'],1); 55 | % ax(end+1)=gca; 56 | 57 | if ~isempty(t_analyze_sec); 58 | for Imark=1:size(t_analyze_sec,1); 59 | hold on; 60 | yl=ylim; 61 | plot(t_analyze_sec(Imark,1)*[1 1],yl,'k--','linewidth',2); 62 | plot(t_analyze_sec(Imark,2)*[1 1],yl,'k--','linewidth',2); 63 | hold off 64 | end 65 | end 66 | 67 | %summarize data 68 | mean_cohere=[]; 69 | if ~isempty(t_analyze_sec) 70 | K=find((wT >= t_analyze_sec(1)) & (wT <= t_analyze_sec(2))); 71 | mean_cohere(:,Icompare) = nanmedian(coherence(:,K)')'; 72 | end 73 | 74 | %end 75 | 76 | %linkaxes(ax); 77 | 78 | -------------------------------------------------------------------------------- /Data/2014-04-23 OpenBCI EEG over Breakfast and Birds/functions/calcCoherece_fromTimeDomain.m: -------------------------------------------------------------------------------- 1 | function [coherence,wT,f,mean_cohere] = calcCoherece_fromTimeDomain(t_sec,data_V,fs,N,overlap,nave,t_analyze_sec,plots); 2 | 3 | data_V = data_V(:,1:2); %only examine the first two channels 4 | 5 | 6 | %fig=figure;setFigureTallestWide;ax=[]; 7 | %plot_count=0; 8 | noise = 0; 9 | %t_sec = ([1:size(data_V,1)]-1)/fs; 10 | mean_cohere = []; 11 | %for Icompare = 1:size(compare_chan,1); 12 | % Ichan1 = compare_chan(Icompare,1); 13 | % Ichan2 = compare_chan(Icompare,2); 14 | 15 | Ichan1 = 1; 16 | Ichan2 = 2; 17 | 18 | %compute spectra 19 | [fftx,wT,f]=windowedFFT2(t_sec,data_V(:,Ichan1),N,overlap,'hanning'); 20 | wT = wT + (N/2)/fs; 21 | inds = find(f <= fs/2); 22 | 23 | foo = data_V(:,Ichan2) + noise ; 24 | [ffty,wT,f]=windowedFFT2(t_sec,foo,N,overlap,'hanning'); 25 | wT = wT + (N/2)/fs; 26 | 27 | %compute coherence 28 | %nave = round(4*(1/(1 - overlap))); 29 | [coherence,yx_raw,yx_filt]=calcCoherence(fftx,ffty,nave); 30 | wT = wT - (0.75*nave*(1-overlap)*N)/fs; %adjust apparent timing of coherence estimates 31 | 32 | if plots 33 | 34 | % figure(fig); 35 | % plot_count = plot_count+1; 36 | % nrow=5;ncol=12;plotwidth=3; 37 | % %nrow=5;ncol=12;plotwidth=4; 38 | % subplotTightBorder(nrow,ncol,getPosition(ncol,plotwidth,Icompare)); 39 | imagesc(wT,f(inds),coherence(inds,:)); 40 | set(gca,'Ydir','normal'); 41 | %if (Icompare >= (size(compare_chan,1)-2)); xlabel('Time (sec)');end 42 | ylabel('Frequency (Hz)'); 43 | %title(['Coherence, Ch ' num2str(Ichan1) ' to Ch ' num2str(Ichan2)]); 44 | title('Coherence'); 45 | set(gca,'Clim',[0 1]); 46 | %ylim([0 80]); 47 | %ylim(flim); 48 | %xlim(t_sec([1 end])); 49 | xlim(t_sec([1 end])); 50 | % if ~isempty(t_analyze_sec) 51 | % xlim(t_analyze_sec); 52 | % end 53 | % cl=get(gca,'Clim'); 54 | %weaText(['Clim = [' num2str(cl(1)) ' ' num2str(cl(2)) '] dB'],1); 55 | % ax(end+1)=gca; 56 | 57 | if ~isempty(t_analyze_sec); 58 | for Imark=1:size(t_analyze_sec,1); 59 | hold on; 60 | yl=ylim; 61 | plot(t_analyze_sec(Imark,1)*[1 1],yl,'k--','linewidth',2); 62 | plot(t_analyze_sec(Imark,2)*[1 1],yl,'k--','linewidth',2); 63 | hold off 64 | end 65 | end 66 | end 67 | 68 | %summarize data 69 | mean_cohere=[]; 70 | for Itime = 1:size(t_analyze_sec,1); 71 | 72 | if ~isempty(t_analyze_sec) 73 | K=find((wT >= t_analyze_sec(Itime,1)) & (wT <= t_analyze_sec(Itime,2))); 74 | mean_cohere(:,Itime) = nanmedian(coherence(:,K)')'; 75 | end 76 | end 77 | 78 | %end 79 | 80 | %linkaxes(ax); 81 | 82 | -------------------------------------------------------------------------------- /Data/2014-04-23 OpenBCI EEG over Breakfast and Birds/functions/calcCoherence.m: -------------------------------------------------------------------------------- 1 | function [coherence,yx_raw,yx_filt]=calcCoherence(fftx,ffty,nave) 2 | 3 | % Basic Form: http://ocw.mit.edu/courses/earth-atmospheric-and-planetary-sciences/12-864-inference-from-data-and-models-spring-2005/lecture-notes/tsamsfmt_1_18.pdf 4 | % Add Averaging: http://www.dsprelated.com/dspbooks/mdft/Coherence_Function.html 5 | % Mostly worthless: http://en.wikipedia.org/wiki/Coherence_(signal_processing) 6 | 7 | 8 | xx = fftx.*conj(fftx); 9 | yy = ffty.*conj(ffty); 10 | yx_raw = conj(fftx).*(ffty); 11 | %coherence = ((abs(yx)).^2)./(xx.*yy); %this always returns 1.0...can't be right 12 | 13 | %ahh, need averaging to see if movement from block to block coherent 14 | b = 1/nave*ones(nave,1); %do a moving average filter over nave blocks 15 | yx_filt = filter(b,1,yx_raw')'; %must filter before the ABS operation (the ABS is later) 16 | xx = filter(b,1,xx')'; 17 | yy = filter(b,1,yy')'; 18 | coherence = (abs(yx_filt).^2)./ (xx.*yy); -------------------------------------------------------------------------------- /Data/2014-04-23 OpenBCI EEG over Breakfast and Birds/functions/evalCoherence_nearbyOnly.asv: -------------------------------------------------------------------------------- 1 | function [mean_cohere,wT,f] = evalCoherence_nearbyOnly(t_sec,data_V,fs,N,overlap,nave,t_analyze_sec,flim); 2 | 3 | compare_chan = [2 1; 4 | 3 1; 5 | 4 2; 6 | 5 3; 7 | 6 4; 8 | 7 5; 9 | 8 6; 10 | 8 7; 11 | ] 12 | 13 | 14 | fig=figure;setFigureTallestWide;ax=[]; 15 | plot_count=0; 16 | noise = 0; 17 | %t_sec = ([1:size(data_V,1)]-1)/fs; 18 | mean_cohere = []; 19 | for Icompare = 1:size(compare_chan,1); 20 | Ichan1 = compare_chan(Icompare,1); 21 | Ichan2 = compare_chan(Icompare,2); 22 | 23 | [fftx,wT,f]=windowedFFT2(t_sec,data_V(:,Ichan1),N,overlap,'hanning'); 24 | wT = wT + (N/2)/fs; 25 | inds = find(f <= fs/2); 26 | 27 | 28 | foo = data_V(:,Ichan2) + noise ; 29 | [ffty,wT,f]=windowedFFT2(t_sec,foo,N,overlap,'hanning'); 30 | wT = wT + (N/2)/fs; 31 | %nave = round(4*(1/(1 - overlap))); 32 | [coherence,yx_raw,yx_filt]=calcCoherence(fftx,ffty,nave); 33 | 34 | figure(fig); 35 | plot_count = plot_count+1; 36 | nrow=5;ncol=12+1;plotwidth=3; 37 | %nrow=5;ncol=12;plotwidth=4; 38 | subplotTightBorder(nrow,ncol,getPosition(ncol,plotwidth,Icompare)); 39 | imagesc(wT,f(inds),coherence(inds,:)); 40 | set(gca,'Ydir','normal'); 41 | if (Ichan2 == Ichan1+1); xlabel('Time (sec)');end 42 | ylabel('Frequency (Hz)'); 43 | title(['Coherence, Ch ' num2str(Ichan1) ' to Ch ' num2str(Ichan2)]); 44 | set(gca,'Clim',[0 1]); 45 | %ylim([0 80]); 46 | ylim(flim); 47 | %xlim(t_sec([1 end])); 48 | xlim(t_sec([1 end])); 49 | % if ~isempty(t_analyze_sec) 50 | % xlim(t_analyze_sec); 51 | % end 52 | cl=get(gca,'Clim'); 53 | %weaText(['Clim = [' num2str(cl(1)) ' ' num2str(cl(2)) '] dB'],1); 54 | ax(end+1)=gca; 55 | 56 | if ~isempty(t_mark_sec); 57 | for Imark=1:size(t_mark_sec,1); 58 | hold on; 59 | yl=ylim; 60 | plot(t_mark_sec(Imark,1)*[1 1],yl,'k--','linewidth',2); 61 | plot(t_mark_sec(Imark,2)*[1 1],yl,'k--','linewidth',2); 62 | hold off 63 | end 64 | end 65 | 66 | %summarize data 67 | K=find((wT >= t_analyze_sec(1)) & (wT <= t_analyze_sec(2))); 68 | mean_cohere(:,Icompare) = nanmedian(coherence(:,K)')'; 69 | 70 | end 71 | 72 | linkaxes(ax); 73 | 74 | 75 | %% %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%5 76 | function pos = getPosition(ncol,plotwidth,Icompare) 77 | 78 | %assume comparing side-by-side around the head 79 | %nwide = 2; 80 | nwide = plotwidth; 81 | switch Icompare 82 | case 1 83 | %top center 84 | pos = floor((ncol / 2) + [0:nwide-1]-(nwide/2-1)); 85 | case 2 86 | %second row, left side, in a smidge 87 | pos = (2-1)*ncol + [1:nwide] + 1; 88 | case 3 89 | %second row, right side, in a smidge 90 | pos = (2-1)*ncol+ ncol+[-(nwide-1):0] - 1; 91 | case 4 92 | %third row, left side 93 | pos = (3-1)*ncol+ [1:nwide]; 94 | case 5 95 | %third row, right side 96 | pos = (3-1)*ncol+ncol+[-(nwide-1):0]; 97 | case 6 98 | %fourth row, left side, in a smidge 99 | pos = (4-1)*ncol+ [1:nwide]+1; 100 | case 7 101 | %fourth row, right side, in a smidge 102 | pos = (4-1)*ncol+ncol+[-(nwide-1):0]-1; 103 | case 8 104 | %fifth row, center 105 | pos = (5-1)*ncol+ floor((ncol / 2) + [0:nwide-1]-(nwide/2-1)); 106 | end 107 | 108 | -------------------------------------------------------------------------------- /Data/2014-04-23 OpenBCI EEG over Breakfast and Birds/functions/evalCoherence_nearbyOnly.m: -------------------------------------------------------------------------------- 1 | function [mean_cohere,wT,f] = evalCoherence_nearbyOnly(t_sec,data_V,fs,N,overlap,nave,t_analyze_sec,flim,plots); 2 | 3 | 4 | % compare_chan = [2 1; 5 | % 3 1; 6 | % 4 2; 7 | % 5 3; 8 | % 6 4; 9 | % 7 5; 10 | % 8 6; 11 | % 8 7; 12 | % ]; 13 | 14 | compare_chan = [2 1; 15 | ]; 16 | 17 | fig=figure;setFigureTallestWide;ax=[]; 18 | plot_count=0; 19 | noise = 0; 20 | %t_sec = ([1:size(data_V,1)]-1)/fs; 21 | mean_cohere = []; 22 | for Icompare = 1:size(compare_chan,1); 23 | Ichan1 = compare_chan(Icompare,1); 24 | Ichan2 = compare_chan(Icompare,2); 25 | 26 | %compute spectra 27 | [fftx,wT,f]=windowedFFT2(t_sec,data_V(:,Ichan1),N,overlap,'hanning'); 28 | wT = wT + (N/2)/fs; 29 | inds = find(f <= fs/2); 30 | 31 | foo = data_V(:,Ichan2) + noise ; 32 | [ffty,wT,f]=windowedFFT2(t_sec,foo,N,overlap,'hanning'); 33 | wT = wT + (N/2)/fs; 34 | 35 | %compute coherence 36 | %nave = round(4*(1/(1 - overlap))); 37 | [coherence,yx_raw,yx_filt]=calcCoherence(fftx,ffty,nave); 38 | wT = wT - (0.75*nave*(1-overlap)*N)/fs; %adjust apparent timing of coherence estimates 39 | 40 | 41 | figure(fig); 42 | plot_count = plot_count+1; 43 | nrow=5;ncol=12;plotwidth=3; 44 | %nrow=5;ncol=12;plotwidth=4; 45 | subplotTightBorder(nrow,ncol,getPosition(ncol,plotwidth,Icompare)); 46 | imagesc(wT,f(inds),coherence(inds,:)); 47 | set(gca,'Ydir','normal'); 48 | if (Icompare >= (size(compare_chan,1)-2)); xlabel('Time (sec)');end 49 | ylabel('Frequency (Hz)'); 50 | title(['Coherence, Ch ' num2str(Ichan1) ' to Ch ' num2str(Ichan2)]); 51 | set(gca,'Clim',[0 1]); 52 | %ylim([0 80]); 53 | ylim(flim); 54 | %xlim(t_sec([1 end])); 55 | xlim(t_sec([1 end])); 56 | % if ~isempty(t_analyze_sec) 57 | % xlim(t_analyze_sec); 58 | % end 59 | cl=get(gca,'Clim'); 60 | %weaText(['Clim = [' num2str(cl(1)) ' ' num2str(cl(2)) '] dB'],1); 61 | ax(end+1)=gca; 62 | 63 | if ~isempty(t_analyze_sec); 64 | for Imark=1:size(t_analyze_sec,1); 65 | hold on; 66 | yl=ylim; 67 | plot(t_analyze_sec(Imark,1)*[1 1],yl,'k--','linewidth',2); 68 | plot(t_analyze_sec(Imark,2)*[1 1],yl,'k--','linewidth',2); 69 | hold off 70 | end 71 | end 72 | 73 | %summarize data 74 | K=find((wT >= t_analyze_sec(1)) & (wT <= t_analyze_sec(2))); 75 | mean_cohere(:,Icompare) = nanmedian(coherence(:,K)')'; 76 | 77 | end 78 | 79 | linkaxes(ax); 80 | 81 | 82 | %% %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%5 83 | function pos = getPosition(ncol,plotwidth,Icompare) 84 | 85 | %assume comparing side-by-side around the head 86 | %nwide = 2; 87 | nwide = plotwidth; 88 | switch Icompare 89 | case 1 90 | %top center 91 | pos = floor((ncol / 2) + [0:nwide-1]-(nwide/2-1)); 92 | case 2 93 | %second row, left side, in a smidge 94 | pos = (2-1)*ncol + [1:nwide] + 1; 95 | case 3 96 | %second row, right side, in a smidge 97 | pos = (2-1)*ncol+ ncol+[-(nwide-1):0] - 1-1; 98 | case 4 99 | %third row, left side 100 | pos = (3-1)*ncol+ [1:nwide]; 101 | case 5 102 | %third row, right side 103 | pos = (3-1)*ncol+ncol+[-(nwide-1):0]-1; 104 | case 6 105 | %fourth row, left side, in a smidge 106 | pos = (4-1)*ncol+ [1:nwide]+1; 107 | case 7 108 | %fourth row, right side, in a smidge 109 | pos = (4-1)*ncol+ncol+[-(nwide-1):0]-1-1; 110 | case 8 111 | %fifth row, center 112 | pos = (5-1)*ncol+ floor((ncol / 2) + [0:nwide-1]-(nwide/2-1)); 113 | end 114 | 115 | -------------------------------------------------------------------------------- /Data/2014-04-23 OpenBCI EEG over Breakfast and Birds/functions/plotSpectrograms_headshape.m: -------------------------------------------------------------------------------- 1 | function [mean_cohere,wT,f] = evalCoherence_nearbyOnly(t_sec,data_V,fs,N,overlap,nave,t_analyze_sec,flim); 2 | 3 | compare_chan = [2 1; 4 | 3 1; 5 | 4 2; 6 | 5 3; 7 | 6 4; 8 | 7 5; 9 | 8 6; 10 | 8 7; 11 | ] 12 | 13 | 14 | fig=figure;setFigureTallestWide;ax=[]; 15 | plot_count=0; 16 | noise = 0; 17 | %t_sec = ([1:size(data_V,1)]-1)/fs; 18 | mean_cohere = []; 19 | for Icompare = 1:size(compare_chan,1); 20 | Ichan1 = compare_chan(Icompare,1); 21 | Ichan2 = compare_chan(Icompare,2); 22 | 23 | [fftx,wT,f]=windowedFFT2(t_sec,data_V(:,Ichan1),N,overlap,'hanning'); 24 | wT = wT + (N/2)/fs; 25 | inds = find(f <= fs/2); 26 | 27 | 28 | foo = data_V(:,Ichan2) + noise ; 29 | [ffty,wT,f]=windowedFFT2(t_sec,foo,N,overlap,'hanning'); 30 | wT = wT + (N/2)/fs; 31 | %nave = round(4*(1/(1 - overlap))); 32 | [coherence,yx_raw,yx_filt]=calcCoherence(fftx,ffty,nave); 33 | 34 | figure(fig); 35 | plot_count = plot_count+1; 36 | nrow=5;ncol=12+1;plotwidth=3; 37 | %nrow=5;ncol=12;plotwidth=4; 38 | subplotTightBorder(nrow,ncol,getPosition(ncol,plotwidth,Icompare)); 39 | imagesc(wT,f(inds),coherence(inds,:)); 40 | set(gca,'Ydir','normal'); 41 | if (Ichan2 == Ichan1+1); xlabel('Time (sec)');end 42 | ylabel('Frequency (Hz)'); 43 | title(['Coherence, Ch ' num2str(Ichan1) ' to Ch ' num2str(Ichan2)]); 44 | set(gca,'Clim',[0 1]); 45 | %ylim([0 80]); 46 | ylim(flim); 47 | xlim(t_sec([1 end])); 48 | if ~isempty(t_analyze_sec) 49 | xlim(t_analyze_sec); 50 | end 51 | cl=get(gca,'Clim'); 52 | %weaText(['Clim = [' num2str(cl(1)) ' ' num2str(cl(2)) '] dB'],1); 53 | ax(end+1)=gca; 54 | 55 | %summarize data 56 | K=find((wT >= t_analyze_sec(1)) & (wT <= t_analyze_sec(2))); 57 | mean_cohere(:,Icompare) = nanmedian(coherence(:,K)')'; 58 | 59 | end 60 | 61 | linkaxes(ax); 62 | 63 | 64 | %% %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%5 65 | function pos = getPosition(ncol,plotwidth,Icompare) 66 | 67 | %assume comparing side-by-side around the head 68 | %nwide = 2; 69 | nwide = plotwidth; 70 | switch Icompare 71 | case 1 72 | %top center 73 | pos = floor((ncol / 2) + [0:nwide-1]-(nwide/2-1)); 74 | case 2 75 | %second row, left side, in a smidge 76 | pos = (2-1)*ncol + [1:nwide] + 1; 77 | case 3 78 | %second row, right side, in a smidge 79 | pos = (2-1)*ncol+ ncol+[-(nwide-1):0] - 1; 80 | case 4 81 | %third row, left side 82 | pos = (3-1)*ncol+ [1:nwide]; 83 | case 5 84 | %third row, right side 85 | pos = (3-1)*ncol+ncol+[-(nwide-1):0]; 86 | case 6 87 | %fourth row, left side, in a smidge 88 | pos = (4-1)*ncol+ [1:nwide]+1; 89 | case 7 90 | %fourth row, right side, in a smidge 91 | pos = (4-1)*ncol+ncol+[-(nwide-1):0]-1; 92 | case 8 93 | %fifth row, center 94 | pos = (5-1)*ncol+ floor((ncol / 2) + [0:nwide-1]-(nwide/2-1)); 95 | end 96 | 97 | -------------------------------------------------------------------------------- /Data/2014-04-30 Visual Steady-State Evoked Potentials/SavedData.zip: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/chipaudette/EEGHacker/f72cc121d51fb5ea2f9176ebc0bb821aef05e64e/Data/2014-04-30 Visual Steady-State Evoked Potentials/SavedData.zip -------------------------------------------------------------------------------- /Data/2014-04-30 Visual Steady-State Evoked Potentials/exploreData.m: -------------------------------------------------------------------------------- 1 | 2 | %given_amp_counts = 4.5/2.4e-3; 3 | 4 | 5 | pname = 'SavedData\'; 6 | fname = 'openBCI_raw_2014-04-05_16-25-11_countBackAfterLastAlpha_filt.txt';nchan=1; 7 | %fname = 'openBCI_raw_2014-04-05_16-31-37_ECGelec_impedanceChecks_filt.txt';nchan=2; 8 | %fname = 'openBCI_raw_2014-04-05_16-36-34_ECGelec_countBackBy3_noFilt.txt';nchan=2; 9 | %fname = 'openBCI_raw_2014-04-05_17-13-48_GoldCup_countBackBy3_afterLastAlpa.txt';nchan=2; 10 | fname = '10-openBCI_raw_2014-04-19_10-23-36_EyesClosed_8secBreaths.txt';nchan=2; 11 | fname = '11-openBCI_raw_2014-04-19_10-32-36_StartedBackBy3s.txt';nchan=2; 12 | % fname = '12-openBCI_raw_2014-04-19_10-40-38_countbackwardsby3.txt';nchan=2; 13 | % fname = '13-openBCI_raw_2014-04-19_10-54-51_bothOnForehead_countback.txt';nchan=2; 14 | fname = 'openBCI_raw_2014-04-23_06-52-48_Breakfast_Birds_CountBack.txt';nchan=1; 15 | fname = 'openBCI_raw_2014-04-30_22-14-48_fullRun_4blocks.txt';nchan=2; 16 | 17 | scale_fac_volts_count=2.23e-8; 18 | 19 | 20 | 21 | 22 | %% load data 23 | data_uV = load([pname fname]); %loads data as microvolts 24 | data_uV = data_uV(:,[1:nchan+1]); 25 | %fs = data2.fs_Hz; 26 | fs = 250; 27 | count = data_uV(:,1); %first column is a packet counter (though it's broken) 28 | data_V = data_uV(:,2:end) * 1e-6; %other columns are data 29 | clear data_uV; 30 | 31 | %% filter data 32 | data_V = data_V - ones(size(data_V,1),1)*mean(data_V); 33 | %[b,a]=butter(2,[0.2 50]/(fs/2)); 34 | [b,a]=butter(2,0.2/(fs/2),'high'); 35 | data_V = filter(b,a,data_V); 36 | [b,a]=butter(3,[55 65]/(fs/2),'stop'); 37 | data_V = filter(b,a,data_V); 38 | [b,a]=butter(3,[65 75]/(fs/2),'stop'); 39 | data_V = filter(b,a,data_V); 40 | 41 | %% write to WAV 42 | fs_dec = fs;foo_V = data_V; 43 | %foo_V = resample(data_V,1,2); fs_dec = fs / 2; %decimate 44 | outfname = ['WAVs\' fname(1:end-4) '.wav']; 45 | disp(['writing to ' outfname]); 46 | wavwrite(foo_V(:,1:min([size(data_V,2) 2]))*1e6/500,fs_dec,16,outfname); 47 | 48 | 49 | %% analyze data 50 | mean_data_V = mean(data_V); 51 | median_data_V = median(data_V); 52 | std_data_V = std(data_V); 53 | spread_data_V = diff(xpercentile(data_V,0.5+(0.68-0.5)*[-1 1]))/2; 54 | spread_data_V = median(spread_data_V)*ones(size(spread_data_V)); 55 | 56 | %% plot data 57 | t_sec = ([1:size(data_V,1)]-1)/fs; 58 | nrow = max([2 size(data_V,2)]); ncol=2; 59 | ax=[]; 60 | figure;setFigureTallestWidest; 61 | for Ichan=1:size(data_V,2); 62 | 63 | %time-domain plot 64 | subplotTightBorder(nrow,ncol,(Ichan-1)*2+1); 65 | plot(t_sec,data_V(:,Ichan)*1e6); 66 | xlim(t_sec([1 end])); 67 | %ylim(1e6*(median_data_V(Ichan)+3*[-1 1]*spread_data_V(Ichan))); 68 | ylim([-200 200]); 69 | weaText({['Mean = ' num2str(mean(data_V(:,Ichan))*1e6,3) ' uV']; 70 | ['Std = ' num2str(std(data_V(:,Ichan))*1e6,3) ' uV']},2); 71 | title(['Channel ' num2str(Ichan)]); 72 | xlabel(['Time (sec)']); 73 | ylabel(['Signal (uV)']); 74 | ax(end+1)=gca; 75 | 76 | %spectrogram 77 | subplotTightBorder(nrow,ncol,(Ichan-1)*2+2); 78 | %N=1024; 79 | %N=1200;overlap = 1-1/32;plots=0; 80 | %N = 2400;overlap = 1-1/64;plots=0; yl=[0 15]; 81 | N=500;overlap = 1-1/16;plots=0; 82 | %yl=[0 fs/2]; 83 | yl = [0 25]; 84 | [pD,wT,f]=windowedFFTPlot_spectragram(data_V(:,Ichan),N,overlap,fs,plots); 85 | wT = wT + (N/2)/fs; 86 | 87 | %smooth in time 88 | % n_ave = 1; 89 | % b = 1/n_ave* ones(n_ave,1);a=1; 90 | % pD = filter(b,a,pD')'; 91 | 92 | imagesc(wT,f,10*log10(pD)); 93 | set(gca,'Ydir','normal'); 94 | if (Ichan > 6); xlabel('Time (sec)');end 95 | ylabel('Frequency (Hz)'); 96 | title([fname ', Channel ' num2str(Ichan)],'interpreter','none'); 97 | %cl=get(gca,'Clim');set(gca,'Clim',cl(2)+[-60 0]); 98 | set(gca,'Clim',-86+[-50 0]+10*log10(256)-10*log10(N)); 99 | ylim(yl); 100 | xlim(t_sec([1 end])); 101 | %cl=get(gca,'Clim'); 102 | %weaText(['Clim = [' num2str(cl(1)) ' ' num2str(cl(2)) '] dB'],1); 103 | ax(end+1)=gca; 104 | end 105 | 106 | linkaxes(ax,'x'); 107 | -------------------------------------------------------------------------------- /Data/2014-04-30 Visual Steady-State Evoked Potentials/functions/calcCoherece_fromTimeDomain.asv: -------------------------------------------------------------------------------- 1 | function [mean_cohere,wT,f,coherence] = calcCoherece_fromTimeDomain(t_sec,data_V,fs,N,overlap,nave,t_analyze_sec,flim,plots); 2 | 3 | data_V = data_V(:,1:2); %only examine the first two channels 4 | 5 | 6 | %fig=figure;setFigureTallestWide;ax=[]; 7 | %plot_count=0; 8 | noise = 0; 9 | %t_sec = ([1:size(data_V,1)]-1)/fs; 10 | mean_cohere = []; 11 | %for Icompare = 1:size(compare_chan,1); 12 | % Ichan1 = compare_chan(Icompare,1); 13 | % Ichan2 = compare_chan(Icompare,2); 14 | 15 | Ichan1 = 1; 16 | Ichan2 = 2; 17 | 18 | %compute spectra 19 | [fftx,wT,f]=windowedFFT2(t_sec,data_V(:,Ichan1),N,overlap,'hanning'); 20 | wT = wT + (N/2)/fs; 21 | inds = find(f <= fs/2); 22 | 23 | foo = data_V(:,Ichan2) + noise ; 24 | [ffty,wT,f]=windowedFFT2(t_sec,foo,N,overlap,'hanning'); 25 | wT = wT + (N/2)/fs; 26 | 27 | %compute coherence 28 | %nave = round(4*(1/(1 - overlap))); 29 | [coherence,yx_raw,yx_filt]=calcCoherence(fftx,ffty,nave); 30 | wT = wT - (0.75*nave*(1-overlap)*N)/fs; %adjust apparent timing of coherence estimates 31 | 32 | if plots 33 | 34 | % figure(fig); 35 | % plot_count = plot_count+1; 36 | % nrow=5;ncol=12;plotwidth=3; 37 | % %nrow=5;ncol=12;plotwidth=4; 38 | % subplotTightBorder(nrow,ncol,getPosition(ncol,plotwidth,Icompare)); 39 | imagesc(wT,f(inds),coherence(inds,:)); 40 | set(gca,'Ydir','normal'); 41 | %if (Icompare >= (size(compare_chan,1)-2)); xlabel('Time (sec)');end 42 | ylabel('Frequency (Hz)'); 43 | %title(['Coherence, Ch ' num2str(Ichan1) ' to Ch ' num2str(Ichan2)]); 44 | title(Coherence); 45 | set(gca,'Clim',[0 1]); 46 | %ylim([0 80]); 47 | ylim(flim); 48 | %xlim(t_sec([1 end])); 49 | xlim(t_sec([1 end])); 50 | % if ~isempty(t_analyze_sec) 51 | % xlim(t_analyze_sec); 52 | % end 53 | % cl=get(gca,'Clim'); 54 | %weaText(['Clim = [' num2str(cl(1)) ' ' num2str(cl(2)) '] dB'],1); 55 | % ax(end+1)=gca; 56 | 57 | if ~isempty(t_analyze_sec); 58 | for Imark=1:size(t_analyze_sec,1); 59 | hold on; 60 | yl=ylim; 61 | plot(t_analyze_sec(Imark,1)*[1 1],yl,'k--','linewidth',2); 62 | plot(t_analyze_sec(Imark,2)*[1 1],yl,'k--','linewidth',2); 63 | hold off 64 | end 65 | end 66 | 67 | %summarize data 68 | mean_cohere=[]; 69 | if ~isempty(t_analyze_sec) 70 | K=find((wT >= t_analyze_sec(1)) & (wT <= t_analyze_sec(2))); 71 | mean_cohere(:,Icompare) = nanmedian(coherence(:,K)')'; 72 | end 73 | 74 | %end 75 | 76 | %linkaxes(ax); 77 | 78 | -------------------------------------------------------------------------------- /Data/2014-04-30 Visual Steady-State Evoked Potentials/functions/calcCoherece_fromTimeDomain.m: -------------------------------------------------------------------------------- 1 | function [coherence,wT,f,mean_cohere] = calcCoherece_fromTimeDomain(t_sec,data_V,fs,N,overlap,nave,t_analyze_sec,plots); 2 | 3 | data_V = data_V(:,1:2); %only examine the first two channels 4 | 5 | 6 | %fig=figure;setFigureTallestWide;ax=[]; 7 | %plot_count=0; 8 | noise = 0; 9 | %t_sec = ([1:size(data_V,1)]-1)/fs; 10 | mean_cohere = []; 11 | %for Icompare = 1:size(compare_chan,1); 12 | % Ichan1 = compare_chan(Icompare,1); 13 | % Ichan2 = compare_chan(Icompare,2); 14 | 15 | Ichan1 = 1; 16 | Ichan2 = 2; 17 | 18 | %compute spectra 19 | [fftx,wT,f]=windowedFFT2(t_sec,data_V(:,Ichan1),N,overlap,'hanning'); 20 | wT = wT + (N/2)/fs; 21 | inds = find(f <= fs/2); 22 | 23 | foo = data_V(:,Ichan2) + noise ; 24 | [ffty,wT,f]=windowedFFT2(t_sec,foo,N,overlap,'hanning'); 25 | wT = wT + (N/2)/fs; 26 | 27 | %compute coherence 28 | %nave = round(4*(1/(1 - overlap))); 29 | [coherence,yx_raw,yx_filt]=calcCoherence(fftx,ffty,nave); 30 | wT = wT - (0.75*nave*(1-overlap)*N)/fs; %adjust apparent timing of coherence estimates 31 | 32 | if plots 33 | 34 | % figure(fig); 35 | % plot_count = plot_count+1; 36 | % nrow=5;ncol=12;plotwidth=3; 37 | % %nrow=5;ncol=12;plotwidth=4; 38 | % subplotTightBorder(nrow,ncol,getPosition(ncol,plotwidth,Icompare)); 39 | imagesc(wT,f(inds),coherence(inds,:)); 40 | set(gca,'Ydir','normal'); 41 | %if (Icompare >= (size(compare_chan,1)-2)); xlabel('Time (sec)');end 42 | ylabel('Frequency (Hz)'); 43 | %title(['Coherence, Ch ' num2str(Ichan1) ' to Ch ' num2str(Ichan2)]); 44 | title('Coherence'); 45 | set(gca,'Clim',[0 1]); 46 | %ylim([0 80]); 47 | %ylim(flim); 48 | %xlim(t_sec([1 end])); 49 | xlim(t_sec([1 end])); 50 | % if ~isempty(t_analyze_sec) 51 | % xlim(t_analyze_sec); 52 | % end 53 | % cl=get(gca,'Clim'); 54 | %weaText(['Clim = [' num2str(cl(1)) ' ' num2str(cl(2)) '] dB'],1); 55 | % ax(end+1)=gca; 56 | 57 | if ~isempty(t_analyze_sec); 58 | for Imark=1:size(t_analyze_sec,1); 59 | hold on; 60 | yl=ylim; 61 | plot(t_analyze_sec(Imark,1)*[1 1],yl,'k--','linewidth',2); 62 | plot(t_analyze_sec(Imark,2)*[1 1],yl,'k--','linewidth',2); 63 | hold off 64 | end 65 | end 66 | end 67 | 68 | %summarize data 69 | mean_cohere=[]; 70 | for Itime = 1:size(t_analyze_sec,1); 71 | 72 | if ~isempty(t_analyze_sec) 73 | K=find((wT >= t_analyze_sec(Itime,1)) & (wT <= t_analyze_sec(Itime,2))); 74 | mean_cohere(:,Itime) = nanmedian(coherence(:,K)')'; 75 | end 76 | end 77 | 78 | %end 79 | 80 | %linkaxes(ax); 81 | 82 | -------------------------------------------------------------------------------- /Data/2014-04-30 Visual Steady-State Evoked Potentials/functions/calcCoherence.m: -------------------------------------------------------------------------------- 1 | function [coherence,yx_raw,yx_filt]=calcCoherence(fftx,ffty,nave) 2 | 3 | % Basic Form: http://ocw.mit.edu/courses/earth-atmospheric-and-planetary-sciences/12-864-inference-from-data-and-models-spring-2005/lecture-notes/tsamsfmt_1_18.pdf 4 | % Add Averaging: http://www.dsprelated.com/dspbooks/mdft/Coherence_Function.html 5 | % Mostly worthless: http://en.wikipedia.org/wiki/Coherence_(signal_processing) 6 | 7 | 8 | xx = fftx.*conj(fftx); 9 | yy = ffty.*conj(ffty); 10 | yx_raw = conj(fftx).*(ffty); 11 | %coherence = ((abs(yx)).^2)./(xx.*yy); %this always returns 1.0...can't be right 12 | 13 | %ahh, need averaging to see if movement from block to block coherent 14 | b = 1/nave*ones(nave,1); %do a moving average filter over nave blocks 15 | yx_filt = filter(b,1,yx_raw')'; %must filter before the ABS operation (the ABS is later) 16 | xx = filter(b,1,xx')'; 17 | yy = filter(b,1,yy')'; 18 | coherence = (abs(yx_filt).^2)./ (xx.*yy); -------------------------------------------------------------------------------- /Data/2014-04-30 Visual Steady-State Evoked Potentials/functions/evalCoherence_nearbyOnly.asv: -------------------------------------------------------------------------------- 1 | function [mean_cohere,wT,f] = evalCoherence_nearbyOnly(t_sec,data_V,fs,N,overlap,nave,t_analyze_sec,flim); 2 | 3 | compare_chan = [2 1; 4 | 3 1; 5 | 4 2; 6 | 5 3; 7 | 6 4; 8 | 7 5; 9 | 8 6; 10 | 8 7; 11 | ] 12 | 13 | 14 | fig=figure;setFigureTallestWide;ax=[]; 15 | plot_count=0; 16 | noise = 0; 17 | %t_sec = ([1:size(data_V,1)]-1)/fs; 18 | mean_cohere = []; 19 | for Icompare = 1:size(compare_chan,1); 20 | Ichan1 = compare_chan(Icompare,1); 21 | Ichan2 = compare_chan(Icompare,2); 22 | 23 | [fftx,wT,f]=windowedFFT2(t_sec,data_V(:,Ichan1),N,overlap,'hanning'); 24 | wT = wT + (N/2)/fs; 25 | inds = find(f <= fs/2); 26 | 27 | 28 | foo = data_V(:,Ichan2) + noise ; 29 | [ffty,wT,f]=windowedFFT2(t_sec,foo,N,overlap,'hanning'); 30 | wT = wT + (N/2)/fs; 31 | %nave = round(4*(1/(1 - overlap))); 32 | [coherence,yx_raw,yx_filt]=calcCoherence(fftx,ffty,nave); 33 | 34 | figure(fig); 35 | plot_count = plot_count+1; 36 | nrow=5;ncol=12+1;plotwidth=3; 37 | %nrow=5;ncol=12;plotwidth=4; 38 | subplotTightBorder(nrow,ncol,getPosition(ncol,plotwidth,Icompare)); 39 | imagesc(wT,f(inds),coherence(inds,:)); 40 | set(gca,'Ydir','normal'); 41 | if (Ichan2 == Ichan1+1); xlabel('Time (sec)');end 42 | ylabel('Frequency (Hz)'); 43 | title(['Coherence, Ch ' num2str(Ichan1) ' to Ch ' num2str(Ichan2)]); 44 | set(gca,'Clim',[0 1]); 45 | %ylim([0 80]); 46 | ylim(flim); 47 | %xlim(t_sec([1 end])); 48 | xlim(t_sec([1 end])); 49 | % if ~isempty(t_analyze_sec) 50 | % xlim(t_analyze_sec); 51 | % end 52 | cl=get(gca,'Clim'); 53 | %weaText(['Clim = [' num2str(cl(1)) ' ' num2str(cl(2)) '] dB'],1); 54 | ax(end+1)=gca; 55 | 56 | if ~isempty(t_mark_sec); 57 | for Imark=1:size(t_mark_sec,1); 58 | hold on; 59 | yl=ylim; 60 | plot(t_mark_sec(Imark,1)*[1 1],yl,'k--','linewidth',2); 61 | plot(t_mark_sec(Imark,2)*[1 1],yl,'k--','linewidth',2); 62 | hold off 63 | end 64 | end 65 | 66 | %summarize data 67 | K=find((wT >= t_analyze_sec(1)) & (wT <= t_analyze_sec(2))); 68 | mean_cohere(:,Icompare) = nanmedian(coherence(:,K)')'; 69 | 70 | end 71 | 72 | linkaxes(ax); 73 | 74 | 75 | %% %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%5 76 | function pos = getPosition(ncol,plotwidth,Icompare) 77 | 78 | %assume comparing side-by-side around the head 79 | %nwide = 2; 80 | nwide = plotwidth; 81 | switch Icompare 82 | case 1 83 | %top center 84 | pos = floor((ncol / 2) + [0:nwide-1]-(nwide/2-1)); 85 | case 2 86 | %second row, left side, in a smidge 87 | pos = (2-1)*ncol + [1:nwide] + 1; 88 | case 3 89 | %second row, right side, in a smidge 90 | pos = (2-1)*ncol+ ncol+[-(nwide-1):0] - 1; 91 | case 4 92 | %third row, left side 93 | pos = (3-1)*ncol+ [1:nwide]; 94 | case 5 95 | %third row, right side 96 | pos = (3-1)*ncol+ncol+[-(nwide-1):0]; 97 | case 6 98 | %fourth row, left side, in a smidge 99 | pos = (4-1)*ncol+ [1:nwide]+1; 100 | case 7 101 | %fourth row, right side, in a smidge 102 | pos = (4-1)*ncol+ncol+[-(nwide-1):0]-1; 103 | case 8 104 | %fifth row, center 105 | pos = (5-1)*ncol+ floor((ncol / 2) + [0:nwide-1]-(nwide/2-1)); 106 | end 107 | 108 | -------------------------------------------------------------------------------- /Data/2014-04-30 Visual Steady-State Evoked Potentials/functions/evalCoherence_nearbyOnly.m: -------------------------------------------------------------------------------- 1 | function [mean_cohere,wT,f] = evalCoherence_nearbyOnly(t_sec,data_V,fs,N,overlap,nave,t_analyze_sec,flim,plots); 2 | 3 | 4 | % compare_chan = [2 1; 5 | % 3 1; 6 | % 4 2; 7 | % 5 3; 8 | % 6 4; 9 | % 7 5; 10 | % 8 6; 11 | % 8 7; 12 | % ]; 13 | 14 | compare_chan = [2 1; 15 | ]; 16 | 17 | fig=figure;setFigureTallestWide;ax=[]; 18 | plot_count=0; 19 | noise = 0; 20 | %t_sec = ([1:size(data_V,1)]-1)/fs; 21 | mean_cohere = []; 22 | for Icompare = 1:size(compare_chan,1); 23 | Ichan1 = compare_chan(Icompare,1); 24 | Ichan2 = compare_chan(Icompare,2); 25 | 26 | %compute spectra 27 | [fftx,wT,f]=windowedFFT2(t_sec,data_V(:,Ichan1),N,overlap,'hanning'); 28 | wT = wT + (N/2)/fs; 29 | inds = find(f <= fs/2); 30 | 31 | foo = data_V(:,Ichan2) + noise ; 32 | [ffty,wT,f]=windowedFFT2(t_sec,foo,N,overlap,'hanning'); 33 | wT = wT + (N/2)/fs; 34 | 35 | %compute coherence 36 | %nave = round(4*(1/(1 - overlap))); 37 | [coherence,yx_raw,yx_filt]=calcCoherence(fftx,ffty,nave); 38 | wT = wT - (0.75*nave*(1-overlap)*N)/fs; %adjust apparent timing of coherence estimates 39 | 40 | 41 | figure(fig); 42 | plot_count = plot_count+1; 43 | nrow=5;ncol=12;plotwidth=3; 44 | %nrow=5;ncol=12;plotwidth=4; 45 | subplotTightBorder(nrow,ncol,getPosition(ncol,plotwidth,Icompare)); 46 | imagesc(wT,f(inds),coherence(inds,:)); 47 | set(gca,'Ydir','normal'); 48 | if (Icompare >= (size(compare_chan,1)-2)); xlabel('Time (sec)');end 49 | ylabel('Frequency (Hz)'); 50 | title(['Coherence, Ch ' num2str(Ichan1) ' to Ch ' num2str(Ichan2)]); 51 | set(gca,'Clim',[0 1]); 52 | %ylim([0 80]); 53 | ylim(flim); 54 | %xlim(t_sec([1 end])); 55 | xlim(t_sec([1 end])); 56 | % if ~isempty(t_analyze_sec) 57 | % xlim(t_analyze_sec); 58 | % end 59 | cl=get(gca,'Clim'); 60 | %weaText(['Clim = [' num2str(cl(1)) ' ' num2str(cl(2)) '] dB'],1); 61 | ax(end+1)=gca; 62 | 63 | if ~isempty(t_analyze_sec); 64 | for Imark=1:size(t_analyze_sec,1); 65 | hold on; 66 | yl=ylim; 67 | plot(t_analyze_sec(Imark,1)*[1 1],yl,'k--','linewidth',2); 68 | plot(t_analyze_sec(Imark,2)*[1 1],yl,'k--','linewidth',2); 69 | hold off 70 | end 71 | end 72 | 73 | %summarize data 74 | K=find((wT >= t_analyze_sec(1)) & (wT <= t_analyze_sec(2))); 75 | mean_cohere(:,Icompare) = nanmedian(coherence(:,K)')'; 76 | 77 | end 78 | 79 | linkaxes(ax); 80 | 81 | 82 | %% %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%5 83 | function pos = getPosition(ncol,plotwidth,Icompare) 84 | 85 | %assume comparing side-by-side around the head 86 | %nwide = 2; 87 | nwide = plotwidth; 88 | switch Icompare 89 | case 1 90 | %top center 91 | pos = floor((ncol / 2) + [0:nwide-1]-(nwide/2-1)); 92 | case 2 93 | %second row, left side, in a smidge 94 | pos = (2-1)*ncol + [1:nwide] + 1; 95 | case 3 96 | %second row, right side, in a smidge 97 | pos = (2-1)*ncol+ ncol+[-(nwide-1):0] - 1-1; 98 | case 4 99 | %third row, left side 100 | pos = (3-1)*ncol+ [1:nwide]; 101 | case 5 102 | %third row, right side 103 | pos = (3-1)*ncol+ncol+[-(nwide-1):0]-1; 104 | case 6 105 | %fourth row, left side, in a smidge 106 | pos = (4-1)*ncol+ [1:nwide]+1; 107 | case 7 108 | %fourth row, right side, in a smidge 109 | pos = (4-1)*ncol+ncol+[-(nwide-1):0]-1-1; 110 | case 8 111 | %fifth row, center 112 | pos = (5-1)*ncol+ floor((ncol / 2) + [0:nwide-1]-(nwide/2-1)); 113 | end 114 | 115 | -------------------------------------------------------------------------------- /Data/2014-04-30 Visual Steady-State Evoked Potentials/functions/plotSpectrograms_headshape.m: -------------------------------------------------------------------------------- 1 | function [mean_cohere,wT,f] = evalCoherence_nearbyOnly(t_sec,data_V,fs,N,overlap,nave,t_analyze_sec,flim); 2 | 3 | compare_chan = [2 1; 4 | 3 1; 5 | 4 2; 6 | 5 3; 7 | 6 4; 8 | 7 5; 9 | 8 6; 10 | 8 7; 11 | ] 12 | 13 | 14 | fig=figure;setFigureTallestWide;ax=[]; 15 | plot_count=0; 16 | noise = 0; 17 | %t_sec = ([1:size(data_V,1)]-1)/fs; 18 | mean_cohere = []; 19 | for Icompare = 1:size(compare_chan,1); 20 | Ichan1 = compare_chan(Icompare,1); 21 | Ichan2 = compare_chan(Icompare,2); 22 | 23 | [fftx,wT,f]=windowedFFT2(t_sec,data_V(:,Ichan1),N,overlap,'hanning'); 24 | wT = wT + (N/2)/fs; 25 | inds = find(f <= fs/2); 26 | 27 | 28 | foo = data_V(:,Ichan2) + noise ; 29 | [ffty,wT,f]=windowedFFT2(t_sec,foo,N,overlap,'hanning'); 30 | wT = wT + (N/2)/fs; 31 | %nave = round(4*(1/(1 - overlap))); 32 | [coherence,yx_raw,yx_filt]=calcCoherence(fftx,ffty,nave); 33 | 34 | figure(fig); 35 | plot_count = plot_count+1; 36 | nrow=5;ncol=12+1;plotwidth=3; 37 | %nrow=5;ncol=12;plotwidth=4; 38 | subplotTightBorder(nrow,ncol,getPosition(ncol,plotwidth,Icompare)); 39 | imagesc(wT,f(inds),coherence(inds,:)); 40 | set(gca,'Ydir','normal'); 41 | if (Ichan2 == Ichan1+1); xlabel('Time (sec)');end 42 | ylabel('Frequency (Hz)'); 43 | title(['Coherence, Ch ' num2str(Ichan1) ' to Ch ' num2str(Ichan2)]); 44 | set(gca,'Clim',[0 1]); 45 | %ylim([0 80]); 46 | ylim(flim); 47 | xlim(t_sec([1 end])); 48 | if ~isempty(t_analyze_sec) 49 | xlim(t_analyze_sec); 50 | end 51 | cl=get(gca,'Clim'); 52 | %weaText(['Clim = [' num2str(cl(1)) ' ' num2str(cl(2)) '] dB'],1); 53 | ax(end+1)=gca; 54 | 55 | %summarize data 56 | K=find((wT >= t_analyze_sec(1)) & (wT <= t_analyze_sec(2))); 57 | mean_cohere(:,Icompare) = nanmedian(coherence(:,K)')'; 58 | 59 | end 60 | 61 | linkaxes(ax); 62 | 63 | 64 | %% %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%5 65 | function pos = getPosition(ncol,plotwidth,Icompare) 66 | 67 | %assume comparing side-by-side around the head 68 | %nwide = 2; 69 | nwide = plotwidth; 70 | switch Icompare 71 | case 1 72 | %top center 73 | pos = floor((ncol / 2) + [0:nwide-1]-(nwide/2-1)); 74 | case 2 75 | %second row, left side, in a smidge 76 | pos = (2-1)*ncol + [1:nwide] + 1; 77 | case 3 78 | %second row, right side, in a smidge 79 | pos = (2-1)*ncol+ ncol+[-(nwide-1):0] - 1; 80 | case 4 81 | %third row, left side 82 | pos = (3-1)*ncol+ [1:nwide]; 83 | case 5 84 | %third row, right side 85 | pos = (3-1)*ncol+ncol+[-(nwide-1):0]; 86 | case 6 87 | %fourth row, left side, in a smidge 88 | pos = (4-1)*ncol+ [1:nwide]+1; 89 | case 7 90 | %fourth row, right side, in a smidge 91 | pos = (4-1)*ncol+ncol+[-(nwide-1):0]-1; 92 | case 8 93 | %fifth row, center 94 | pos = (5-1)*ncol+ floor((ncol / 2) + [0:nwide-1]-(nwide/2-1)); 95 | end 96 | 97 | -------------------------------------------------------------------------------- /Data/2014-05-08 Multi-Rate Visual Evoked Potentials/SavedData.zip: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/chipaudette/EEGHacker/f72cc121d51fb5ea2f9176ebc0bb821aef05e64e/Data/2014-05-08 Multi-Rate Visual Evoked Potentials/SavedData.zip -------------------------------------------------------------------------------- /Data/2014-05-08 Multi-Rate Visual Evoked Potentials/exploreData.m: -------------------------------------------------------------------------------- 1 | 2 | %given_amp_counts = 4.5/2.4e-3; 3 | 4 | f_lim = [0 25]; 5 | pname = 'SavedData\'; 6 | 7 | 8 | fname = 'openBCI_raw_2014-05-08_20-52-43_Block1_15HzToggle_10HzToggle.txt'; nchan=3; 9 | %fname = 'openBCI_raw_2014-05-08_21-24-31_countbackby3_countbackby41from1200.txt';nchan=3;f_lim = [0 100]; 10 | scale_fac_volts_count=2.23e-8; 11 | 12 | 13 | 14 | 15 | %% load data 16 | data_uV = load([pname fname]); %loads data as microvolts 17 | data_uV = data_uV(:,[1:nchan+1]); 18 | %fs = data2.fs_Hz; 19 | fs = 250; 20 | count = data_uV(:,1); %first column is a packet counter (though it's broken) 21 | data_V = data_uV(:,2:end) * 1e-6; %other columns are data 22 | clear data_uV; 23 | 24 | %% filter data 25 | data_V = data_V - ones(size(data_V,1),1)*mean(data_V); 26 | %[b,a]=butter(2,[0.2 50]/(fs/2)); 27 | [b,a]=butter(2,0.2/(fs/2),'high'); 28 | data_V = filter(b,a,data_V); 29 | [b,a]=butter(3,[55 65]/(fs/2),'stop'); 30 | data_V = filter(b,a,data_V); 31 | % [b,a]=butter(3,[65 75]/(fs/2),'stop'); 32 | % data_V = filter(b,a,data_V); 33 | 34 | %% write to WAV 35 | % fs_dec = fs;foo_V = data_V; 36 | % %foo_V = resample(data_V,1,2); fs_dec = fs / 2; %decimate 37 | % outfname = ['WAVs\' fname(1:end-4) '.wav']; 38 | % disp(['writing to ' outfname]); 39 | % wavwrite(foo_V(:,1:min([size(data_V,2) 2]))*1e6/500,fs_dec,16,outfname); 40 | 41 | 42 | %% analyze data 43 | mean_data_V = mean(data_V); 44 | median_data_V = median(data_V); 45 | std_data_V = std(data_V); 46 | spread_data_V = diff(xpercentile(data_V,0.5+(0.68-0.5)*[-1 1]))/2; 47 | spread_data_V = median(spread_data_V)*ones(size(spread_data_V)); 48 | 49 | %% plot data 50 | t_sec = ([1:size(data_V,1)]-1)/fs; 51 | nrow = max([2 size(data_V,2)]); ncol=2; 52 | ax=[]; 53 | figure;setFigureTallestWidest; 54 | for Ichan=1:size(data_V,2); 55 | 56 | %time-domain plot 57 | subplotTightBorder(nrow,ncol,(Ichan-1)*2+1); 58 | plot(t_sec,data_V(:,Ichan)*1e6); 59 | xlim(t_sec([1 end])); 60 | %ylim(1e6*(median_data_V(Ichan)+3*[-1 1]*spread_data_V(Ichan))); 61 | ylim([-200 200]); 62 | weaText({['Mean = ' num2str(mean(data_V(:,Ichan))*1e6,3) ' uV']; 63 | ['Std = ' num2str(std(data_V(:,Ichan))*1e6,3) ' uV']},2); 64 | title(['Channel ' num2str(Ichan)]); 65 | xlabel(['Time (sec)']); 66 | ylabel(['Signal (uV)']); 67 | ax(end+1)=gca; 68 | 69 | %spectrogram 70 | subplotTightBorder(nrow,ncol,(Ichan-1)*2+2); 71 | %N=1024; 72 | %N=1200;overlap = 1-1/32;plots=0; 73 | %N = 2400;overlap = 1-1/64;plots=0; yl=[0 15]; 74 | N=512;overlap = 1-1/16;plots=0; 75 | %yl=[0 fs/2]; 76 | [pD,wT,f]=windowedFFTPlot_spectragram(data_V(:,Ichan)*1e6,N,overlap,fs,plots); 77 | wT = wT + (N/2)/fs; 78 | 79 | %smooth in time 80 | % n_ave = 1; 81 | % b = 1/n_ave* ones(n_ave,1);a=1; 82 | % pD = filter(b,a,pD')'; 83 | 84 | imagesc(wT,f,10*log10(pD)); 85 | set(gca,'Ydir','normal'); 86 | xlabel('Time (sec)'); 87 | ylabel('Frequency (Hz)'); 88 | ylim(f_lim); 89 | title([fname ', Channel ' num2str(Ichan)],'interpreter','none'); 90 | set(gca,'Clim',+20+[-40 0]+10*log10(256)-10*log10(N)); 91 | xlim(t_sec([1 end])); 92 | cl=get(gca,'Clim'); 93 | h=weaText({['Nfft = ' num2str(N) ', fs = ' num2str(fs) ' Hz'];['Clim = [' num2str(round(cl(1))) ' ' num2str(round(cl(2))) '] dB']},1); 94 | set(h,'BackgroundColor','white'); 95 | ax(end+1)=gca; 96 | end 97 | 98 | linkaxes(ax,'x'); 99 | -------------------------------------------------------------------------------- /Data/2014-05-08 Multi-Rate Visual Evoked Potentials/exploreData_wAux.m: -------------------------------------------------------------------------------- 1 | 2 | %given_amp_counts = 4.5/2.4e-3; 3 | 4 | f_lim = [0 22]; 5 | pname = 'SavedData\'; 6 | 7 | %fname = 'openBCI_raw_2014-05-08_20-26-47_EyesClosedSeperates_Left_Right_Left_Right_Both.txt';nchan=3; 8 | %fname = 'openBCI_raw_2014-05-08_20-37-56_1block_fullscreenblink_15secSegments.txt';nhcan=3; 9 | %fname = 'openBCI_raw_2014-05-08_20-45-00_Block1_10HzToggle_6.67HzToggle.txt';nchan=3; 10 | %fname = 'openBCI_raw_2014-05-08_20-47-30_Block1_20HzToggle_15HzToggle.txt';nchan=3; 11 | %fname = 'openBCI_raw_2014-05-08_20-50-15_Block1_10HzToggle_3.33HzToggle.txt';nchan=3; 12 | fname = 'openBCI_raw_2014-05-08_20-52-43_Block1_15HzToggle_10HzToggle.txt';nchan=3; %best? 13 | %fname = 'openBCI_raw_2014-05-08_21-03-08_Block1_15HzToggle_10HzToggle_wAux.txt';nchan=3; %best? 14 | %fname = 'openBCI_raw_2014-05-08_21-08-33_Block1_10HzToggle_6.67HzToggle_wAux.txt';nchan=3; 15 | %fname = 'openBCI_raw_2014-05-08_21-12-01_Block1_15HzToggle_10HzToggle_followFastOne.txt'; nchan=3; 16 | %fname = 'openBCI_raw_2014-05-08_21-24-31_countbackby3_countbackby41from1200.txt';nchan=3;f_lim = [0 100]; 17 | scale_fac_volts_count=2.23e-8; 18 | 19 | 20 | 21 | 22 | %% load data 23 | data_uV = load([pname fname]); %loads data as microvolts 24 | data_uV = data_uV(:,[1:nchan+1 size(data_uV,2)]); %get aux, too 25 | %fs = data2.fs_Hz; 26 | fs = 250; 27 | count = data_uV(:,1); %first column is a packet counter (though it's broken) 28 | data_V = data_uV(:,2:end) * 1e-6; %other columns are data 29 | clear data_uV; 30 | 31 | %% filter data 32 | data_V = data_V - ones(size(data_V,1),1)*mean(data_V); 33 | %[b,a]=butter(2,[0.2 50]/(fs/2)); 34 | [b,a]=butter(2,0.2/(fs/2),'high'); 35 | data_V = filter(b,a,data_V); 36 | [b,a]=butter(3,[55 65]/(fs/2),'stop'); 37 | data_V = filter(b,a,data_V); 38 | % [b,a]=butter(3,[65 75]/(fs/2),'stop'); 39 | % data_V = filter(b,a,data_V); 40 | 41 | %% write to WAV 42 | % fs_dec = fs;foo_V = data_V; 43 | % %foo_V = resample(data_V,1,2); fs_dec = fs / 2; %decimate 44 | % outfname = ['WAVs\' fname(1:end-4) '.wav']; 45 | % disp(['writing to ' outfname]); 46 | % wavwrite(foo_V(:,1:min([size(data_V,2) 2]))*1e6/500,fs_dec,16,outfname); 47 | 48 | 49 | %% analyze data 50 | % mean_data_V = mean(data_V); 51 | % median_data_V = median(data_V); 52 | % std_data_V = std(data_V); 53 | % spread_data_V = diff(xpercentile(data_V,0.5+(0.68-0.5)*[-1 1]))/2; 54 | % spread_data_V = median(spread_data_V)*ones(size(spread_data_V)); 55 | 56 | %% plot data 57 | t_sec = ([1:size(data_V,1)]-1)/fs; 58 | nrow = max([2 size(data_V,2)]); ncol=2; 59 | ax=[]; 60 | figure;setFigureTallestWidest; 61 | for Ichan=1:size(data_V,2); 62 | 63 | %time-domain plot 64 | subplotTightBorder(nrow,ncol,(Ichan-1)*2+1); 65 | plot(t_sec,data_V(:,Ichan)*1e6); 66 | xlim(t_sec([1 end])); 67 | %ylim(1e6*(median_data_V(Ichan)+3*[-1 1]*spread_data_V(Ichan))); 68 | ylim([-200 200]); 69 | weaText({['Mean = ' num2str(mean(data_V(:,Ichan))*1e6,3) ' uV']; 70 | ['Std = ' num2str(std(data_V(:,Ichan))*1e6,3) ' uV']},2); 71 | title(['Channel ' num2str(Ichan)]); 72 | xlabel(['Time (sec)']); 73 | ylabel(['Signal (uV)']); 74 | ax(end+1)=gca; 75 | 76 | %spectrogram 77 | subplotTightBorder(nrow,ncol,(Ichan-1)*2+2); 78 | %N=1024; 79 | %N=1200;overlap = 1-1/32;plots=0; 80 | %N = 2400;overlap = 1-1/64;plots=0; yl=[0 15]; 81 | N=512;overlap = 1-1/16;plots=0; 82 | [pD,wT,f]=windowedFFTPlot_spectragram(data_V(:,Ichan)*1e6,N,overlap,fs,plots); 83 | wT = wT + (N/2)/fs; 84 | 85 | imagesc(wT,f,10*log10(pD)); 86 | set(gca,'Ydir','normal'); 87 | xlabel('Time (sec)'); 88 | ylabel('Frequency (Hz)'); 89 | title([fname ', Channel ' num2str(Ichan)],'interpreter','none'); 90 | set(gca,'Clim',+20+[-40 0]+10*log10(256)-10*log10(N)); 91 | xlim(t_sec([1 end])); 92 | ylim(f_lim); 93 | cl=get(gca,'Clim'); 94 | h=weaText({['Nfft = ' num2str(N) ', fs = ' num2str(fs) ' Hz'];['Clim = [' num2str(round(cl(1))) ' ' num2str(round(cl(2))) '] dB']},1); 95 | set(h,'BackgroundColor','white'); 96 | ax(end+1)=gca; 97 | end 98 | 99 | linkaxes(ax,'x'); 100 | -------------------------------------------------------------------------------- /Data/2014-05-31 RobotControl/.picasa.ini: -------------------------------------------------------------------------------- 1 | [MVI_2940.MOV] 2 | filters=moviestart=2ed15f7; 3 | backuphash=5851 4 | -------------------------------------------------------------------------------- /Data/2014-05-31 RobotControl/AnalysisResults/Detection Results.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/chipaudette/EEGHacker/f72cc121d51fb5ea2f9176ebc0bb821aef05e64e/Data/2014-05-31 RobotControl/AnalysisResults/Detection Results.png -------------------------------------------------------------------------------- /Data/2014-05-31 RobotControl/AnalysisResults/Detection Rules.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/chipaudette/EEGHacker/f72cc121d51fb5ea2f9176ebc0bb821aef05e64e/Data/2014-05-31 RobotControl/AnalysisResults/Detection Rules.png -------------------------------------------------------------------------------- /Data/2014-05-31 RobotControl/AnalysisResults/RawDataSpectrograms.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/chipaudette/EEGHacker/f72cc121d51fb5ea2f9176ebc0bb821aef05e64e/Data/2014-05-31 RobotControl/AnalysisResults/RawDataSpectrograms.png -------------------------------------------------------------------------------- /Data/2014-05-31 RobotControl/AnalysisResults/RawDataSpectrum.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/chipaudette/EEGHacker/f72cc121d51fb5ea2f9176ebc0bb821aef05e64e/Data/2014-05-31 RobotControl/AnalysisResults/RawDataSpectrum.png -------------------------------------------------------------------------------- /Data/2014-05-31 RobotControl/BlogPics/DecideCommand.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/chipaudette/EEGHacker/f72cc121d51fb5ea2f9176ebc0bb821aef05e64e/Data/2014-05-31 RobotControl/BlogPics/DecideCommand.png -------------------------------------------------------------------------------- /Data/2014-05-31 RobotControl/BlogPics/EEG Processing.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/chipaudette/EEGHacker/f72cc121d51fb5ea2f9176ebc0bb821aef05e64e/Data/2014-05-31 RobotControl/BlogPics/EEG Processing.png -------------------------------------------------------------------------------- /Data/2014-05-31 RobotControl/BlogPics/Figures.ppt: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/chipaudette/EEGHacker/f72cc121d51fb5ea2f9176ebc0bb821aef05e64e/Data/2014-05-31 RobotControl/BlogPics/Figures.ppt -------------------------------------------------------------------------------- /Data/2014-05-31 RobotControl/BlogPics/Setup-Schematic.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/chipaudette/EEGHacker/f72cc121d51fb5ea2f9176ebc0bb821aef05e64e/Data/2014-05-31 RobotControl/BlogPics/Setup-Schematic.png -------------------------------------------------------------------------------- /Data/2014-05-31 RobotControl/BlogPics/Setup-Schematic2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/chipaudette/EEGHacker/f72cc121d51fb5ea2f9176ebc0bb821aef05e64e/Data/2014-05-31 RobotControl/BlogPics/Setup-Schematic2.png -------------------------------------------------------------------------------- /Data/2014-05-31 RobotControl/BlogPics/Setup.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/chipaudette/EEGHacker/f72cc121d51fb5ea2f9176ebc0bb821aef05e64e/Data/2014-05-31 RobotControl/BlogPics/Setup.png -------------------------------------------------------------------------------- /Data/2014-05-31 RobotControl/BlogPics/Spectrum-Forward.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/chipaudette/EEGHacker/f72cc121d51fb5ea2f9176ebc0bb821aef05e64e/Data/2014-05-31 RobotControl/BlogPics/Spectrum-Forward.png -------------------------------------------------------------------------------- /Data/2014-05-31 RobotControl/BlogPics/Spectrum-TurnLeft.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/chipaudette/EEGHacker/f72cc121d51fb5ea2f9176ebc0bb821aef05e64e/Data/2014-05-31 RobotControl/BlogPics/Spectrum-TurnLeft.png -------------------------------------------------------------------------------- /Data/2014-05-31 RobotControl/BlogPics/Spectrum-TurnRight.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/chipaudette/EEGHacker/f72cc121d51fb5ea2f9176ebc0bb821aef05e64e/Data/2014-05-31 RobotControl/BlogPics/Spectrum-TurnRight.png -------------------------------------------------------------------------------- /Data/2014-05-31 RobotControl/RobotMotionTimingRelMovie.xlsx: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/chipaudette/EEGHacker/f72cc121d51fb5ea2f9176ebc0bb821aef05e64e/Data/2014-05-31 RobotControl/RobotMotionTimingRelMovie.xlsx -------------------------------------------------------------------------------- /Data/2014-05-31 RobotControl/SavedData/openBCI_raw_2014-05-31_20-48-01_RobotControlAll.zip: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/chipaudette/EEGHacker/f72cc121d51fb5ea2f9176ebc0bb821aef05e64e/Data/2014-05-31 RobotControl/SavedData/openBCI_raw_2014-05-31_20-48-01_RobotControlAll.zip -------------------------------------------------------------------------------- /Data/2014-05-31 RobotControl/analysis.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | """ 3 | Created on Tue Jul 01 12:20:20 2014 4 | 5 | @author: wea 6 | """ 7 | 8 | import matplotlib 9 | import matplotlib.pyplot as plt 10 | import numpy as np 11 | from scipy import signal 12 | import math 13 | from c2cb import c2cb 14 | 15 | pname = "SavedData\\" 16 | fname = "openBCI_raw_2014-05-31_20-57-51_Robot05.txt" 17 | t_plot_sec = [0.0, 135.0] 18 | fs_Hz = 250.0 #sample rate 19 | 20 | #load data 21 | fullfname = pname+fname 22 | print("loading from: " + fullfname) 23 | data = np.loadtxt(fullfname,delimiter=',',comments='%') 24 | 25 | 26 | #parse the data 27 | (r,c) = data.shape 28 | print 'Size of data = %i, %i' % (r, c) 29 | data_counter = data[:,0] # get just first column 30 | data = data[:,1:] #remove first column 31 | (r,c) = data.shape 32 | print 'Size of data = %i, %i' % (r, c) 33 | if (c < 16): 34 | naux = c-8 35 | else: 36 | naux = c-16 37 | data_aux = data[:,-naux:] 38 | data = data[:,:-naux] 39 | (r,c) = data.shape 40 | print 'Size of data = %i, %i' % (r, c) 41 | 42 | 43 | # High-pass filter 44 | Ichan = 2-1 45 | N = 2 46 | hp_Hz = 1.0 47 | (b, a) = signal.butter(N, hp_Hz / (fs_Hz / 2.0), 'high') 48 | filter_axis = 0 49 | data_filt = signal.lfilter(b, a, data, filter_axis) 50 | 51 | bp_Hz =np.array([8.0, 14.0]) 52 | (b, a) = signal.butter(N, bp_Hz / (fs_Hz / 2.0), 'bandpass') 53 | filter_axis = 0 54 | data_filt_bp = signal.lfilter(b, a, data, filter_axis) 55 | 56 | # compute the spectrogram 57 | Nfft = 512 58 | novrlap = Nfft-50 59 | (Pxx,freqs,t) = plt.mlab.specgram(data_filt[:,Ichan],Nfft,fs_Hz,noverlap=novrlap) 60 | Pxx = np.array(Pxx) 61 | Pxx = Pxx 62 | 63 | #smooth the spectrogram in log space 64 | smooth_fac = 0.9; 65 | b = np.array([1.0-smooth_fac]) 66 | a = np.array([1.0, -smooth_fac]) 67 | Pxx_dB = np.log10(Pxx) 68 | Pxx_dB = signal.lfilter(b,a,Pxx_dB) 69 | Pxx = np.power(10.0,Pxx_dB) 70 | 71 | 72 | #plot the data 73 | t_sec = (data_counter-data_counter[0])/fs_Hz 74 | 75 | plt.figure(figsize=(14,12)) 76 | 77 | plt.subplot(3,1,1) 78 | plt.tight_layout() #add space between plots 79 | plt.plot(t_sec,data[:,Ichan]) 80 | plt.title("Channel " + str(Ichan) + '\n' + fname) 81 | plt.xlabel("Time (sec)") 82 | plt.ylabel('Microvolts') 83 | #plt.xlim(0,t_sec[-1]) 84 | plt.xlim(t_plot_sec) 85 | xl = plt.xlim() 86 | 87 | plt.subplot(3,1,2) 88 | plt.tight_layout() #add space between plots 89 | plt.plot(t_sec,data_filt[:,Ichan],t_sec,data_filt_bp[:,Ichan]) 90 | plt.ylim(-100,100) 91 | plt.title("Filtered, Channel " + str(Ichan)) 92 | plt.xlabel("Time (sec)") 93 | plt.ylabel('Microvolts') 94 | plt.xlim(xl) 95 | plt.legend(['HP','BP']) 96 | 97 | plt.subplot(3,1,3) 98 | plt.tight_layout() 99 | plt.pcolormesh(t,freqs,10.0*np.log10(Pxx)) 100 | cl = np.array([-30.0, 0.0]) 101 | plt.clim(cl+18.0) 102 | plt.xlim(xl) 103 | plt.ylim(0,22) 104 | plt.xlabel("Time (sec)") 105 | plt.ylabel("Frequency (Hz)") 106 | plt.title("Power Spectral Density") 107 | plt.ion() 108 | plt.show() 109 | 110 | -------------------------------------------------------------------------------- /Data/2014-05-31 RobotControl/c2cb.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | """ 3 | Created on Tue Jul 01 14:59:44 2014 4 | 5 | @author: mpu 6 | """ 7 | from matplotlib.pyplot import gcf 8 | import win32clipboard 9 | import tempfile 10 | from PIL import Image 11 | import os 12 | from cStringIO import StringIO 13 | 14 | def c2cb(fformat='png'): 15 | fig = gcf() 16 | fid = tempfile.NamedTemporaryFile(suffix=fformat, delete=False) 17 | fid.close() 18 | fig.savefig(fid.name, format=fformat) 19 | image = Image.open(fid.name) 20 | output = StringIO() 21 | image.convert("RGB").save(output, "BMP") 22 | data = output.getvalue()[14:] 23 | output.close() 24 | 25 | send_to_clipboard(win32clipboard.CF_DIB, data) 26 | del image 27 | 28 | os.remove(fid.name) 29 | 30 | def send_to_clipboard(clip_type, data): 31 | win32clipboard.OpenClipboard() 32 | win32clipboard.EmptyClipboard() 33 | win32clipboard.SetClipboardData(clip_type, data) 34 | win32clipboard.CloseClipboard() 35 | -------------------------------------------------------------------------------- /Data/2014-05-31 RobotControl/makeBlinkingMovie/ThreeSpeedMovie/Block1_20Hz_12Hz_15HzToggle.mp4: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/chipaudette/EEGHacker/f72cc121d51fb5ea2f9176ebc0bb821aef05e64e/Data/2014-05-31 RobotControl/makeBlinkingMovie/ThreeSpeedMovie/Block1_20Hz_12Hz_15HzToggle.mp4 -------------------------------------------------------------------------------- /Data/2014-05-31 RobotControl/makeBlinkingMovie/TwoSpeedMovie/MP4/Block1_15HzToggle_10HzToggle.mp4: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/chipaudette/EEGHacker/f72cc121d51fb5ea2f9176ebc0bb821aef05e64e/Data/2014-05-31 RobotControl/makeBlinkingMovie/TwoSpeedMovie/MP4/Block1_15HzToggle_10HzToggle.mp4 -------------------------------------------------------------------------------- /Data/2014-05-31 RobotControl/makeBlinkingMovie/makeBlinkingMovie_1speed.m: -------------------------------------------------------------------------------- 1 | % Created: Chip Audette, http://eeghacker.blogspot.com 2 | % Date: May 2014 3 | % Purpose: Create blinking movies at different rates 4 | % Platform: Matlab 7.1 on Windows XP 5 | % License: The MIT License (MIT) 6 | 7 | % Choose aspect ratio for the movie 8 | width_vs_height = 16/9; 9 | 10 | %make color map for the movie 11 | map = ones(256,3); %create color map, all white 12 | map(1,:) = 1; %modify color map by making first entry as black 13 | 14 | % make the black and white frames 15 | hblock = 64; 16 | wblock = round(64*width_vs_height); 17 | nblock=1; 18 | npix_w=wblock*nblock; 19 | npix_h=hblock*nblock; 20 | X1 = uint8(ones(npix_h,npix_w)); 21 | X2 = uint8(zeros(npix_h,npix_w)); 22 | 23 | 24 | % view the two frames 25 | figure; 26 | try;setFigureWide;catch;end 27 | subplot(1,2,1); 28 | try;imshow(X1,map);catch;image(X1);colormap(map);end 29 | title('Frame 1'); 30 | axis equal;axis tight; 31 | subplot(1,2,2); 32 | try;imshow(X2,map);catch;image(X2);end 33 | title('Frame 2'); 34 | axis equal;axis tight; 35 | 36 | % loop to make individual movies at the desired blink rates 37 | desired_rates_Hz = [1:20]; %this sets the white-to-white blink rate 38 | for Irate = 1:length(desired_rates_Hz) 39 | desired_rate_Hz = desired_rates_Hz(Irate); 40 | 41 | %fabricate series of movies 42 | desired_rate_Hz = desired_rates_Hz(Irate); %for complete cycle of X1 and X2 together 43 | desired_duration_sec = 15; 44 | n_frames = round(desired_rate_Hz * desired_duration_sec) 45 | clear M 46 | for I = 1:n_frames 47 | M((I-1)*2+1)=im2frame(X1,map); 48 | M((I-1)*2+2)=im2frame(X2,map); 49 | end 50 | 51 | % watch movie 52 | %figure;setFigureTallWide;set(gcf,'DoubleBuffer','on');movie(M,1,desired_rate_Hz*2); 53 | 54 | % save movie 55 | outpname=['Movies_' num2str(nblock) 'block\']; 56 | try;mkdir(outpname);catch;end; 57 | outfname = [outpname 'checkerboard' num2str(nblock) '_rate' num2str(desired_rate_Hz) 'HzX2']; 58 | if (1) 59 | %write as AVI 60 | outfname = [outfname '.avi']; 61 | disp(['Writing to ' outfname]); 62 | movie2avi(M,outfname,'Compression','none','FPS',desired_rate_Hz*2); 63 | else 64 | %write as WMV...doesn't seem to work anymore. So, I'll use the AVI and 65 | %then use windows movie maker to convert to WMV 66 | clear video2 67 | video2.width=size(M(1).cdata,2); 68 | video2.height=size(M(1).cdata,1); 69 | video2.frames=M; 70 | video2.rate=desired_rate_Hz*2; 71 | video2.times=[0:1:length(M)-1] /video2.rate; 72 | 73 | outfname = [outfname '.wmv']; 74 | disp(['Writing to ' outfname]); 75 | mmwrite(outfname,video2); 76 | end 77 | end 78 | -------------------------------------------------------------------------------- /Data/2014-05-31 RobotControl/makeBlinkingMovie/makeBlinkingMovie_2speeds.m: -------------------------------------------------------------------------------- 1 | % Created: Chip Audette, http://eeghacker.blogspot.com 2 | % Date: May 2014 3 | % Purpose: Create movies with two simultaneous blink rates, 4 | % one blink rate on the left and another blink rate on 5 | % the right. 6 | % Platform: Matlab 7.1 on Windows XP 7 | % License: The MIT License (MIT) 8 | 9 | %make black and white frames 10 | if (1) 11 | map = ones(256,3); %all white 12 | map(1,:) = 0; %black 13 | 14 | % make the two frames...all black and all white 15 | width_vs_height = 16/9; 16 | hblock = 64; 17 | wblock = round(hblock*width_vs_height/2); 18 | nblock=1; 19 | npix_w=wblock*nblock; 20 | npix_h=hblock*nblock; 21 | Xwhite = ones(npix_h,npix_w); 22 | Xblack = ~Xwhite; 23 | 24 | %put a dot in the middle of the white one 25 | np=1; 26 | xcenter = round(wblock/2)-1; 27 | hcenter = round(hblock/2)-1; 28 | Xwhite(hcenter-2,xcenter)=0; 29 | Xwhite(hcenter,xcenter+[-2 2])=0; 30 | Xwhite(hcenter+2,xcenter)=0; 31 | 32 | %convert to "byte" 33 | Xwhite = uint8(Xwhite); 34 | Xblack = uint8(Xblack); 35 | end 36 | 37 | %choose the blinking rate 38 | switch 3 39 | case 1 40 | overall_toggle_Hz = 60; 41 | nleft = 3; 42 | nright = 4; 43 | case 2 44 | overall_toggle_Hz = 30; 45 | nleft = 2; 46 | nright = 3; 47 | case 3 48 | overall_toggle_Hz = 20; 49 | nleft = 2; 50 | nright = 3; 51 | end 52 | left_toggle_Hz = overall_toggle_Hz/nleft; 53 | right_toggle_Hz = overall_toggle_Hz/nright; 54 | 55 | %set the movie diration 56 | if (0) 57 | %I did this branch for my first successful 2-speed EEG Hacker post 58 | desired_duration_sec = 20; 59 | n_swap = 4; % how many times to swap the left and right sides 60 | else 61 | %I did this branch to produce actual useful movies for my BCI 62 | desired_duration_sec = 30; 63 | n_swap = 1; % don't switch sides 64 | end 65 | nframes = round(desired_duration_sec*overall_toggle_Hz); 66 | 67 | %create the movie 68 | n_frames = round(overall_toggle_Hz * desired_duration_sec) 69 | M=[]; 70 | left_state=0;right_state=0; 71 | for Iswap=1:n_swap 72 | for I = 1:n_frames 73 | %change states (ie, change which side the movie is on) 74 | if (rem(I-1,nleft)==0); 75 | left_state = ~left_state; 76 | end 77 | if(rem(I-1,nright)==0); 78 | right_state = ~right_state; 79 | end 80 | 81 | %choose which is the left and which is the right image 82 | XL = Xblack; XR = Xblack; 83 | if (left_state), XL = Xwhite;end 84 | if (right_state), XR = Xwhite; end; 85 | 86 | %build the composite left+right image 87 | if (rem(Iswap,2)==1) 88 | X = [XL XR]; 89 | else 90 | X = [XR XL]; 91 | end 92 | 93 | %save to movie 94 | if isempty(M) 95 | M = im2frame(X,map); 96 | else 97 | M(end+1) = im2frame(X,map); 98 | end 99 | 100 | end 101 | end 102 | 103 | % watch movie 104 | %figure;setFigureTallWide;set(gcf,'DoubleBuffer','on');movie(M,1,desired_rate_Hz*2); 105 | 106 | % save movie as AVI 107 | outpname=['TwoSpeedMovie\']; 108 | try;mkdir(outpname);catch;end; 109 | outfname = [outpname 'Block' num2str(nblock) ... 110 | '_' num2str(left_toggle_Hz,3) 'HzToggle' ... 111 | '_' num2str(right_toggle_Hz,3) 'HzToggle']; 112 | 113 | outfname = [outfname '.avi']; 114 | disp(['Writing to ' outfname]); 115 | try;eval(['!del "' outfname '"']);catch;end; %for WINDOWS! 116 | movie2avi(M,outfname,'Compression','none','FPS',overall_toggle_Hz); 117 | 118 | 119 | -------------------------------------------------------------------------------- /Data/2014-05-31 RobotControl/makeBlinkingMovie/makeBlinkingMovie_3speeds.m: -------------------------------------------------------------------------------- 1 | % Created: Chip Audette, http://eeghacker.blogspot.com 2 | % Date: May 2014 3 | % Purpose: Create movies with two simultaneous blink rates, 4 | % one blink rate on the left and another blink rate on 5 | % the right. 6 | % Platform: Matlab 7.1 on Windows XP 7 | % License: The MIT License (MIT) 8 | 9 | %make black and white frames 10 | if (1) 11 | map = ones(256,3); %all white 12 | map(1,:) = 0; %black 13 | 14 | % make the two frames...all black and all white 15 | width_vs_height = 16/9; 16 | hblock = 64; 17 | wblock = round(hblock*width_vs_height/3); 18 | nblock=1; 19 | npix_w=wblock*nblock; 20 | npix_h=hblock*nblock; 21 | Xwhite = ones(npix_h,npix_w); 22 | Xblack = ~Xwhite; 23 | 24 | %put a dot in the middle of the white one 25 | np=1; 26 | xcenter = round(wblock/2)-1; 27 | hcenter = round(hblock/2)-1; 28 | Xwhite(hcenter-2,xcenter)=0; 29 | Xwhite(hcenter,xcenter+[-2 2])=0; 30 | Xwhite(hcenter+2,xcenter)=0; 31 | 32 | %convert to "byte" 33 | Xwhite = uint8(Xwhite); 34 | Xblack = uint8(Xblack); 35 | end 36 | 37 | %choose the blinking rate 38 | switch 3 39 | case 1 40 | overall_toggle_Hz = 60; 41 | nleft = 3; 42 | nright = 4; 43 | ncenter = 5; 44 | case 2 45 | overall_toggle_Hz = 30; 46 | nleft = 2; 47 | nright = 3; 48 | ncenter = 5; 49 | case 3 50 | overall_toggle_Hz = 20; 51 | nleft = 2; 52 | nright = 3; 53 | ncenter = 5; 54 | end 55 | left_toggle_Hz = overall_toggle_Hz/nleft; 56 | right_toggle_Hz = overall_toggle_Hz/nright; 57 | center_toggle_Hz = overall_toggle_Hz/ncenter; 58 | 59 | %set the movie diration 60 | if (0) 61 | %I did this branch for my first successful 2-speed EEG Hacker post 62 | desired_duration_sec = 20; 63 | n_swap = 4; % how many times to swap the left and right sides 64 | else 65 | %I did this branch to produce actual useful movies for my BCI 66 | desired_duration_sec = 30; 67 | n_swap = 1; % don't switch sides 68 | end 69 | nframes = round(desired_duration_sec*overall_toggle_Hz); 70 | 71 | %create the movie 72 | n_frames = round(overall_toggle_Hz * desired_duration_sec) 73 | M=[]; 74 | left_state=0;right_state=0;center_state = 0; 75 | for Iswap=1:n_swap 76 | for I = 1:n_frames 77 | %change states (ie, change which side the movie is on) 78 | if (rem(I-1,nleft)==0); 79 | left_state = ~left_state; 80 | end 81 | if(rem(I-1,nright)==0); 82 | right_state = ~right_state; 83 | end 84 | if (rem(I-1,ncenter)==0); 85 | center_state = ~center_state; 86 | end 87 | 88 | %choose which is the left and which is the right image 89 | XL = Xblack; XR = Xblack;XC = Xblack; 90 | if (left_state), XL = Xwhite;end 91 | if (right_state), XR = Xwhite; end; 92 | if (center_state), XC = Xwhite; end; 93 | 94 | %build the composite left+right image 95 | if (rem(Iswap,2)==1) 96 | X = [XL XC XR]; 97 | else 98 | X = [XR XC XL]; 99 | end 100 | 101 | %save to movie 102 | if isempty(M) 103 | M = im2frame(X,map); 104 | else 105 | M(end+1) = im2frame(X,map); 106 | end 107 | 108 | end 109 | end 110 | 111 | % watch movie 112 | %figure;setFigureTallWide;set(gcf,'DoubleBuffer','on');movie(M,1,desired_rate_Hz*2); 113 | 114 | % save movie as AVI 115 | outpname=['ThreeSpeedMovie\']; 116 | try;mkdir(outpname);catch;end; 117 | outfname = [outpname 'Block' num2str(nblock) ... 118 | '_' num2str(left_toggle_Hz,3) 'HzToggle' ... 119 | '_' num2str(center_toggle_Hz,3) 'HzToggle' ... 120 | '_' num2str(right_toggle_Hz,3) 'HzToggle']; 121 | 122 | outfname = [outfname '.avi']; 123 | disp(['Writing to ' outfname]); 124 | try;eval(['!del "' outfname '"']);catch;end; %for WINDOWS! 125 | movie2avi(M,outfname,'Compression','none','FPS',overall_toggle_Hz); 126 | 127 | 128 | -------------------------------------------------------------------------------- /Data/2014-05-31 RobotControl/readme.txt: -------------------------------------------------------------------------------- 1 | 2014-05-31 2 | 3 | I controlled a Hex Bug with my brain waves. 4 | 5 | I used an OpenBCI V1 board with my Processing GUI (blinkyLights variant). I attached the ref (SRB1) to my left ear lobe, chan 2 to the left-back of my head (O1), and the bias electrode to my right ear lobe. Electrode impedance for chan 2 was about 50 kOhm. 6 | 7 | For stimuli, I did eyes-closed Alpha (move robot forward) and I played a blinking movie (15Hz toggle on left, 10 Hz toggle on right). 8 | 9 | 10 | 11 | 12 | 13 | -------------------------------------------------------------------------------- /Data/2014-07-17 ECG Using Bluetooth and Android/SavedData/RawDataFromAndroid.zip: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/chipaudette/EEGHacker/f72cc121d51fb5ea2f9176ebc0bb821aef05e64e/Data/2014-07-17 ECG Using Bluetooth and Android/SavedData/RawDataFromAndroid.zip -------------------------------------------------------------------------------- /Data/2014-07-17 ECG Using Bluetooth and Android/ScreenShots/Screenshot_2014-07-17-11-20-52.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/chipaudette/EEGHacker/f72cc121d51fb5ea2f9176ebc0bb821aef05e64e/Data/2014-07-17 ECG Using Bluetooth and Android/ScreenShots/Screenshot_2014-07-17-11-20-52.png -------------------------------------------------------------------------------- /Data/2014-07-17 ECG Using Bluetooth and Android/ScreenShots/Screenshot_2014-07-17-11-22-20.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/chipaudette/EEGHacker/f72cc121d51fb5ea2f9176ebc0bb821aef05e64e/Data/2014-07-17 ECG Using Bluetooth and Android/ScreenShots/Screenshot_2014-07-17-11-22-20.png -------------------------------------------------------------------------------- /Data/2014-07-17 ECG Using Bluetooth and Android/ScreenShots/Screenshot_2014-07-17-11-22-35.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/chipaudette/EEGHacker/f72cc121d51fb5ea2f9176ebc0bb821aef05e64e/Data/2014-07-17 ECG Using Bluetooth and Android/ScreenShots/Screenshot_2014-07-17-11-22-35.png -------------------------------------------------------------------------------- /Data/2014-07-17 ECG Using Bluetooth and Android/Test Setup.pptx: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/chipaudette/EEGHacker/f72cc121d51fb5ea2f9176ebc0bb821aef05e64e/Data/2014-07-17 ECG Using Bluetooth and Android/Test Setup.pptx -------------------------------------------------------------------------------- /Data/2014-08-17 First V3 Data/Data/05-testSig_1x_Fast.bin: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/chipaudette/EEGHacker/f72cc121d51fb5ea2f9176ebc0bb821aef05e64e/Data/2014-08-17 First V3 Data/Data/05-testSig_1x_Fast.bin -------------------------------------------------------------------------------- /Data/2014-08-17 First V3 Data/Data/06-normalInput.bin: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/chipaudette/EEGHacker/f72cc121d51fb5ea2f9176ebc0bb821aef05e64e/Data/2014-08-17 First V3 Data/Data/06-normalInput.bin -------------------------------------------------------------------------------- /Data/2014-08-17 First V3 Data/Data/07-capture_bot_bot.bin: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/chipaudette/EEGHacker/f72cc121d51fb5ea2f9176ebc0bb821aef05e64e/Data/2014-08-17 First V3 Data/Data/07-capture_bot_bot.bin -------------------------------------------------------------------------------- /Data/2014-08-17 First V3 Data/Data/08-capture_top_top.bin: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/chipaudette/EEGHacker/f72cc121d51fb5ea2f9176ebc0bb821aef05e64e/Data/2014-08-17 First V3 Data/Data/08-capture_top_top.bin -------------------------------------------------------------------------------- /Data/2014-08-17 First V3 Data/Data/09-capture_bot_top.bin: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/chipaudette/EEGHacker/f72cc121d51fb5ea2f9176ebc0bb821aef05e64e/Data/2014-08-17 First V3 Data/Data/09-capture_bot_top.bin -------------------------------------------------------------------------------- /Data/2014-08-17 First V3 Data/Data/10-capture_top_bot.bin: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/chipaudette/EEGHacker/f72cc121d51fb5ea2f9176ebc0bb821aef05e64e/Data/2014-08-17 First V3 Data/Data/10-capture_top_bot.bin -------------------------------------------------------------------------------- /Data/2014-08-17 First V3 Data/Data/20-capture_8chanTestSig_died.bin: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/chipaudette/EEGHacker/f72cc121d51fb5ea2f9176ebc0bb821aef05e64e/Data/2014-08-17 First V3 Data/Data/20-capture_8chanTestSig_died.bin -------------------------------------------------------------------------------- /Data/2014-08-17 First V3 Data/Data/21-capture_8chanTestSig_died.bin: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/chipaudette/EEGHacker/f72cc121d51fb5ea2f9176ebc0bb821aef05e64e/Data/2014-08-17 First V3 Data/Data/21-capture_8chanTestSig_died.bin -------------------------------------------------------------------------------- /Data/2014-08-17 First V3 Data/Data/22-capture_8chanTestSig_died.bin: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/chipaudette/EEGHacker/f72cc121d51fb5ea2f9176ebc0bb821aef05e64e/Data/2014-08-17 First V3 Data/Data/22-capture_8chanTestSig_died.bin -------------------------------------------------------------------------------- /Data/2014-08-17 First V3 Data/Pics/ECG on OpenBCI V3.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/chipaudette/EEGHacker/f72cc121d51fb5ea2f9176ebc0bb821aef05e64e/Data/2014-08-17 First V3 Data/Pics/ECG on OpenBCI V3.png -------------------------------------------------------------------------------- /Data/2014-08-17 First V3 Data/Pics/Figures.pptx: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/chipaudette/EEGHacker/f72cc121d51fb5ea2f9176ebc0bb821aef05e64e/Data/2014-08-17 First V3 Data/Pics/Figures.pptx -------------------------------------------------------------------------------- /Data/2014-08-17 First V3 Data/Pics/IMG_3039.JPG: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/chipaudette/EEGHacker/f72cc121d51fb5ea2f9176ebc0bb821aef05e64e/Data/2014-08-17 First V3 Data/Pics/IMG_3039.JPG -------------------------------------------------------------------------------- /Data/2014-08-17 First V3 Data/Pics/IMG_3046.JPG: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/chipaudette/EEGHacker/f72cc121d51fb5ea2f9176ebc0bb821aef05e64e/Data/2014-08-17 First V3 Data/Pics/IMG_3046.JPG -------------------------------------------------------------------------------- /Data/2014-08-17 First V3 Data/Pics/TestSig.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/chipaudette/EEGHacker/f72cc121d51fb5ea2f9176ebc0bb821aef05e64e/Data/2014-08-17 First V3 Data/Pics/TestSig.png -------------------------------------------------------------------------------- /Data/2014-08-17 First V3 Data/SavedData/OpenBCI-2014-08-18_15-57-32_8chanTestSig.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/chipaudette/EEGHacker/f72cc121d51fb5ea2f9176ebc0bb821aef05e64e/Data/2014-08-17 First V3 Data/SavedData/OpenBCI-2014-08-18_15-57-32_8chanTestSig.jpg -------------------------------------------------------------------------------- /Data/2014-10-03 V3 Alpha/Figures/.picasa.ini: -------------------------------------------------------------------------------- 1 | [Picasa] 2 | P2category=Exported Pictures 3 | date=41918.299074 4 | -------------------------------------------------------------------------------- /Data/2014-10-03 V3 Alpha/Figures/2014-10-05_Alpha_NoCaffeine.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/chipaudette/EEGHacker/f72cc121d51fb5ea2f9176ebc0bb821aef05e64e/Data/2014-10-03 V3 Alpha/Figures/2014-10-05_Alpha_NoCaffeine.png -------------------------------------------------------------------------------- /Data/2014-10-03 V3 Alpha/Figures/IMG_3195.JPG: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/chipaudette/EEGHacker/f72cc121d51fb5ea2f9176ebc0bb821aef05e64e/Data/2014-10-03 V3 Alpha/Figures/IMG_3195.JPG -------------------------------------------------------------------------------- /Data/2014-10-03 V3 Alpha/SavedData/Unzip This Data.zip: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/chipaudette/EEGHacker/f72cc121d51fb5ea2f9176ebc0bb821aef05e64e/Data/2014-10-03 V3 Alpha/SavedData/Unzip This Data.zip -------------------------------------------------------------------------------- /Data/2014-10-03 V3 Alpha/ScreenShots/OpenBCI-2014-10-04_18-54-52_impedanceCheck.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/chipaudette/EEGHacker/f72cc121d51fb5ea2f9176ebc0bb821aef05e64e/Data/2014-10-03 V3 Alpha/ScreenShots/OpenBCI-2014-10-04_18-54-52_impedanceCheck.jpg -------------------------------------------------------------------------------- /Data/2014-10-03 V3 Alpha/ScreenShots/OpenBCI-2014-10-04_18-57-38_alpha.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/chipaudette/EEGHacker/f72cc121d51fb5ea2f9176ebc0bb821aef05e64e/Data/2014-10-03 V3 Alpha/ScreenShots/OpenBCI-2014-10-04_18-57-38_alpha.jpg -------------------------------------------------------------------------------- /Data/2014-10-03 V3 Alpha/ScreenShots/OpenBCI-2014-10-04_18-59-54_biasFromTopRow.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/chipaudette/EEGHacker/f72cc121d51fb5ea2f9176ebc0bb821aef05e64e/Data/2014-10-03 V3 Alpha/ScreenShots/OpenBCI-2014-10-04_18-59-54_biasFromTopRow.jpg -------------------------------------------------------------------------------- /Data/2014-10-03 V3 Alpha/ScreenShots/OpenBCI-2014-10-04_19-00-16_biasFromBottomRow.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/chipaudette/EEGHacker/f72cc121d51fb5ea2f9176ebc0bb821aef05e64e/Data/2014-10-03 V3 Alpha/ScreenShots/OpenBCI-2014-10-04_19-00-16_biasFromBottomRow.jpg -------------------------------------------------------------------------------- /Data/2014-10-03 V3 Alpha/ScreenShots/OpenBCI-2014-10-04_19-01-59_noBias.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/chipaudette/EEGHacker/f72cc121d51fb5ea2f9176ebc0bb821aef05e64e/Data/2014-10-03 V3 Alpha/ScreenShots/OpenBCI-2014-10-04_19-01-59_noBias.jpg -------------------------------------------------------------------------------- /Data/2014-10-03 V3 Alpha/ScreenShots/OpenBCI-2014-10-04_19-07-07_eyesOpen.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/chipaudette/EEGHacker/f72cc121d51fb5ea2f9176ebc0bb821aef05e64e/Data/2014-10-03 V3 Alpha/ScreenShots/OpenBCI-2014-10-04_19-07-07_eyesOpen.jpg -------------------------------------------------------------------------------- /Data/2014-10-03 V3 Alpha/ScreenShots/OpenBCI-2014-10-04_19-07-34_eyesShut.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/chipaudette/EEGHacker/f72cc121d51fb5ea2f9176ebc0bb821aef05e64e/Data/2014-10-03 V3 Alpha/ScreenShots/OpenBCI-2014-10-04_19-07-34_eyesShut.jpg -------------------------------------------------------------------------------- /Data/2014-10-03 V3 Alpha/ScreenShots/OpenBCI-2014-10-05_17-16-44_alpha_noCaffeine.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/chipaudette/EEGHacker/f72cc121d51fb5ea2f9176ebc0bb821aef05e64e/Data/2014-10-03 V3 Alpha/ScreenShots/OpenBCI-2014-10-05_17-16-44_alpha_noCaffeine.jpg -------------------------------------------------------------------------------- /Data/2014-11-23 Accelerometer/Pics/BoardWithBatteries.JPG: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/chipaudette/EEGHacker/f72cc121d51fb5ea2f9176ebc0bb821aef05e64e/Data/2014-11-23 Accelerometer/Pics/BoardWithBatteries.JPG -------------------------------------------------------------------------------- /Data/2014-11-23 Accelerometer/Pics/BoardZoom.JPG: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/chipaudette/EEGHacker/f72cc121d51fb5ea2f9176ebc0bb821aef05e64e/Data/2014-11-23 Accelerometer/Pics/BoardZoom.JPG -------------------------------------------------------------------------------- /Data/2014-11-23 Accelerometer/Pics/Figures.pptx: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/chipaudette/EEGHacker/f72cc121d51fb5ea2f9176ebc0bb821aef05e64e/Data/2014-11-23 Accelerometer/Pics/Figures.pptx -------------------------------------------------------------------------------- /Data/2014-11-23 Accelerometer/SavedData/OpenBCI-RAW-2014-11-23_18-54-57.zip: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/chipaudette/EEGHacker/f72cc121d51fb5ea2f9176ebc0bb821aef05e64e/Data/2014-11-23 Accelerometer/SavedData/OpenBCI-RAW-2014-11-23_18-54-57.zip -------------------------------------------------------------------------------- /Data/2014-11-23 Accelerometer/exploreAccelData.py: -------------------------------------------------------------------------------- 1 | # ###################### 2 | # 3 | # exploreAccelData.py 4 | # 5 | # load and Plot data from OpenBCI text file 6 | # 7 | # Written for the Anaconda distribution of Python 8 | # Run inside the Spyder IDE (Pyton 2.7) 9 | # 10 | # Chip Audette, 2014 11 | # Distribute under the MIT License 12 | # http://opensource.org/licenses/MIT 13 | # 14 | # ######################## 15 | 16 | import matplotlib.pyplot as plt 17 | import matplotlib.mlab as mlab 18 | import numpy as np 19 | from scipy import signal 20 | 21 | # some program constants 22 | 23 | # define which data to load 24 | case = 1 # choose which case to load 25 | pname = 'SavedData/' 26 | if (case == 1): 27 | fname = 'OpenBCI-RAW-2014-11-23_18-54-57.txt' 28 | 29 | 30 | # load data into numpy array 31 | fs_Hz = 250.0 # assumed sample rate for the EEG data 32 | data = np.loadtxt(pname + fname, 33 | delimiter=',', 34 | skiprows=5) 35 | 36 | # parse the data 37 | data_indices = data[:, 0] # the first column is the packet index 38 | eeg_data_uV = data[:, 1:(8+1)] # ignore the first channel (column 0), so channel 1 is column 1 39 | accel_data_G = data[:, 9:(11+1)]/1000.0/9.806 #acceleromater data...convert mm/s2 to G 40 | mag_accel_G = np.sqrt(accel_data_G[:,0]**2 + accel_data_G[:,1]**2 + accel_data_G[:,2]**2) 41 | 42 | # check data indices 43 | d_indices = data_indices[2:]-data_indices[1:-1] 44 | n_jump = np.count_nonzero((d_indices != 1) & (d_indices != -255)) 45 | print("Number of Discontinuities in the packet counter: " + str(n_jump)) 46 | 47 | 48 | ## # 49 | fig = plt.figure(figsize=(10.0, 9.5)) # make new figure, set size in inches 50 | n_row = 3+1 51 | 52 | t_sec = np.arange(len(accel_data_G[:, 0])) / fs_Hz 53 | for Iplot in range(3): 54 | if (Iplot)==0: 55 | ax1 = plt.subplot(n_row,1,Iplot+1) 56 | ax = ax1 57 | else: 58 | ax = plt.subplot(n_row,1,Iplot+1, sharex=ax1) 59 | 60 | plt.plot(t_sec,accel_data_G[:, Iplot]) 61 | plt.xlabel("Time (sec)") 62 | plt.ylabel("Acceleration (G)") 63 | plt.title("Channel " + str(Iplot)) 64 | 65 | ax = plt.subplot(n_row,1,4, sharex=ax1) 66 | plt.plot(t_sec,mag_accel_G) 67 | plt.xlabel("Time (sec)") 68 | plt.ylabel("Acceleration (G)") 69 | plt.title("Magnitude") 70 | plt.ylim([0, 1.2]) 71 | 72 | 73 | plt.tight_layout() 74 | 75 | -------------------------------------------------------------------------------- /Data/2014-11-23 Accelerometer/readme.txt: -------------------------------------------------------------------------------- 1 | 2 | 2014-11-23 3 | 4 | Accelerometer Testing 5 | 6 | 1) Started Flat and Level (Z is up) 7 | 2) Tipped so X is down, then back to level, then X is up, then back to level 8 | 3) Tipped so Y is down, then back to level, then Y is up, then back to level 9 | 4) Flipped over so Z is down, then back to Z is up 10 | 11 | -------------------------------------------------------------------------------- /Data/2015-01-24 Auditory Steady State/2015-01-24 ASSR Figures.pptx: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/chipaudette/EEGHacker/f72cc121d51fb5ea2f9176ebc0bb821aef05e64e/Data/2015-01-24 Auditory Steady State/2015-01-24 ASSR Figures.pptx -------------------------------------------------------------------------------- /Data/2015-01-24 Auditory Steady State/SavedData.zip: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/chipaudette/EEGHacker/f72cc121d51fb5ea2f9176ebc0bb821aef05e64e/Data/2015-01-24 Auditory Steady State/SavedData.zip -------------------------------------------------------------------------------- /Data/2015-01-24 Auditory Steady State/SavedData/OpenBCI-2015-01-24_12-19-36.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/chipaudette/EEGHacker/f72cc121d51fb5ea2f9176ebc0bb821aef05e64e/Data/2015-01-24 Auditory Steady State/SavedData/OpenBCI-2015-01-24_12-19-36.jpg -------------------------------------------------------------------------------- /Data/2015-01-24 Auditory Steady State/SavedData/OpenBCI-2015-01-24_12-19-47.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/chipaudette/EEGHacker/f72cc121d51fb5ea2f9176ebc0bb821aef05e64e/Data/2015-01-24 Auditory Steady State/SavedData/OpenBCI-2015-01-24_12-19-47.jpg -------------------------------------------------------------------------------- /Data/2015-01-24 Auditory Steady State/SavedData/OpenBCI-2015-01-25_18-30-11.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/chipaudette/EEGHacker/f72cc121d51fb5ea2f9176ebc0bb821aef05e64e/Data/2015-01-24 Auditory Steady State/SavedData/OpenBCI-2015-01-25_18-30-11.jpg -------------------------------------------------------------------------------- /Data/2015-01-24 Auditory Steady State/SavedData/OpenBCI-2015-01-25_18-31-17.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/chipaudette/EEGHacker/f72cc121d51fb5ea2f9176ebc0bb821aef05e64e/Data/2015-01-24 Auditory Steady State/SavedData/OpenBCI-2015-01-25_18-31-17.jpg -------------------------------------------------------------------------------- /Data/2015-01-24 Auditory Steady State/SavedData/OpenBCI-2015-01-25_19-17-30.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/chipaudette/EEGHacker/f72cc121d51fb5ea2f9176ebc0bb821aef05e64e/Data/2015-01-24 Auditory Steady State/SavedData/OpenBCI-2015-01-25_19-17-30.jpg -------------------------------------------------------------------------------- /Data/2015-01-24 Auditory Steady State/SavedData/OpenBCI-2015-01-25_19-17-53.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/chipaudette/EEGHacker/f72cc121d51fb5ea2f9176ebc0bb821aef05e64e/Data/2015-01-24 Auditory Steady State/SavedData/OpenBCI-2015-01-25_19-17-53.jpg -------------------------------------------------------------------------------- /Data/2015-01-24 Auditory Steady State/SavedData_Day2.zip: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/chipaudette/EEGHacker/f72cc121d51fb5ea2f9176ebc0bb821aef05e64e/Data/2015-01-24 Auditory Steady State/SavedData_Day2.zip -------------------------------------------------------------------------------- /Data/2015-01-24 Auditory Steady State/TestTones/1000Hz_37HzSine.mp3: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/chipaudette/EEGHacker/f72cc121d51fb5ea2f9176ebc0bb821aef05e64e/Data/2015-01-24 Auditory Steady State/TestTones/1000Hz_37HzSine.mp3 -------------------------------------------------------------------------------- /Data/2015-01-24 Auditory Steady State/TestTones/1000Hz_38Hz.mp3: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/chipaudette/EEGHacker/f72cc121d51fb5ea2f9176ebc0bb821aef05e64e/Data/2015-01-24 Auditory Steady State/TestTones/1000Hz_38Hz.mp3 -------------------------------------------------------------------------------- /Data/2015-01-24 Auditory Steady State/TestTones/1000Hz_40Hz.mp3: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/chipaudette/EEGHacker/f72cc121d51fb5ea2f9176ebc0bb821aef05e64e/Data/2015-01-24 Auditory Steady State/TestTones/1000Hz_40Hz.mp3 -------------------------------------------------------------------------------- /Data/2015-01-24 Auditory Steady State/TestTones/1000Hz_40HzSine.mp3: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/chipaudette/EEGHacker/f72cc121d51fb5ea2f9176ebc0bb821aef05e64e/Data/2015-01-24 Auditory Steady State/TestTones/1000Hz_40HzSine.mp3 -------------------------------------------------------------------------------- /Data/2015-01-24 Auditory Steady State/TestTones/1000Hz_42Hz.mp3: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/chipaudette/EEGHacker/f72cc121d51fb5ea2f9176ebc0bb821aef05e64e/Data/2015-01-24 Auditory Steady State/TestTones/1000Hz_42Hz.mp3 -------------------------------------------------------------------------------- /Data/2015-01-24 Auditory Steady State/TestTones/1000Hz_43HzSine.mp3: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/chipaudette/EEGHacker/f72cc121d51fb5ea2f9176ebc0bb821aef05e64e/Data/2015-01-24 Auditory Steady State/TestTones/1000Hz_43HzSine.mp3 -------------------------------------------------------------------------------- /Data/2015-01-24 Auditory Steady State/TestTones/2500Hz_38Hz.mp3: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/chipaudette/EEGHacker/f72cc121d51fb5ea2f9176ebc0bb821aef05e64e/Data/2015-01-24 Auditory Steady State/TestTones/2500Hz_38Hz.mp3 -------------------------------------------------------------------------------- /Data/2015-01-24 Auditory Steady State/TestTones/2500Hz_40Hz.mp3: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/chipaudette/EEGHacker/f72cc121d51fb5ea2f9176ebc0bb821aef05e64e/Data/2015-01-24 Auditory Steady State/TestTones/2500Hz_40Hz.mp3 -------------------------------------------------------------------------------- /Data/2015-01-24 Auditory Steady State/TestTones/2500Hz_42Hz.mp3: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/chipaudette/EEGHacker/f72cc121d51fb5ea2f9176ebc0bb821aef05e64e/Data/2015-01-24 Auditory Steady State/TestTones/2500Hz_42Hz.mp3 -------------------------------------------------------------------------------- /Data/2015-01-24 Auditory Steady State/TestTones/2500_37HzSine.mp3: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/chipaudette/EEGHacker/f72cc121d51fb5ea2f9176ebc0bb821aef05e64e/Data/2015-01-24 Auditory Steady State/TestTones/2500_37HzSine.mp3 -------------------------------------------------------------------------------- /Data/2015-01-24 Auditory Steady State/TestTones/2500_40HzSine.mp3: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/chipaudette/EEGHacker/f72cc121d51fb5ea2f9176ebc0bb821aef05e64e/Data/2015-01-24 Auditory Steady State/TestTones/2500_40HzSine.mp3 -------------------------------------------------------------------------------- /Data/2015-01-24 Auditory Steady State/TestTones/2500_43HzSine.mp3: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/chipaudette/EEGHacker/f72cc121d51fb5ea2f9176ebc0bb821aef05e64e/Data/2015-01-24 Auditory Steady State/TestTones/2500_43HzSine.mp3 -------------------------------------------------------------------------------- /Data/2015-01-24 Auditory Steady State/TestTones/L-1000-37Hz_R-2500-43Hz.mp3: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/chipaudette/EEGHacker/f72cc121d51fb5ea2f9176ebc0bb821aef05e64e/Data/2015-01-24 Auditory Steady State/TestTones/L-1000-37Hz_R-2500-43Hz.mp3 -------------------------------------------------------------------------------- /Data/2015-01-24 Auditory Steady State/readme.txt: -------------------------------------------------------------------------------- 1 | 2 | ** Auditory Steady State Response ** 3 | 4 | 2015-01-24 and 2015-01-25 5 | EEG Hacker 6 | 7 | 8 | * 2015-01-24 * 9 | 10 | Chan 1: Cz 11 | EEG Ref: Left Ear Lobe 12 | EEG Bias: Right Ear Lobe 13 | 14 | Stimulation: Same signal to both ears. All sounds are for 20 sec. First, 1000Hz at 38, 40, 42Hz beating. Then, 2500Hz at 38, 40, 42 Hz beating. 15 | 16 | 17 | * 2015-01-25 * 18 | 19 | Chan 1: Fpz (Forehead, Midline) 20 | Chan 2: Fz (Front-ish, Midline) 21 | Chan 3: T7 (Above Left Ear) 22 | Chan 4: T8 (Above Right Ear) 23 | Chan 5: C3 (Left, Half-Way Up to Cz) 24 | Chan 6: C4 (Right, half-Way Up to Cz) 25 | Chan 7: Cz (top of head, Midline) 26 | Chan 8: Oz (back of head, Midline) 27 | EEG Ref: Right Ear Lobe 28 | EEG Bias: Left Ear Lobe 29 | 30 | Stimulation: Three tests: A and B and C 31 | 32 | Test A: Same signal to both ears, except at end as noted below 33 | * Start eyes closed 34 | * 20 sec: 1000 Hz at 37, 40, 43Hz beating 35 | * 10 sec: silence (eyes closed) 36 | * 20 sec: 2500 Hz at 37, 40, 43 Hz beating 37 | * 10 sec: silence (eyes closed) 38 | * 20 sec: Finish with 1000/37 in left and 22500/43 in right. 39 | * End eyes closed 40 | 41 | Test B: Stereo: 42 | * 20 sec: 1000/37 in left and 22500/43 in right. (Attention to Left) 43 | * 10 sec: silence 44 | * 20 sec: 1000/37 in left and 22500/43 in right. (Attention to Right) -------------------------------------------------------------------------------- /Data/2015-01-30 Test on Human at Dartmouth/elec_locations.csv: -------------------------------------------------------------------------------- 1 | Fp1,-0.309016994,0.951056516 2 | Fpz,0,1 3 | Fp2,0.309016994,0.951056516 4 | F7,-0.809016994,0.587785252 5 | F3,-0.4,0.52 6 | Fz,0,0.5 7 | F4,0.4,0.52 8 | F8,0.809016994,0.587785252 9 | FC5,-0.677254249,0.276946313 10 | FC1,-0.225,0.255 11 | FC2,0.225,0.255 12 | FC6,0.677254249,0.276946313 13 | M1,-1.07,-0.25 14 | T7,-1,0 15 | C3,-0.5,0 16 | Cz,0,0 17 | C4,0.5,0 18 | T8,1,0 19 | M2,1.07,-0.25 20 | CP5,-0.677254249,-0.276946313 21 | CP1,-0.225,-0.255 22 | CP2,0.225,-0.255 23 | CP6,0.677254249,-0.276946313 24 | P7,-0.809016994,-0.587785252 25 | P3,-0.4,-0.52 26 | Pz,0,-0.5 27 | P4,0.4,-0.52 28 | P8,0.809016994,-0.587785252 29 | Poz,0,-0.75 30 | O1,-0.309016994,-0.951056516 31 | Oz,0,-1 32 | O2,0.309016994,-0.951056516 33 | -------------------------------------------------------------------------------- /Data/2015-01-30 Test on Human at Dartmouth/elec_locations.xls: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/chipaudette/EEGHacker/f72cc121d51fb5ea2f9176ebc0bb821aef05e64e/Data/2015-01-30 Test on Human at Dartmouth/elec_locations.xls -------------------------------------------------------------------------------- /Data/2015-01-30 Test on Human at Dartmouth/elec_positions.txt: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/chipaudette/EEGHacker/f72cc121d51fb5ea2f9176ebc0bb821aef05e64e/Data/2015-01-30 Test on Human at Dartmouth/elec_positions.txt -------------------------------------------------------------------------------- /Matlab/makeBlinkingMovie/makeBlinkingMovie_1speed.m: -------------------------------------------------------------------------------- 1 | % Created: Chip Audette, http://eeghacker.blogspot.com 2 | % Date: May 2014 3 | % Purpose: Create blinking movies at different rates 4 | % Platform: Matlab 7.1 on Windows XP 5 | % License: The MIT License (MIT) 6 | 7 | % Choose aspect ratio for the movie 8 | width_vs_height = 16/9; 9 | 10 | %make color map for the movie 11 | map = ones(256,3); %create color map, all white 12 | map(1,:) = 1; %modify color map by making first entry as black 13 | 14 | % make the black and white frames 15 | hblock = 64; 16 | wblock = round(64*width_vs_height); 17 | nblock=1; 18 | npix_w=wblock*nblock; 19 | npix_h=hblock*nblock; 20 | X1 = uint8(ones(npix_h,npix_w)); 21 | X2 = uint8(zeros(npix_h,npix_w)); 22 | 23 | 24 | % view the two frames 25 | figure; 26 | try;setFigureWide;catch;end 27 | subplot(1,2,1); 28 | try;imshow(X1,map);catch;image(X1);colormap(map);end 29 | title('Frame 1'); 30 | axis equal;axis tight; 31 | subplot(1,2,2); 32 | try;imshow(X2,map);catch;image(X2);end 33 | title('Frame 2'); 34 | axis equal;axis tight; 35 | 36 | % loop to make individual movies at the desired blink rates 37 | desired_rates_Hz = [1:20]; %this sets the white-to-white blink rate 38 | for Irate = 1:length(desired_rates_Hz) 39 | desired_rate_Hz = desired_rates_Hz(Irate); 40 | 41 | %fabricate series of movies 42 | desired_rate_Hz = desired_rates_Hz(Irate); %for complete cycle of X1 and X2 together 43 | desired_duration_sec = 15; 44 | n_frames = round(desired_rate_Hz * desired_duration_sec) 45 | clear M 46 | for I = 1:n_frames 47 | M((I-1)*2+1)=im2frame(X1,map); 48 | M((I-1)*2+2)=im2frame(X2,map); 49 | end 50 | 51 | % watch movie 52 | %figure;setFigureTallWide;set(gcf,'DoubleBuffer','on');movie(M,1,desired_rate_Hz*2); 53 | 54 | % save movie 55 | outpname=['Movies_' num2str(nblock) 'block\']; 56 | try;mkdir(outpname);catch;end; 57 | outfname = [outpname 'checkerboard' num2str(nblock) '_rate' num2str(desired_rate_Hz) 'HzX2']; 58 | if (1) 59 | %write as AVI 60 | outfname = [outfname '.avi']; 61 | disp(['Writing to ' outfname]); 62 | movie2avi(M,outfname,'Compression','none','FPS',desired_rate_Hz*2); 63 | else 64 | %write as WMV...doesn't seem to work anymore. So, I'll use the AVI and 65 | %then use windows movie maker to convert to WMV 66 | clear video2 67 | video2.width=size(M(1).cdata,2); 68 | video2.height=size(M(1).cdata,1); 69 | video2.frames=M; 70 | video2.rate=desired_rate_Hz*2; 71 | video2.times=[0:1:length(M)-1] /video2.rate; 72 | 73 | outfname = [outfname '.wmv']; 74 | disp(['Writing to ' outfname]); 75 | mmwrite(outfname,video2); 76 | end 77 | end 78 | -------------------------------------------------------------------------------- /Matlab/makeBlinkingMovie/makeBlinkingMovie_2speeds.m: -------------------------------------------------------------------------------- 1 | % Created: Chip Audette, http://eeghacker.blogspot.com 2 | % Date: May 2014 3 | % Purpose: Create movies with two simultaneous blink rates, 4 | % one blink rate on the left and another blink rate on 5 | % the right. 6 | % Platform: Matlab 7.1 on Windows XP 7 | % License: The MIT License (MIT) 8 | 9 | %make black and white frames 10 | if (1) 11 | map = ones(256,3); %all white 12 | map(1,:) = 0; %black 13 | 14 | % make the two frames...all black and all white 15 | width_vs_height = 16/9; 16 | hblock = 64; 17 | wblock = round(hblock*width_vs_height/2); 18 | nblock=1; 19 | npix_w=wblock*nblock; 20 | npix_h=hblock*nblock; 21 | Xwhite = ones(npix_h,npix_w); 22 | Xblack = ~Xwhite; 23 | 24 | %put a dot in the middle of the white one 25 | np=1; 26 | xcenter = round(wblock/2)-1; 27 | hcenter = round(hblock/2)-1; 28 | Xwhite(hcenter-2,xcenter)=0; 29 | Xwhite(hcenter,xcenter+[-2 2])=0; 30 | Xwhite(hcenter+2,xcenter)=0; 31 | 32 | %convert to "byte" 33 | Xwhite = uint8(Xwhite); 34 | Xblack = uint8(Xblack); 35 | end 36 | 37 | %choose the blinking rate 38 | switch 3 39 | case 1 40 | overall_toggle_Hz = 60; 41 | nleft = 3; 42 | nright = 4; 43 | case 2 44 | overall_toggle_Hz = 30; 45 | nleft = 2; 46 | nright = 3; 47 | case 3 48 | overall_toggle_Hz = 20; 49 | nleft = 2; 50 | nright = 3; 51 | end 52 | left_toggle_Hz = overall_toggle_Hz/nleft; 53 | right_toggle_Hz = overall_toggle_Hz/nright; 54 | 55 | %set the movie diration 56 | if (0) 57 | %I did this branch for my first successful 2-speed EEG Hacker post 58 | desired_duration_sec = 20; 59 | n_swap = 4; % how many times to swap the left and right sides 60 | else 61 | %I did this branch to produce actual useful movies for my BCI 62 | desired_duration_sec = 30; 63 | n_swap = 1; % don't switch sides 64 | end 65 | nframes = round(desired_duration_sec*overall_toggle_Hz); 66 | 67 | %create the movie 68 | n_frames = round(overall_toggle_Hz * desired_duration_sec) 69 | M=[]; 70 | left_state=0;right_state=0; 71 | for Iswap=1:n_swap 72 | for I = 1:n_frames 73 | %change states (ie, change which side the movie is on) 74 | if (rem(I-1,nleft)==0); 75 | left_state = ~left_state; 76 | end 77 | if(rem(I-1,nright)==0); 78 | right_state = ~right_state; 79 | end 80 | 81 | %choose which is the left and which is the right image 82 | XL = Xblack; XR = Xblack; 83 | if (left_state), XL = Xwhite;end 84 | if (right_state), XR = Xwhite; end; 85 | 86 | %build the composite left+right image 87 | if (rem(Iswap,2)==1) 88 | X = [XL XR]; 89 | else 90 | X = [XR XL]; 91 | end 92 | 93 | %save to movie 94 | if isempty(M) 95 | M = im2frame(X,map); 96 | else 97 | M(end+1) = im2frame(X,map); 98 | end 99 | 100 | end 101 | end 102 | 103 | % watch movie 104 | %figure;setFigureTallWide;set(gcf,'DoubleBuffer','on');movie(M,1,desired_rate_Hz*2); 105 | 106 | % save movie as AVI 107 | outpname=['TwoSpeedMovie\']; 108 | try;mkdir(outpname);catch;end; 109 | outfname = [outpname 'Block' num2str(nblock) ... 110 | '_' num2str(left_toggle_Hz,3) 'HzToggle' ... 111 | '_' num2str(right_toggle_Hz,3) 'HzToggle']; 112 | 113 | outfname = [outfname '.avi']; 114 | disp(['Writing to ' outfname]); 115 | try;eval(['!del "' outfname '"']);catch;end; %for WINDOWS! 116 | movie2avi(M,outfname,'Compression','none','FPS',overall_toggle_Hz); 117 | 118 | 119 | -------------------------------------------------------------------------------- /Matlab/makeBlinkingMovie/makeBlinkingMovie_3speeds.m: -------------------------------------------------------------------------------- 1 | % Created: Chip Audette, http://eeghacker.blogspot.com 2 | % Date: May 2014 3 | % Purpose: Create movies with two simultaneous blink rates, 4 | % one blink rate on the left and another blink rate on 5 | % the right. 6 | % Platform: Matlab 7.1 on Windows XP 7 | % License: The MIT License (MIT) 8 | 9 | %make black and white frames 10 | if (1) 11 | map = ones(256,3); %all white 12 | map(1,:) = 0; %black 13 | 14 | % make the two frames...all black and all white 15 | width_vs_height = 16/9; 16 | hblock = 64; 17 | wblock = round(hblock*width_vs_height/3); 18 | nblock=1; 19 | npix_w=wblock*nblock; 20 | npix_h=hblock*nblock; 21 | Xwhite = ones(npix_h,npix_w); 22 | Xblack = ~Xwhite; 23 | 24 | %put a dot in the middle of the white one 25 | np=1; 26 | xcenter = round(wblock/2)-1; 27 | hcenter = round(hblock/2)-1; 28 | Xwhite(hcenter-2,xcenter)=0; 29 | Xwhite(hcenter,xcenter+[-2 2])=0; 30 | Xwhite(hcenter+2,xcenter)=0; 31 | 32 | %convert to "byte" 33 | Xwhite = uint8(Xwhite); 34 | Xblack = uint8(Xblack); 35 | end 36 | 37 | %choose the blinking rate 38 | switch 2 39 | case 1 40 | overall_toggle_Hz = 60; 41 | nleft = 5; 42 | nright = 4; 43 | ncenter = 3; 44 | case 2 45 | overall_toggle_Hz = 30; 46 | nleft = 5; 47 | nright = 3; 48 | ncenter = 2; 49 | case 3 50 | overall_toggle_Hz = 20; 51 | nleft = 3; 52 | nright = 5; 53 | ncenter = 2; 54 | end 55 | left_toggle_Hz = overall_toggle_Hz/nleft; 56 | right_toggle_Hz = overall_toggle_Hz/nright; 57 | center_toggle_Hz = overall_toggle_Hz/ncenter; 58 | 59 | %set the movie diration 60 | if (0) 61 | %I did this branch for my first successful 2-speed EEG Hacker post 62 | desired_duration_sec = 20; 63 | n_swap = 4; % how many times to swap the left and right sides 64 | else 65 | %I did this branch to produce actual useful movies for my BCI 66 | desired_duration_sec = 30; 67 | n_swap = 1; % don't switch sides 68 | end 69 | nframes = round(desired_duration_sec*overall_toggle_Hz); 70 | 71 | %create the movie 72 | n_frames = round(overall_toggle_Hz * desired_duration_sec) 73 | M=[]; 74 | left_state=0;right_state=0;center_state = 0; 75 | for Iswap=1:n_swap 76 | for I = 1:n_frames 77 | %change states (ie, change which side the movie is on) 78 | if (rem(I-1,nleft)==0); 79 | left_state = ~left_state; 80 | end 81 | if(rem(I-1,nright)==0); 82 | right_state = ~right_state; 83 | end 84 | if (rem(I-1,ncenter)==0); 85 | center_state = ~center_state; 86 | end 87 | 88 | %choose which is the left and which is the right image 89 | XL = Xblack; XR = Xblack;XC = Xblack; 90 | if (left_state), XL = Xwhite;end 91 | if (right_state), XR = Xwhite; end; 92 | if (center_state), XC = Xwhite; end; 93 | 94 | %build the composite left+right image 95 | if (rem(Iswap,2)==1) 96 | X = [XL XC XR]; 97 | else 98 | X = [XR XC XL]; 99 | end 100 | 101 | %save to movie 102 | if isempty(M) 103 | M = im2frame(X,map); 104 | else 105 | M(end+1) = im2frame(X,map); 106 | end 107 | 108 | end 109 | end 110 | 111 | % watch movie 112 | %figure;setFigureTallWide;set(gcf,'DoubleBuffer','on');movie(M,1,desired_rate_Hz*2); 113 | 114 | % save movie as AVI 115 | outpname=['ThreeSpeedMovie\']; 116 | try;mkdir(outpname);catch;end; 117 | outfname = [outpname 'Block' num2str(nblock) ... 118 | '_' num2str(left_toggle_Hz,3) 'HzToggle' ... 119 | '_' num2str(center_toggle_Hz,3) 'HzToggle' ... 120 | '_' num2str(right_toggle_Hz,3) 'HzToggle']; 121 | 122 | outfname = [outfname '.avi']; 123 | disp(['Writing to ' outfname]); 124 | try;eval(['!del "' outfname '"']);catch;end; %for WINDOWS! 125 | movie2avi(M,outfname,'Compression','none','FPS',overall_toggle_Hz); 126 | 127 | 128 | -------------------------------------------------------------------------------- /Processing/OBCI_V3_Debugging/OBCI_Verify_PacketCount/data/Dialog-24.vlw: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/chipaudette/EEGHacker/f72cc121d51fb5ea2f9176ebc0bb821aef05e64e/Processing/OBCI_V3_Debugging/OBCI_Verify_PacketCount/data/Dialog-24.vlw -------------------------------------------------------------------------------- /Processing/OBCI_V3_Debugging/OBCI_Verify_PacketCount/folderStuff.pde: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | void folderSelected(File selection) { 6 | if (selection == null) { 7 | println("Window was closed or the user hit cancel."); 8 | } else { 9 | fileToVerify = selection.getAbsolutePath(); 10 | println("User selected " + fileToVerify); //selection.getAbsolutePath()); 11 | dataReader = createReader(fileToVerify); //selection.getAbsolutePath()); 12 | reading = true; 13 | dataWriter.println("%OBCI Packet Count Verification of file " + fileToVerify); 14 | println("OBCI Packet Count Verification of file " + fileToVerify); 15 | println("timing file verification"); 16 | thatTime = millis(); 17 | } 18 | } 19 | 20 | void createFile(){ 21 | logFileName = "OBCI_packetCount_verification/"+month()+"_"+day()+"_"+hour()+"_"+minute()+"_"+second()+".txt"; 22 | dataWriter = createWriter(logFileName); 23 | 24 | } 25 | 26 | 27 | -------------------------------------------------------------------------------- /Processing/OBCI_V3_Debugging/OBCI_Verify_PacketCount/mouseButtonSuff.pde: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | void drawButton(){ 5 | updateButton(); 6 | if (overButton) { 7 | fill(buttonHighlight); 8 | } else { 9 | fill(buttonColor); 10 | } 11 | stroke(strokeColor); 12 | rect(buttonX, buttonY, buttonWidth, buttonHeight); 13 | fill(0); 14 | text("select file to verify", width/2,height/2 + 10); 15 | } 16 | 17 | 18 | void updateButton() { 19 | if (buttonOver(buttonX, buttonY, buttonWidth, buttonHeight) ) { 20 | overButton = true; 21 | } else { 22 | overButton = false; 23 | } 24 | } 25 | 26 | boolean buttonOver(int x, int y, float w, float h) { 27 | if (mouseX >= x-w/2 && mouseX <= x+w/2 && 28 | mouseY >= y-h/2 && mouseY <= y+h/2) { 29 | return true; 30 | } else { 31 | return false; 32 | } 33 | } 34 | 35 | void mousePressed() { 36 | if (overButton) { 37 | println("mouse pressed"); 38 | createFile(); 39 | selectInput("Select a folder to process:", "folderSelected"); 40 | } 41 | } 42 | -------------------------------------------------------------------------------- /Processing/OBCI_V3_Debugging/OBCI_Verify_PacketCount/sketch.properties: -------------------------------------------------------------------------------- 1 | mode.id=processing.mode.java.JavaMode 2 | mode=Java 3 | -------------------------------------------------------------------------------- /Processing/OBCI_V3_Debugging/OpenBCI_GUI/AndroidManifest.xml: -------------------------------------------------------------------------------- 1 | 2 | 6 | 7 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | -------------------------------------------------------------------------------- /Processing/OBCI_V3_Debugging/OpenBCI_GUI/Button.pde: -------------------------------------------------------------------------------- 1 | 2 | //////////////////// 3 | // 4 | // This class creates and manages a button for use on the screen to trigger actions. 5 | // 6 | // Created: Chip Audette, Oct 2013. 7 | // 8 | // Based on Processing's "Button" example code 9 | // 10 | //////////////////// 11 | 12 | class Button { 13 | 14 | int but_x, but_y, but_dx, but_dy; // Position of square button 15 | //int rectSize = 90; // Diameter of rect 16 | color color_pressed = color(51); 17 | color color_highlight = color(102); 18 | color color_notPressed = color(255); 19 | color rectHighlight; 20 | //boolean isMouseHere = false; 21 | boolean isActive = false; 22 | public String but_txt; 23 | PFont font; 24 | 25 | public Button(int x, int y, int w, int h, String txt, int fontSize) { 26 | setup(x, y, w, h, txt); 27 | //println(PFont.list()); //see which fonts are available 28 | //font = createFont("SansSerif.plain",fontSize); 29 | //font = createFont("Lucida Sans Regular",fontSize); 30 | font = createFont("Arial",fontSize); 31 | //font = loadFont("SansSerif.plain.vlw"); 32 | } 33 | 34 | public void setup(int x, int y, int w, int h, String txt) { 35 | but_x = x; 36 | but_y = y; 37 | but_dx = w; 38 | but_dy = h; 39 | setString(txt); 40 | } 41 | 42 | public void setString(String txt) { 43 | but_txt = txt; 44 | //println("Button: setString: string = " + txt); 45 | } 46 | 47 | public boolean isActive() { 48 | return isActive; 49 | } 50 | 51 | public void setIsActive(boolean val) { 52 | isActive = val; 53 | } 54 | 55 | public boolean isMouseHere() { 56 | if ( overRect(but_x, but_y, but_dx, but_dy) ) { 57 | return true; 58 | } 59 | else { 60 | return false; 61 | } 62 | } 63 | 64 | color getColor() { 65 | if (isActive) { 66 | return color_pressed; 67 | } else { 68 | return color_notPressed; 69 | } 70 | } 71 | 72 | boolean overRect(int x, int y, int width, int height) { 73 | if (mouseX >= x && mouseX <= x+width && 74 | mouseY >= y && mouseY <= y+height) { 75 | return true; 76 | } 77 | else { 78 | return false; 79 | } 80 | } 81 | 82 | public void draw() { 83 | //draw the button 84 | fill(getColor()); 85 | // stroke(255); 86 | noStroke(); 87 | rect(but_x,but_y,but_dx,but_dy); 88 | 89 | //draw the text 90 | fill(0); 91 | stroke(255); 92 | textFont(font); 93 | textSize(12); 94 | textAlign(CENTER, CENTER); 95 | textLeading(round(0.9*(textAscent()+textDescent()))); 96 | // int x1 = but_x+but_dx/2; 97 | // int y1 = but_y+but_dy/2; 98 | int x1, y1; 99 | if (false) { 100 | //auto wrap 101 | x1 = but_x; 102 | y1 = but_y; 103 | int w = but_dx-2*2; //use a 2 pixel buffer on the left and right sides 104 | int h = but_dy; 105 | text(but_txt,x1,y1,w,h); 106 | } else { 107 | //no auto wrap 108 | x1 = but_x+but_dx/2; 109 | y1 = but_y+but_dy/2; 110 | text(but_txt,x1,y1); 111 | } 112 | } 113 | }; 114 | 115 | 116 | 117 | -------------------------------------------------------------------------------- /Processing/OBCI_V3_Debugging/OpenBCI_GUI/data/CourierNewPSMT-24.vlw: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/chipaudette/EEGHacker/f72cc121d51fb5ea2f9176ebc0bb821aef05e64e/Processing/OBCI_V3_Debugging/OpenBCI_GUI/data/CourierNewPSMT-24.vlw -------------------------------------------------------------------------------- /Processing/OBCI_V3_Debugging/OpenBCI_GUI/data/electrode_positions_12elec_scalp9.txt: -------------------------------------------------------------------------------- 1 | X,Y 2 | -0.30,-0.275 3 | -0.225,-0.05 4 | -0.225,0.175 5 | -0.275,0.335 6 | 0.0,-0.4 7 | 0.0,-0.15 8 | 0.0,0.025 9 | 0.0,0.25 10 | 0.3,-0.275 11 | 0.225,-0.025 12 | 0.225,0.175 13 | 0.275,0.335 14 | +0.1,0 15 | +0.1,0 16 | +0.1,0 17 | +0.1,0 18 | 0.0,0.025 19 | -------------------------------------------------------------------------------- /Processing/OBCI_V3_Debugging/OpenBCI_GUI/data/electrode_positions_default.txt: -------------------------------------------------------------------------------- 1 | X,Y 2 | -0.125,-0.416 3 | 0.125,-0.416 4 | -0.2,0.0 5 | 0.2,0.0 6 | -0.3425,0.27 7 | 0.3425,0.27 8 | -0.125,0.416 9 | 0.125,0.416 10 | -0.3425,-0.27 11 | 0.3425,-0.27 12 | -0.18,-0.15 13 | 0.18,-0.15 14 | -0.422,0.0 15 | 0.422,0.0 16 | -0.18,0.15 17 | 0.18,0.15 18 | 0.0,0.0 19 | -------------------------------------------------------------------------------- /Processing/OBCI_V3_Debugging/OpenBCI_GUI/data/electrode_positions_maker_faire_2013.txt: -------------------------------------------------------------------------------- 1 | X,Y 2 | -0.125,-0.416 3 | 0.125,-0.416 4 | -0.2,0.0 5 | 0.2,0.0 6 | -0.3425,0.27 7 | 0.3425,0.27 8 | -0.125,0.416 9 | 0.125,0.416 10 | 0.0,0.0 11 | 0.0,0.0 12 | 0.0,0.0 13 | 0.0,0.0 14 | 0.0,0.0 15 | 0.0,0.0 16 | 0.0,0.0 17 | 0.0,0.0 18 | 0.0,-0.275 19 | -------------------------------------------------------------------------------- /Processing/OBCI_V3_Debugging/OpenBCI_GUI/math.pde: -------------------------------------------------------------------------------- 1 | 2 | //compute the standard deviation 3 | float std(float[] data) { 4 | //calc mean 5 | float ave = mean(data); 6 | 7 | //calc sum of squares relative to mean 8 | float val = 0; 9 | for (int i=0; i < data.length; i++) { 10 | val += pow(data[i]-ave,2); 11 | } 12 | 13 | // divide by n to make it the average 14 | val /= data.length; 15 | 16 | //take square-root and return the standard 17 | return (float)Math.sqrt(val); 18 | } 19 | 20 | 21 | float mean(float[] data) { 22 | return mean(data,data.length); 23 | } 24 | 25 | int medianDestructive(int[] data) { 26 | sort(data); 27 | int midPoint = data.length / 2; 28 | return data[midPoint]; 29 | } 30 | 31 | 32 | ////////////////////////////////////////////////// 33 | // 34 | // Some functions to implement some math and some filtering. These functions 35 | // probably already exist in Java somewhere, but it was easier for me to just 36 | // recreate them myself as I needed them. 37 | // 38 | // Created: Chip Audette, Oct 2013 39 | // 40 | ////////////////////////////////////////////////// 41 | 42 | int findMax(float[] data) { 43 | float maxVal = data[0]; 44 | int maxInd = 0; 45 | for (int I=1; I maxVal) { 47 | maxVal = data[I]; 48 | maxInd = I; 49 | } 50 | } 51 | return maxInd; 52 | } 53 | 54 | float mean(float[] data, int Nback) { 55 | return sum(data,Nback)/Nback; 56 | } 57 | 58 | float sum(float[] data) { 59 | return sum(data, data.length); 60 | } 61 | 62 | float sum(float[] data, int Nback) { 63 | float sum = 0; 64 | if (Nback > 0) { 65 | for (int i=(data.length)-Nback; i < data.length; i++) { 66 | sum += data[i]; 67 | } 68 | } 69 | return sum; 70 | } 71 | 72 | float calcDotProduct(float[] data1, float[] data2) { 73 | int len = min(data1.length, data2.length); 74 | float val=0.0; 75 | for (int I=0;I 0; j--) { 104 | prev_y[j] = prev_y[j-1]; 105 | prev_x[j] = prev_x[j-1]; 106 | } 107 | 108 | //add in the new point 109 | prev_x[0] = data[i]; 110 | 111 | //compute the new data point 112 | double out = 0; 113 | for (int j = 0; j < Nback; j++) { 114 | out += filt_b[j]*prev_x[j]; 115 | if (j > 0) { 116 | out -= filt_a[j]*prev_y[j]; 117 | } 118 | } 119 | 120 | //save output value 121 | prev_y[0] = out; 122 | data[i] = (float)out; 123 | } 124 | } 125 | 126 | 127 | void removeMean(float[] filty, int Nback) { 128 | float meanVal = mean(filty,Nback); 129 | for (int i=0; i < filty.length; i++) { 130 | filty[i] -= meanVal; 131 | } 132 | } 133 | 134 | void rereferenceTheMontage(float[][] data) { 135 | int n_chan = data.length; 136 | int n_points = data[0].length; 137 | float sum, mean; 138 | 139 | //loop over all data points 140 | for (int Ipoint=0;Ipoint