Added average HR calculations to SdAlgHR - SdAlgHR still needs to be commissioned in SdDataSource class so it is used though.

This commit is contained in:
Graham Jones
2023-04-07 21:35:16 +01:00
parent 908e9a8563
commit 2bac4a9522
4 changed files with 237 additions and 31 deletions

View File

@@ -3,7 +3,7 @@
xmlns:tools="http://schemas.android.com/tools" xmlns:tools="http://schemas.android.com/tools"
package="uk.org.openseizuredetector" package="uk.org.openseizuredetector"
android:versionCode="115" android:versionCode="115"
android:versionName="4.1.3n"> android:versionName="4.1.3m">
<!-- android:allowBackup="false" --> <!-- android:allowBackup="false" -->
<uses-permission android:name="android.permission.BLUETOOTH" /> <uses-permission android:name="android.permission.BLUETOOTH" />
<uses-permission android:name="android.permission.BLUETOOTH_ADMIN" /> <uses-permission android:name="android.permission.BLUETOOTH_ADMIN" />

View File

@@ -0,0 +1,99 @@
package uk.org.openseizuredetector;
import android.util.Log;
import java.util.ArrayList;
public class CircBuf {
/*
* A circular buffer used to calculate rolling averages
* Based loosely on https://gist.github.com/hardik-vala/dc2d19fa7c5108536fbbff96b4fcf105
*/
private final static String TAG = "CircBuf";
private double[] mBuff;
private double mErrVal;
private int mBuffLen;
private int mHead;
private int mTail;
private boolean mIsFull;
public CircBuf(int n, double errVal) {
/**
* Create a circular buffer of doubles, of length n members.
*/
Log.i(TAG, "CircBuf Constructor");
mBuff = new double[n];
mBuffLen = n;
mErrVal = errVal;
mHead = 0;
mTail = 0;
mIsFull = false;
}
public void add(double val) {
/**
* Add value val to the circular buffer.
*/
Log.d(TAG,"add() - before: mHead="+mHead+", mTail="+mTail);
//System.out.println(TAG+" add() - before: mHead="+mHead+", mTail="+mTail);
if (mIsFull)
mHead = (mHead + 1) % mBuffLen;
mBuff[mTail] = val;
mTail = (mTail + 1) % mBuffLen;
if (mTail == mHead)
mIsFull = true;
Log.d(TAG,"add() - after: mHead="+mHead+", mTail="+mTail);
//System.out.println(TAG+" add() - before: mHead="+mHead+", mTail="+mTail);
}
public int getNumVals() {
int numElements;
if (mIsFull) {
numElements = mBuffLen;
} else {
// Not sure if this is necessary - why would mHead be greater than mTail if the buffer is not full?
if (mHead > mTail) {
numElements = (mTail + mBuffLen) - mHead;
} else {
numElements = mTail-mHead;
}
}
return numElements;
}
/**
* Returns a double array of buffer items in order of their insertion time
* @return double[] of buffer items
*/
public double[] getVals () {
int numElements = getNumVals();
System.out.println(TAG+" getVals() - numElements=" + numElements);
double[] retArr = new double[numElements];
for (int i = 0; i < numElements; i++) {
retArr[i] = mBuff[(mHead + i) % mBuffLen];
}
return retArr;
}
public double getAverageVal() {
double hrSum = 0.;
int hrCount = 0;
double valArr[] = getVals();
double retVal;
for (int n=0; n<valArr.length; n++) {
if (valArr[n] != mErrVal) {
hrSum += valArr[n];
hrCount++;
}
}
if (hrCount>0) {
retVal = hrSum / hrCount;
} else {
retVal = -1;
}
return(retVal);
}
}

View File

@@ -25,13 +25,15 @@ public class SdAlgHr {
private double mAverageHrAlarmThreshMin; private double mAverageHrAlarmThreshMin;
private double mAverageHrAlarmThreshMax; private double mAverageHrAlarmThreshMax;
private ArrayList<Double> mHrHist; private CircBuf mAdaptiveHrBuff;
private CircBuf mAverageHrBuff;
public SdAlgHr(Context context) { public SdAlgHr(Context context) {
Log.i(TAG, "SdAlgHr Constructor"); Log.i(TAG, "SdAlgHr Constructor");
mContext = context; mContext = context;
mHrHist = new ArrayList<Double>();
updatePrefs(); updatePrefs();
mAdaptiveHrBuff = new CircBuf(mAdaptiveHrAlarmWindowDp, -1.0);
mAverageHrBuff = new CircBuf(mAverageHrAlarmWindowDp, -1.0);
} }
public void close() { public void close() {
@@ -93,15 +95,7 @@ public class SdAlgHr {
} }
private void addToHist(double hrVal) {
/**
* Add value hrVal to the heart rate history list, truncating the list if it is
* longer than the required length.
*/
Log.d(TAG,"addToHist() - length before="+mHrHist.size());
mHrHist.add(hrVal);
Log.d(TAG,"addToHist() - length before="+mHrHist.size());
}
private boolean checkSimpleHr(double hrVal) { private boolean checkSimpleHr(double hrVal) {
/** /**
@@ -118,33 +112,42 @@ public class SdAlgHr {
} }
private boolean checkAdaptiveHr(double hrVal) { private boolean checkAdaptiveHr(double hrVal) {
// FIXME Make this do something boolean retVal;
return(false); double hrThreshMin;
double hrThreshMax;
double avHr = mAdaptiveHrBuff.getAverageVal();
hrThreshMin = avHr - mAdaptiveHrAlarmThresh;
hrThreshMax = avHr + mAdaptiveHrAlarmThresh;
retVal = false;
if (hrVal < hrThreshMin) {
retVal = true;
}
if (hrVal > hrThreshMax) {
retVal = true;
}
Log.d(TAG, "checkAdaptiveHr() - hrVal="+hrVal+", avHr="+avHr+", thresholds=("+hrThreshMin+", "+hrThreshMax+"): Alarm="+retVal);
return(retVal);
} }
private boolean checkAverageHr(double hrVal) { private boolean checkAverageHr(double hrVal) {
// FIXME Make this do something boolean retVal;
return(false); double avHr = mAdaptiveHrBuff.getAverageVal();
}
public double getAverageHrVal() { retVal = false;
double hrSum = 0.; if (hrVal < mAverageHrAlarmThreshMin) {
int hrCount = 0; retVal = true;
double retVal;
for (int n=0; n<mHrHist.size(); n++) {
if (mHrHist.get(n) > -1) {
hrSum += mHrHist.get(n);
hrCount++;
} }
if (hrVal > mAverageHrAlarmThreshMax) {
retVal = true;
} }
if (hrCount>0) { Log.d(TAG, "checkAverageHr() - hrVal="+hrVal+", avHr="+avHr+", thresholds=("+mAverageHrAlarmThreshMin+", "+mAverageHrAlarmThreshMin+"): Alarm="+retVal);
retVal = hrSum / hrCount;
} else {
retVal = -1;
}
return(retVal); return(retVal);
} }
public ArrayList<Boolean> checkHr(double hrVal) { public ArrayList<Boolean> checkHr(double hrVal) {
/** /**
* Checks the current Heart Rate reading hrVal against the * Checks the current Heart Rate reading hrVal against the
@@ -153,7 +156,8 @@ public class SdAlgHr {
* true=ALARM, false=OK. * true=ALARM, false=OK.
*/ */
Log.v(TAG, "checkHr("+hrVal+")"); Log.v(TAG, "checkHr("+hrVal+")");
addToHist(hrVal); mAdaptiveHrBuff.add(hrVal);
mAverageHrBuff.add(hrVal);
ArrayList<Boolean> retVal = new ArrayList<Boolean>(); ArrayList<Boolean> retVal = new ArrayList<Boolean>();
retVal.add(checkSimpleHr(hrVal)); retVal.add(checkSimpleHr(hrVal));
retVal.add(checkAdaptiveHr(hrVal)); retVal.add(checkAdaptiveHr(hrVal));

View File

@@ -0,0 +1,103 @@
package uk.org.openseizuredetector;
import junit.framework.TestCase;
public class CircBufTest extends TestCase {
private CircBuf mCb;
public void setUp() throws Exception {
super.setUp();
mCb = new CircBuf(10, -1);
}
public void tearDown() throws Exception {
}
public void printArr(double[] arr) {
for (int n=0; n<arr.length; n++) {
System.out.println("arr["+n+"] = "+arr[n]);
}
}
public void testAdd() {
double[] retArr;
// Add a single value = we should get a single element array back.
mCb.add(1);
retArr = mCb.getVals();
assertEquals(1,retArr.length);
// Add 9 more elements - we should get a 10 element array back.
for (int i=0; i<9;i++) {
mCb.add(i);
}
retArr = mCb.getVals();
assertEquals(10,retArr.length);
}
public void testGetVals() {
double[] retArr;
// Add 10 more elements - we should get a 10 element array back.
for (int i=0; i<10;i++) {
mCb.add(i);
}
retArr = mCb.getVals();
assertEquals(0.0, retArr[0]);
assertEquals(9.0, retArr[9]);
//add one more element
mCb.add(10.0);
retArr = mCb.getVals();
printArr(retArr);
assertEquals(1.0, retArr[0]);
assertEquals(10.0, retArr[9]);
//add one more element
mCb.add(10.0);
retArr = mCb.getVals();
printArr(retArr);
assertEquals(2.0, retArr[0]);
assertEquals(10.0, retArr[9]);
}
public void testGetAverageVal() {
double[] retArr;
double avVal;
// empty array;
avVal = mCb.getAverageVal();
assertEquals(-1.0, avVal, 1e-5);
// A trivial example
for (int i=0; i<10;i++) {
mCb.add(1.0);
}
retArr = mCb.getVals();
avVal = mCb.getAverageVal();
assertEquals(1.0, avVal,1e-5);
// Real calculation
double sum = 0.0;
for (int i=0; i<10;i++) {
mCb.add(i);
sum += i;
}
avVal = mCb.getAverageVal();
assertEquals(sum/10, avVal, 1e-5);
// Error value in array - should now be average of 9 values between 1 and 9 (because zero value is removed when -1 is added to end).
sum = 0.0;
for(int i=1;i<10;i++)
sum+= i;
mCb.add(-1.0);
avVal = mCb.getAverageVal();
assertEquals(sum/9, avVal, 1e-5);
}
}