Skip to content

Instantly share code, notes, and snippets.

@kasperkamperman
Created June 13, 2019 20:30
Show Gist options
  • Save kasperkamperman/5a52eb345416ed605d39e2746fe2f557 to your computer and use it in GitHub Desktop.
Save kasperkamperman/5a52eb345416ed605d39e2746fe2f557 to your computer and use it in GitHub Desktop.
Code in which I read serial data and write it to a CSV file. Used for a research project.
// ReadPulseCooking.pde
import processing.serial.*;
/*
http://pulsesensor.myshopify.com/
Uses a modified pulse sensor script in Arduino to update each 10ms
A different string is formulated with all the data
We use to pulse flag to add data to running average etc.
*/
public class ReadPulseCooking //extends PApplet
{
PApplet p;
Serial port;
int heartbeatVisual;
long rowId = 0;
long timeInMillis = 0;
PrintWriter outputCSV;
private boolean isLookingAuto = false;
private boolean isLookingManual = false;
private boolean isLooking = false;
private boolean isReadingManual = false;
//long timeStamp;
// calculations RunningStat
private RunningStat bpmStat;
private RunningStat bpmLookingStat;
private RunningStat bpmNotLookingStat;
private int pulseBPM;
private float [] [] bpmStatArray;
boolean turnPortOff = false;
public ReadPulseCooking (PApplet p) {
this.p = p;
//printArray(Serial.list());
if(!turnPortOff)
{ println("open pulse cooking port: "+Serial.list()[2]);
port = new Serial(p, Serial.list()[2], 115200);
port.clear(); // flush buffer
port.bufferUntil(10); // set buffer full flag on receipt of carriage return
}
// able to record about 40 minutes
// 120BPM*40 = 4800
//sampleArraySize = 4800;
//sampleArray = new PulseSample[sampleArraySize];
//sampleArrayIndex = 0;
// runningstat
bpmStat = new RunningStat();
bpmLookingStat = new RunningStat();
bpmNotLookingStat = new RunningStat();
// array: cols - rows (rows: normal/looking/not-looking, cols:mean, std)
bpmStatArray = new float[2][3];
}
void dispose()
{ if(!turnPortOff)
{
println("stop ReadPulseCooking serialport");
port.clear();
port.stop();
}
}
void reinitSerialPort()
{ if(!turnPortOff)
{
// restarts Arduino, that's the reason
port.clear();
port.stop();
port = new Serial(p, Serial.list()[2], 115200);
port.clear(); // flush buffer
port.bufferUntil(10); // set buffer full flag on receipt of carriage return
println("re-opened pulse-amped port: "+Serial.list()[1]);
}
}
public void updateIsLookingAuto(boolean val)
{ isLookingAuto = val;
if(isLookingAuto || isLookingManual) isLooking = true;
else isLooking = false;
}
public void updateIsLookingManual(boolean val)
{ isLookingManual = val;
if(isLookingAuto || isLookingManual) isLooking = true;
else isLooking = false;
}
public void updateIsReading(boolean val)
{ isReadingManual = val;
}
//public void serialEvent(Serial s)
public void serialEvent()
{
String incomingData = port.readStringUntil(10);
incomingData = trim(incomingData);
String[] values = split(incomingData, ',');
//println("incomingData: "+incomingData);
//println(values[0]);
//println(values[1]);
//timeStamp = Long.parseLong(values[0]);
pulseBPM = int(values[1]);
//println("pulseBPMCook: "+pulseBPM);
if(isTimeRunning)
{
timeInMillis = getRunTime(); // get the runtime, so that's written // millis();
// update RunningStat
if(pulseBPM>0)
{
bpmStat.addSample(pulseBPM);
if(isLooking) bpmLookingStat.addSample(pulseBPM);
else bpmNotLookingStat.addSample(pulseBPM);
}
bpmStatArray[0][0] = (float) bpmStat.getMean();
bpmStatArray[0][1] = (float) bpmLookingStat.getMean();
bpmStatArray[0][2] = (float) bpmNotLookingStat.getMean();
bpmStatArray[1][0] = (float) bpmStat.getStdDev();
bpmStatArray[1][1] = (float) bpmLookingStat.getStdDev();
bpmStatArray[1][2] = (float) bpmNotLookingStat.getStdDev();
// store sample in csv file
// rowId, millis Processing, millis Arduino, BPM, IBI, isLooking, isLookingAuto, isLookingManual
String csv = rowId + "," + timeInMillis + "," + int(values[0]) + "," + pulseBPM + "," +
int(isPersonWaiting) + "," + int(isSession) + ","+ int(isLooking) + "," + int(isLookingAuto) + "," + int(isLookingManual) + "," +
// mean bpm total std bpm total
bpmStatArray[0][0] + "," + bpmStatArray[1][0] + "," +
// mean looking std bpm looking
bpmStatArray[0][1] + "," + bpmStatArray[1][1] + "," +
// mean bpm not looking std bpm not looking
bpmStatArray[0][2] + "," + bpmStatArray[1][2];
outputCSV.println(csv);
//println(csv);
rowId++;
}
}
void startReading(String fileName)
{
outputCSV = p.createWriter(fileName);
rowId = 0;
// reset Runningstat
bpmStat.clear();
bpmLookingStat.clear();
bpmNotLookingStat.clear();
}
void stopReading()
{ outputCSV.flush();
outputCSV.close();
}
}
// RunningStat.PDE -----------
// http://whileonefork.blogspot.nl/2011/09/tracking-running-standard-deviation.html
// points to: http://www.johndcook.com/standard_deviation.html
// This better way of computing variance goes back to a 1962 paper by B. P. Welford and is presented in
// Donald Knuth's Art of Computer Programming, Vol 2, page 232, 3rd edition.
// std dev is sqrt of variance
//class
public class RunningStat {
private int m_n;
private double m_oldM;
private double m_newM;
private double m_oldS;
private double m_newS;
public RunningStat() {
m_n = 0;
}
public void clear() { m_n = 0; }
public void addSample(double sample) {
m_n++;
// See Knuth TAOCP vol 2, 3rd edition, page 232
if (m_n == 1)
{
m_oldM = m_newM = sample;
m_oldS = 0.0;
}
else
{
m_newM = m_oldM + (sample - m_oldM)/m_n;
m_newS = m_oldS + (sample - m_oldM)*(sample - m_newM);
// set up for next iteration
m_oldM = m_newM;
m_oldS = m_newS;
}
}
public int getNumSamples() { return m_n; }
public double getMean() { return (m_n > 0) ? m_newM : 0.0; }
public double getVariance() { return ( (m_n > 1) ? m_newS/(m_n - 1) : 0.0 ); }
public double getStdDev() { return Math.sqrt(getVariance()); }
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment