package org.physionet.challenge2011; import java.io.IOException; import java.io.InputStream; import java.io.ObjectInputStream; public class ChallengeEntry { // ECG data characteristics. In the general case, these should be read // from metadata. In the Challenge, they are givens, as below. final static int sfreq = 500; // samples per second per signal final static int nsig = 12; // number of signals final static int tmax = 5000; // total number of samples per signal // Histogram parameters. In the general case, these should be calculated // from the ADC characteristics. For the Challenge, the ADC characteristics // (16 bit, 5 microvolt steps, signed (two's complement) output) are known. final static int nbins = 2048; // number of bins per histogram final static int binwidth = 32; // raw ADC units; 1 unit = 5 microvolts final static int zbin = 1024; // bin number corresponding to 0 V input // Classifier parameters and variables. int nb; // number of non-empty bins in a histogram final static int nbmax = nbins/100; // acceptable signals have nb <= nbmax final static int nbmin = nbins/1000;// acceptable signals have nb >= nbmin final static int thr = 2*nsig-3; // decision threshold int score = 0; // ECG quality (0 - nsig*2). Each signal with // nbmin <= nb contributes 2 to score if nb <= nbmax, // or 1 if nb > nbmax; acceptable ECGs have score >= thr final static int GOOD = 0; // acceptable ECG final static int BAD = 1; // unacceptable ECG int result = BAD; // result // Raw ECG samples and histograms. The raw ECG samples are read from iFile // as short (16-bit) signed integers, in sets of nsig (12) samples (one // from each signal); tmax sets from the input are stored consecutively in // data[]. The histograms are constructed by the code below, one for each // signal. short[] data = new short[tmax*nsig]; short[][] ah = new short[nsig][nbins]; // amplitude histograms synchronized public int get_result(InputStream iFile, final ECG_MetaData m_MetaData) throws IOException { ObjectInputStream in = new ObjectInputStream(iFile); try { data = (short[])in.readObject(); } catch (ClassNotFoundException e) { e.printStackTrace(); } iFile.close(); // Build amplitude histograms for each lead. // Each histogram has 2048 bins, and each bin covers a range of 160 // microvolts (32 adu). Shifting a raw sample right by 5 bits and // adding 1024 converts it to a bin number. for (int i = 0, t = 0; t < tmax; t++) { for (int s = 0; s < nsig; s++) { int n = (data[i++] / binwidth) + zbin; ah[s][n]++; } } score = 0; // initialize the score for this ECG // Examine each histogram to determine if the signal is flat (missing), // or else if it contains a reasonable range of amplitudes. for (int s = 0; s < nsig; s++) { // Count non-empty bins in histogram for signal s int nb = 0; for (int n = 0; n < nbins; n++) { if (ah[s][n] > 0) nb++; ah[s][n] = 0; // reset histogram for the next ECG } // Adjust quality estimate based on signal s if (nbmin <= nb) { score++; if (nb <= nbmax) { score++; } } } // Classify this ECG based on the quality estimate. If the value // returned is -9 to 0, the ECG is classified as acceptable; a // return value of 1 to 10 indicates it is unacceptable (by the // rules of the challenge. result = thr - score; if (result > 10) { result = 10; } return result; } }