/*
* Copyright (C) 2014 TU Darmstadt, Hessen, Germany.
* Department of Computer Science Databases and Distributed Systems
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
/**
*
*/
package de.tudarmstadt.dvs.myhealthassistant.myhealthhub.examples;
import java.util.Iterator;
import java.util.LinkedList;
import java.util.List;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
import android.util.Log;
import de.tudarmstadt.dvs.myhealthassistant.myhealthhub.events.AbstractChannel;
import de.tudarmstadt.dvs.myhealthassistant.myhealthhub.events.Event;
import de.tudarmstadt.dvs.myhealthassistant.myhealthhub.events.sensorreadings.SensorReadingEvent;
import de.tudarmstadt.dvs.myhealthassistant.myhealthhub.events.sensorreadings.cardiovascular.ECGEvent;
import de.tudarmstadt.dvs.myhealthassistant.myhealthhub.events.sensorreadings.cardiovascular.HeartRateEvent;
/**
* @author chris
*
*/
public class ECGtoHR {
/* Define event channel and event receiver */
private final IntentFilter readingChannel = new IntentFilter(SensorReadingEvent.ECG_STREAM);
private ReadingEventReceiver mReadingEventReceiver;
private Context ctx;
private static int PEAK_HIGHT_THRES = 30;
private static int NUMBER_OF_VALUES = 104;
private String TAG = "ECGtoHR";
private boolean D = false;
private int number;
private String oldID;
private List<Integer> stream;
int[] pulseValues;
int pulseValuesIdx;
// calc RR-Interval factor
float factor;
private int eventIndex;
private String timeOfMeasurment;
// Roger: on start
public ECGtoHR(Context ctx) {
if (D)
Log.d(TAG, TAG + " was started and listening on "
+ SensorReadingEvent.ECG_STREAM);
this.ctx = ctx;
mReadingEventReceiver = new ReadingEventReceiver();
ctx.getApplicationContext().registerReceiver(mReadingEventReceiver,
readingChannel);
oldID = "";
number = 0;
stream = new LinkedList<Integer>();
factor = 1f / (2f * NUMBER_OF_VALUES);
pulseValuesIdx = 0;
pulseValues = new int[4];
eventIndex = 0;
}
// Roger: on stop
public void onStop() {
ctx.getApplicationContext().unregisterReceiver(mReadingEventReceiver);
}
/** Event receiver implemented as a Android BroadcastReceiver */
private class ReadingEventReceiver extends BroadcastReceiver {
@Override
public void onReceive(Context context, Intent intent) {
/* Get event type and the event itself */
String eventType = intent
.getStringExtra(Event.PARCELABLE_EXTRA_EVENT_TYPE);
if (D)
Log.d(TAG, "Incoming event of type " + eventType);
if (eventType.equals(ECGEvent.EVENT_TYPE)) {
// Handle incoming acceleration event:
ECGEvent evt = (ECGEvent) intent
.getParcelableExtra(Event.PARCELABLE_EXTRA_EVENT);
if (evt.getID() == oldID) {
if (D)
Log.d(TAG, "old event");
} else {
incomingECGEvent(evt);
oldID = evt.getID();
findRRInterval();
timeOfMeasurment = evt.getTimeOfMeasurement();
}
}
};
private void incomingECGEvent(ECGEvent evt) {
int[] values = evt.getEcgValues();
if (D)
Log.d(TAG, "#readings: " + values.length);
number++;
values = filterValues(values);
// printValues(values);
for (int i = 1; i < values.length - 1; i++) {
if (values[i - 1] < values[i] && values[i] > values[i + 1]) {
// check difference of peak
int diff = (values[i] - values[i - 1])
+ (values[i] - values[i + 1]);
if (diff >= PEAK_HIGHT_THRES) {
if (D)
Log.d(TAG, "Peak found at " + i
+ " in packet number " + number);
addPeak(i);
break;
}
}
}
addPeak(-1);
}
public void findRRInterval() {
int rrInterval;
int peak;
// Search for first peak
Iterator<Integer> streamIterator = stream.iterator();
while (streamIterator.hasNext()) {
peak = (Integer) streamIterator.next();
if (peak != -1) {
// first Peak found
rrInterval = NUMBER_OF_VALUES - peak;
// Search for second peak
while (streamIterator.hasNext()) {
peak = (Integer) streamIterator.next();
if (peak != -1) {
// Peak found: calc pulse
rrInterval += peak;
calculatePulseFromRR(rrInterval);
return;
} else {
// no peak: add miliseconds
rrInterval += NUMBER_OF_VALUES;
}
}
}
}
}
private void calculatePulseFromRR(int rrInterval) {
// calc pulse
float pulse = 60.0f / ((float) rrInterval * factor);
// Average pulse
pulseValues[pulseValuesIdx] = (int) pulse;
int outputPulse = 0;
for (int val : pulseValues) {
outputPulse += val;
}
outputPulse = outputPulse / pulseValues.length;
// increase index
if (pulseValuesIdx < pulseValues.length - 1) {
pulseValuesIdx++;
} else {
pulseValuesIdx = 0;
}
// Create HR Event
HeartRateEvent heartRateEvent = new HeartRateEvent(
"ECGtoHR_transformation_" + getIndex(),
(String) android.text.format.DateFormat.format(
"yyyy-MM-dd_hh:mm:ss", new java.util.Date()),
"ECGtoHR_transformation", "ECG sensor", timeOfMeasurment,
outputPulse);
// Send event
Intent i = new Intent();
i.putExtra(Event.PARCELABLE_EXTRA_EVENT_TYPE,
heartRateEvent.getEventType());
i.putExtra(Event.PARCELABLE_EXTRA_EVENT, heartRateEvent);
i.setAction(AbstractChannel.RECEIVER);
ctx.sendBroadcast(i);
}
private int getIndex() {
if (eventIndex != Integer.MAX_VALUE) {
return eventIndex++;
} else {
return eventIndex = 0;
}
}
private int[] filterValues(int[] values) {
for (int i = 0; i < values.length - 5; i++) {
values[i] = (values[i] + values[i + 1] + values[i + 2]
+ values[i + 3] + values[i + 4]) / 5;
}
if(D)printValues(values);
return values;
}
private void printValues(int[] values) {
String output = "";
for(int i : values) {
output += i+" ";
}
Log.d(TAG, "xyz "+output);
}
private void addPeak(int pos) {
// Add to top
stream.add(0, pos);
// Remove last element while more than 4
while (stream.size() >= 5) {
stream.remove(stream.size() - 1);
}
}
}
}