From 85cd881c63b99dbf2e74acbc7f43a7befc37d9c7 Mon Sep 17 00:00:00 2001 From: Graham Jones Date: Wed, 18 Oct 2017 22:08:38 +0100 Subject: [PATCH] Fixed FFT analysis - close to working --- .../SdDataSourceNetworkPassive.java | 80 +++++++++++++++++-- 1 file changed, 74 insertions(+), 6 deletions(-) diff --git a/app/src/main/java/uk/org/openseizuredetector/SdDataSourceNetworkPassive.java b/app/src/main/java/uk/org/openseizuredetector/SdDataSourceNetworkPassive.java index cebe471..398b4c0 100644 --- a/app/src/main/java/uk/org/openseizuredetector/SdDataSourceNetworkPassive.java +++ b/app/src/main/java/uk/org/openseizuredetector/SdDataSourceNetworkPassive.java @@ -48,6 +48,8 @@ import java.util.Timer; import java.util.TimerTask; import java.util.UUID; +import static java.lang.Math.sqrt; + /** * Abstract class for a seizure detector data source. Subclasses include a pebble smart watch data source and a @@ -56,6 +58,7 @@ import java.util.UUID; public class SdDataSourceNetworkPassive extends SdDataSource { private Handler mHandler = new Handler(); private Timer mStatusTimer; + private Timer mAlarmCheckTimer; private Time mDataStatusTime; private boolean mWatchAppRunningCheck = false; private int mAppRestartTimeout = 10; // Timeout before re-starting watch app (sec) if we have not received @@ -90,6 +93,8 @@ public class SdDataSourceNetworkPassive extends SdDataSource { private short mFallThreshMax; private short mFallWindow; + private int mAlarmCount; + // raw data storage for SD_MODE_RAW private int MAX_RAW_DATA = 500; public double[] mAccData = new double[MAX_RAW_DATA]; @@ -132,6 +137,20 @@ public class SdDataSourceNetworkPassive extends SdDataSource { Log.v(TAG, "start(): status timer already running."); mUtil.writeToSysLogFile("SdDataSourceNetworkPassive.start() - status timer already running??"); } + if (mAlarmCheckTimer == null) { + Log.v(TAG, "start(): starting alarm check timer"); + mUtil.writeToSysLogFile("SdDataSourceNetworkPassive.start() - starting alarm check timer"); + mAlarmCheckTimer = new Timer(); + mAlarmCheckTimer.schedule(new TimerTask() { + @Override + public void run() { + alarmCheck(); + } + }, 0, 1000); + } else { + Log.v(TAG, "start(): alarm check timer already running."); + mUtil.writeToSysLogFile("SdDataSourceNetworkPassive.start() - alarm check timer already running??"); + } } /** @@ -290,11 +309,13 @@ public class SdDataSourceNetworkPassive extends SdDataSource { mAccData[i] = accelVals.getInt(i); } mNSamp = accelVals.length(); + mWatchAppRunningCheck = true; doAnalysis(); } else if (dataTypeStr.equals("settings")){ Log.v(TAG,"updateFromJSON - processing settings"); mSamplePeriod = (short)dataObject.getInt("analysisPeriod"); - mSampleFreq = (short)dataObject.getInt("analysisPeriod"); + mSampleFreq = (short)dataObject.getInt("sampleFreq"); + Log.v(TAG,"updateFromJSON - mSamplePeriod="+mSamplePeriod+" mSampleFreq="+mSampleFreq); mSdData.haveSettings = true; mSdData.mSampleFreq = mSampleFreq; } @@ -303,6 +324,18 @@ public class SdDataSourceNetworkPassive extends SdDataSource { } } + /** + * Calculate the magnitude of entry i in the fft array fft + * @param fft + * @param i + * @return magnitude ( Re*Re + Im*Im ) + */ + private double getMagnitude(double[] fft, int i) { + double mag; + mag = sqrt(fft[2*i]*fft[2*i] + fft[2*i + 1] * fft[2*i +1]); + return mag; + } + /** * doAnalysis() - analyse the data if the accelerometer data array mAccData * and populate the output data structure mSdData @@ -322,15 +355,14 @@ public class SdDataSourceNetworkPassive extends SdDataSource { DoubleFFT_1D fftDo = new DoubleFFT_1D(mNSamp); double[] fft = new double[mNSamp * 2]; System.arraycopy(mAccData, 0, fft, 0, mNSamp); - fftDo.realForwardFull(fft); + fftDo.realForward(fft); // Calculate the whole spectrum power (well a value equivalent to it that avoids suare root calculations // and zero any readings that are above the frequency cutoff. double specPower = 0; for (int i = 1; i < mNSamp / 2; i++) { if (i <= nFreqCutoff) { - specPower = specPower + fft[2 * i] + fft[2*i] + fft[2*i +1] * fft[2*i+1]; - + specPower = specPower + getMagnitude(fft,i); } else { fft[2*i] = 0.; fft[2*i+1] = 0.; @@ -341,7 +373,7 @@ public class SdDataSourceNetworkPassive extends SdDataSource { // Calculate the Region of Interest power and power ratio. double roiPower = 0; for (int i=nMin;i mAlarmThresh) && (10*(mSdData.roiPower/mSdData.specPower) > mAlarmRatioThresh)) { + inAlarm = true; + } else { + inAlarm = false; + } + + if (inAlarm) { + mAlarmCount+=mSamplePeriod; + if (mAlarmCount>mAlarmTime) { + mSdData.alarmState = 2; + } else if (mAlarmCount>mWarnTime) { + mSdData.alarmState = 1; + } + } else { + // If we are in an ALARM state, revert back to WARNING, otherwise + // revert back to OK. + if (mSdData.alarmState == 2) { + mSdData.alarmState = 1; + } else { + mSdData.alarmState = 0; + mAlarmCount = 0; + } + } + Log.v(TAG,"inAlarm="+inAlarm+", alarmState = "+mSdData.alarmState+" alarmCount="+mAlarmCount); + + + + } }