Improving the Quality of ECGs Collected using Mobile Phones: The PhysioNet/Computing in Cardiology Challenge 2011 1.0.0

File: <base>/sources/dieter.hayn_at_ait.ac.at-ChallengeEntry.java (3,357 bytes)
package org.physionet.challenge2011;
import java.io.IOException;
import java.io.InputStream;
import java.io.ObjectInputStream;
import android.util.Log;

/* Computing in Cardiology Challenge Entry 2011
 * Dieter Hayn, Bernhard Jammerbund, Guenter Schreier
 * AIT Austrian Institute of Technology GmbH
 * Reininghausstr. 13, 8020 Graz, Austria
 * Tel.: +43 664 8157858
 * EMail: dieter.hayn@ait.ac.at
 */
public class ChallengeEntry {

	public static final String DEBUGTAG = ChallengeEntry.class.toString();
	final static int FS= 500;					//Sampling Frequency
	final static int CH= 12;
	final static int WIN=FS*10;
	final static int START = FS*1;
	
	//Threshold values 
	final static int MAX_AMP = 2000;
	final static short MAX_DIFF = 400; 
	final static short BAD_AROUND_SPIKE = 5;
	
	final static short MAX_WRONG_AMP = 1800;
	final static short MAX_WRONG_DIFF = 1800;
	final static short MAX_CONSTANT = 3600;
	final static short MAX_BAD = 4000;
	final static short N_X_MAX = 49;
	final static short CHAN_DIST = 2000;
	
	//Define Quality values (could also be defined as enum...)
	final static int GOOD = 0;
	final static int BAD =  1;
	final static int AMP =  2;
	final static int DIFF =  3;
	final static int CONST =  4;
	final static int CROSS =  5;
	
	short[] data=new short[WIN*CH];
	boolean[] good_samples = new boolean[WIN-START];
	
	synchronized public int get_result(
			InputStream iFile, 
			final ECG_MetaData m_MetaData) 
	throws IOException 
	{
		ObjectInputStream in = new ObjectInputStream(iFile);
		int result = GOOD; 
		
		try {
			data = (short[])in.readObject();
		} catch (ClassNotFoundException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
			Log.e(DEBUGTAG,"Could not open data file.");
		}
		iFile.close();	

		for (int chan_i=0; chan_i<CH; chan_i++){
			int n_wrong_amp = 0;
			int n_wrong_diff = 0;
			int n_constant = 0;
			int n_bad = 0;
			short n_x_this_chan = 0;
			
			for (int i=0; i<WIN-START; i++){
				good_samples[i] = true;
			}
			
			for (int i=0; i<WIN-START; i++){
				short val = data[CH*(i + START) + chan_i];
				short prev_val = data[CH*(i + START - 1) + chan_i];
				
				if (Math.abs(val - prev_val) > MAX_DIFF){
					for (	int j=Math.max(i-BAD_AROUND_SPIKE,0); 
							j<i+BAD_AROUND_SPIKE+1 && j<WIN-START; 
							j++)
					{
						if (good_samples[j]){
							n_wrong_diff++;
							good_samples[j] = false;
							n_bad++;
						}
					}
				} else if (Math.abs(val) > MAX_AMP){
					n_wrong_amp++;
					good_samples[i] = false;
					n_bad++;
				} else if (val == prev_val){
					n_constant++;
					good_samples[i] = false;
					n_bad++;
				}
				if (n_bad > MAX_BAD){
					return BAD;
				}
				if (n_wrong_amp > MAX_WRONG_AMP){
					return AMP;
				}
				if (n_wrong_diff > MAX_WRONG_DIFF){
					return DIFF;
				}
				if (n_constant > MAX_CONSTANT){
					return CONST;
				}
				
				for (int sec_chan_i = chan_i+1; sec_chan_i < CH; sec_chan_i++){
					int sec_val = -CHAN_DIST * (sec_chan_i-chan_i) + data[CH*(i + START) + sec_chan_i];
					int sec_prev_val = -CHAN_DIST * (sec_chan_i-chan_i) + data[CH*(i + START -1) + sec_chan_i];
					if (
						val == sec_val ||
						((prev_val < sec_prev_val) == (val > sec_val))
					){
						n_x_this_chan++;
					}
				}
				if (n_x_this_chan > N_X_MAX){
					return CROSS;
				}
			} // for i
		} // for chan_i
		return result;
	}
}