Skip to content
This repository has been archived by the owner on Apr 13, 2021. It is now read-only.

Commit

Permalink
Version 1.7 with Data recording, downsampled notch-filtered EEG graph…
Browse files Browse the repository at this point in the history
…, interactive filters, and Lottie SVG animations
  • Loading branch information
jdpigeon committed Apr 2, 2017
1 parent aa73567 commit 2ab2600
Show file tree
Hide file tree
Showing 43 changed files with 340 additions and 317 deletions.
2 changes: 1 addition & 1 deletion EEG101/android/.idea/misc.xml

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

5 changes: 2 additions & 3 deletions EEG101/android/app/build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -90,8 +90,8 @@ android {
applicationId "com.eeg_project"
minSdkVersion 16
targetSdkVersion 25
versionCode 9
versionName "1.6"
versionCode 10
versionName "1.7"
ndk {
abiFilters "armeabi-v7a"
}
Expand Down Expand Up @@ -150,7 +150,6 @@ dependencies {
compile files('libs/libmuse_android.jar')
compile "com.androidplot:androidplot-core:1.2.2"
compile group: 'com.github.wendykierp', name: 'JTransforms', version: '3.1'
// compile 'com.airbnb.android:lottie:1.5.2'
}

// Run this once to be able to run the application with BUCK
Expand Down
1 change: 0 additions & 1 deletion EEG101/android/app/src/main/assets/awakeasleep.json

This file was deleted.

2 changes: 1 addition & 1 deletion EEG101/android/app/src/main/assets/epoching.json
100755 → 100644

Large diffs are not rendered by default.

2 changes: 1 addition & 1 deletion EEG101/android/app/src/main/assets/fourier.json
100755 → 100644

Large diffs are not rendered by default.

Binary file removed EEG101/android/app/src/main/assets/images/img_0.png
Binary file not shown.
Binary file removed EEG101/android/app/src/main/assets/images/img_1.png
Binary file not shown.
160 changes: 82 additions & 78 deletions EEG101/android/app/src/main/assets/index.android.bundle

Large diffs are not rendered by default.

Original file line number Diff line number Diff line change
@@ -1 +1 @@
,��o�ـ��$\m�X�����
�����p;'QI�ї:
Original file line number Diff line number Diff line change
Expand Up @@ -23,17 +23,16 @@ public class MainApplication extends Application implements ReactApplication {

private final ReactNativeHost mReactNativeHost = new ReactNativeHost(this) {
@Override
protected boolean getUseDeveloperSupport() {
Log.w("MainApplication", "build config is " + BuildConfig.DEBUG);
return true;
public boolean getUseDeveloperSupport() {
return BuildConfig.DEBUG;
}

// All packages for native libraries must be added to the array returned by this method
@Override
protected List<ReactPackage> getPackages() {
return Arrays.<ReactPackage>asList(
new MainReactPackage(),
new LottiePackage(),
new LottiePackage(),
new SvgPackage(),
new EEGPackage()
);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,9 @@
import java.util.Arrays;

/**
* Created by dano on 14/03/17.
* Writes EEG data (either raw/filtered EEG or computed FFT) into a csv. Presents a toast when
* recording is started and starts sharing intent for sending data to email when recording is
* completed
*/

public class EEGFileWriter {
Expand Down Expand Up @@ -63,9 +65,6 @@ public void addDataToFile(double[] data) {
// Append timestamp
Long tsLong = System.currentTimeMillis();
builder.append(tsLong.toString() +",");

// Loops through every FFT bin

for (int j = 0; j < data.length; j++) {
builder.append(Double.toString(data[j]));
if (j < data.length - 1) {
Expand All @@ -75,26 +74,14 @@ public void addDataToFile(double[] data) {
builder.append("\n");
}


public void writeFile(String title) {
FileOutputStream outputStream ;
try {
final File dir = context.getExternalFilesDir(Environment.DIRECTORY_DOWNLOADS);
final File file = new File(dir,
title+fileNum+
".csv");
Log.w("Listener", "Creating new file " + file);
final File file = new File(dir, title + fileNum + ".csv");
fileWriter = new java.io.FileWriter(file);

if (!dir.exists()) {
dir.mkdir();
}


BufferedWriter bufferedWriter = new BufferedWriter(fileWriter);
bufferedWriter.write(builder.toString());
bufferedWriter.close();

sendData(file);
fileNum ++;
isRecording = false;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@
// AndroidPlot class that stores dataSource to be plotted. getX() and getY() are called by XYPlot to to draw graph
// This implementation only stores Y values, with X values implicitily determined by the index of the dataSource in the LinkedList
// readwritelocks prevent flickering issue when dataseries is modified while being rendered
class DynamicSeries implements XYSeries, PlotListener {
public class DynamicSeries implements XYSeries, PlotListener {

// -------------------------------------------------------------
// Variables
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -48,27 +48,18 @@ public class EEGGraph extends FrameLayout {
// ----------------------------------------------------------------------
// Variables

public XYPlot eegPlot;
public static final int PLOT_LENGTH = 1100;
public static XYPlot eegPlot;
public static final int PLOT_LENGTH = 366;
private static final String PLOT_TITLE = "Raw_EEG";
public PlotUpdater plotUpdater;
EEGDataSource dataSource;
private EEGDataSource dataSource;
public DynamicSeries dataSeries;
String TAG = "EEGGraph";
Thread dataThread;
Thread renderingThread;
LineAndPointFormatter lineFormatter;
public DataListener dataListener;
public CircularBuffer eegBuffer = new CircularBuffer(220, 4);
public double[] newData = new double[4];


// Filter variables
public int filterFreq;
public Filter highPassFilter;
public Filter bandstopFilter;
public double[] bandstopFiltState;
public double[] highPassFiltState;
private Thread dataThread;
private Thread renderingThread;
private LineAndPointFormatter lineFormatter;
public DataListener dataListener;
public CircularBuffer eegBuffer = new CircularBuffer(220, 4);


// Bridged props
// Default channelOfInterest = 1 (left ear)
Expand All @@ -83,7 +74,6 @@ public class EEGGraph extends FrameLayout {
public EEGGraph(Context context) {
super(context);
appState = ((MainApplication)context.getApplicationContext());

initView(context);
// Data threads are started in onVisibilityChanged function
}
Expand All @@ -101,7 +91,6 @@ public EEGGraph(Context context, AttributeSet attrs, int defStyle) {
// -----------------------------------------------------------------------
// Bridge functions
public void setChannelOfInterest(int channel) {

channelOfInterest = channel;
dataSeries.clear();

Expand Down Expand Up @@ -168,29 +157,24 @@ public void initView(Context context) {
highPassFilter = new Filter(filterFreq, "highpass", 2, .1, 0);
highPassFiltState = new double[bandstopFilter.getNB()];
*/

// Set X and Y domain
eegPlot.setRangeBoundaries(600, 1000, BoundaryMode.FIXED);
eegPlot.setDomainBoundaries(0, PLOT_LENGTH, BoundaryMode.FIXED);

// This is critical for being able to set the color of the plot
PixelUtils.init(getContext());



// Create line formatter with set color
lineFormatter = new FastLineAndPointRenderer.Formatter(Color.rgb(255, 255, 255), null, null, null);

// Set line thickness
//Float linethickness = new Float(1);
//lineFormatter.getLinePaint().setStrokeWidth(linethickness);
lineFormatter.getLinePaint().setStrokeWidth(3);

// add series to plot
eegPlot.addSeries(dataSeries,
lineFormatter);

// hook up series to dataSource source
//dataSource.addObserver(plotUpdater);

// Format plot layout
//Remove margins, padding and border
eegPlot.setPlotMargins(0, 0, 0, 0);
Expand All @@ -216,12 +200,12 @@ public void initView(Context context) {
eegPlot.getGraph().getDomainOriginLinePaint().setColor(Color.TRANSPARENT);

// Remove extraneous elements
//eegPlot.setTitle(null);
eegPlot.getLayoutManager().remove(eegPlot.getLegend());

// Set size of plot
SizeMetric height = new SizeMetric(1, SizeMode.FILL);
SizeMetric width = new SizeMetric(1, SizeMode.FILL);

// Set size of plot
eegPlot.getGraph().setSize(new Size(height, width));

Expand All @@ -233,7 +217,6 @@ public void initView(Context context) {
this.addView(eegPlot, new LayoutParams(
LayoutParams.MATCH_PARENT, LayoutParams.MATCH_PARENT));

eegPlot.setDrawingCacheEnabled(true);

// Explicity visibility setting handles bug on older devices where graph wasn't starting
onVisibilityChanged(this, View.VISIBLE);
Expand All @@ -247,9 +230,6 @@ public void onVisibilityChanged(View changedView, int visibility){
else if (dataThread == null || !dataThread.isAlive()) {
startDataThread();
startRenderingThread();
// Register a listener to receive connection state changes.
dataListener = new DataListener();
appState.connectedMuse.registerDataListener(dataListener, MuseDataPacketType.EEG);
}
}

Expand All @@ -258,7 +238,10 @@ else if (dataThread == null || !dataThread.isAlive()) {

// Start thread that will update the dataSource whenever a Muse dataSource packet is received
public void startDataThread() {
dataListener = new DataListener();

// Register a listener to receive dataSource packets from Muse. Second argument defines which type(s) of dataSource will be transmitted to listener
appState.connectedMuse.registerDataListener(dataListener, MuseDataPacketType.EEG);
dataThread = new Thread (dataSource);
dataThread.start();
}
Expand All @@ -270,7 +253,6 @@ public void startRenderingThread(){
renderingThread.start();
}


public void stopThreads(){
plotUpdater.stopThread();
dataSource.stopThread();
Expand All @@ -286,18 +268,36 @@ public void stopThreads(){
// Listener that receives incoming dataSource from the Muse.
// Will call receiveMuseDataPacket as dataSource comes in around 220hz (260hz for Muse 2016)
// Updates eegBuffer with latest values for all 4 electrodes
class DataListener extends MuseDataListener {
Boolean isLowEnergy;
public class DataListener extends MuseDataListener {
public double[] newData;

// Filter variables
public boolean filterOn = false;
public Filter bandstopFilter;
public double[][] bandstopFiltState;
public double[] bandstopFiltResult;

DataListener() {
if (appState.connectedMuse.isLowEnergy()) {
filterOn = true;
bandstopFilter = new Filter(256, "bandstop", 5, 55, 65);
bandstopFiltState = new double[4][bandstopFilter.getNB()];
}
newData = new double[4];
}

@Override
public void receiveMuseDataPacket(final MuseDataPacket p, final Muse muse) {
getEegChannelValues(newData, p);

if(filterOn) {
bandstopFiltState = bandstopFilter.transform(newData, bandstopFiltState);
newData = bandstopFilter.extractFilteredSamples(bandstopFiltState);
}
eegBuffer.update(newData);
}

// Updates newData array based on incoming EEG channel values
private void getEegChannelValues(double[] newData, MuseDataPacket p) {
newData[0] = p.getEegChannelValue(Eeg.EEG1);
newData[1] = p.getEegChannelValue(Eeg.EEG2);
Expand Down Expand Up @@ -347,30 +347,27 @@ public void stopThread() {
// Updates dataSeries, performs dataSource processing
public final class EEGDataSource implements Runnable {
private boolean keepRunning;
private int stepSize;
EEGFileWriter fileWriter = new EEGFileWriter(getContext(), PLOT_TITLE);
public EEGFileWriter fileWriter = new EEGFileWriter(getContext(), PLOT_TITLE);
public boolean isRecording;

// Choosing these step sizes arbitrarily based on how they look
public EEGDataSource(Boolean isLowEnergy) {
if (isLowEnergy) {stepSize = 6;}
else {
stepSize = 5;
}
}

@Override
public void run() {
try {
keepRunning = true;
while (keepRunning) {
if (eegBuffer.getPts() >= stepSize) {
if (eegBuffer.getPts() >= 3) {
if (dataSeries.size() >= PLOT_LENGTH) {
dataSeries.removeFirst();
}


// For adding 10 data points at a time (Full sampling)
//dataSeries.addAll(eegBuffer.extractSingleChannelTransposedAsDouble(10, channelOfInterest - 1));

// For adding every 5th or 6th data point (Down sampling)
dataSeries.addLast(eegBuffer.extract(1)[0][channelOfInterest - 1]);
if (isRecording) { fileWriter.addDataToFile(eegBuffer.extract(1)[0]);}

Expand Down
Loading

0 comments on commit 2ab2600

Please sign in to comment.