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

File: <base>/sources/benjaminmoody_at_gmail.com-ChallengeEntry.java (5,161 bytes)
/*
  Entry for the Physionet/CinC 2011 Challenge

  Benjamin E Moody <benjaminmoody@gmail.com>
*/

package org.physionet.challenge2011;
import java.io.IOException;
import java.io.InputStream;
import java.io.ObjectInputStream;

public class ChallengeEntry
{
    /* Number of signals */
    private static final int NUMSIG = 12;

    /* Length of input record (number of samples) */
    private static final int NUMSAMP = 5000;

    /* Maximum number of consecutive constant samples */
    private static final int MAX_CONSTANT_INTERVAL = 100;

    /* Maximum overall range of each signal */
    private static final int MAX_SIGNAL_PEAK = 3000;

    /* Minimum overall range of each signal */
    private static final int MIN_SIGNAL_PEAK = 40;

    /* Size of window to check for "quiet" sections */
    private static final int QUIET_WINDOW_SIZE = 32;

    /* Largest change within a window considered "quiet" */
    private static final int QUIET_THRESHOLD = 20;

    /* Minimum number of quiet windows */
    private static final int MIN_QUIET_WINDOWS = 200;

    /* Maximum number of quiet windows */
    private static final int MAX_QUIET_WINDOWS = 300;


    synchronized public int get_result(InputStream iFile, final ECG_MetaData m_MetaData)
        throws IOException
    {
        ObjectInputStream in = new ObjectInputStream(iFile);
        short data[];

        try {
            data = (short[]) in.readObject();
        }
        catch (ClassNotFoundException e) {
            throw new IOException("bad input file");
        }

        short cur_local_min[] = new short[NUMSIG];
        short cur_local_max[] = new short[NUMSIG];
        short next_local_min[] = new short[NUMSIG];
        short next_local_max[] = new short[NUMSIG];
        short global_min[] = new short[NUMSIG];
        short global_max[] = new short[NUMSIG];
        short nconst[] = new short[NUMSIG];
        short nquiet[] = new short[NUMSIG];

        int badsignal = -1;
        int t, i, w;
        short cur_sample, prev_sample;

        for (i = 0; i < NUMSIG; i++) {
            cur_local_min[i] = next_local_min[i] = global_min[i] = 32767;
            cur_local_max[i] = next_local_max[i] = global_max[i] = -32768;
        }

        w = QUIET_WINDOW_SIZE / 2;

        for (t = 0; t < NUMSAMP; t++) {

            w--;

            for (i = 0; i < NUMSIG; i++) {

                /* if signal alreay marked as bad, ignore it */
                if (i == badsignal)
                    continue;

                cur_sample = data[t * NUMSIG + i];

                /* check for constant signal */
                if (t > 0) {
                    prev_sample = data[(t-1) * NUMSIG + i];

                    if (cur_sample == prev_sample) {
                        nconst[i]++;
                        if (nconst[i] > MAX_CONSTANT_INTERVAL) {
                            if (badsignal >= 0)
                                return 1;
                            badsignal = i;
                            continue;
                        }
                    }
                    else {
                        nconst[i] = 0;
                    }
                }

                /* check global min/max */
                if (cur_sample > global_max[i])
                    global_max[i] = cur_sample;
                if (cur_sample < global_min[i])
                    global_min[i] = cur_sample;

                /* local min/max */
                if (cur_sample > cur_local_max[i])
                    cur_local_max[i] = next_local_max[i] = cur_sample;
                else if (cur_sample > next_local_max[i])
                    next_local_max[i] = cur_sample;

                if (cur_sample < cur_local_min[i])
                    cur_local_min[i] = next_local_min[i] = cur_sample;
                else if (cur_sample < next_local_min[i])
                    next_local_min[i] = cur_sample;

                if (w == 0) {
                    if (cur_local_max[i] - cur_local_min[i] <= QUIET_THRESHOLD)
                        nquiet[i]++;
                    cur_local_min[i] = 32767;
                    cur_local_max[i] = -32768;
                }
            }

            if (w == 0) {
                w = QUIET_WINDOW_SIZE / 2;

                short tmp[] = cur_local_min;
                cur_local_min = next_local_min;
                next_local_min = tmp;

                tmp = cur_local_max;
                cur_local_max = next_local_max;
                next_local_max = tmp;
            }
        }

        for (i = 0; i < NUMSIG; i++) {
            if (i == badsignal)
                continue;
            if (nquiet[i] < MIN_QUIET_WINDOWS || nquiet[i] > MAX_QUIET_WINDOWS)
                break;
        }

        if (i == NUMSIG)
            return 0;

        for (i = 0; i < NUMSIG; i++) {
            if (i == badsignal)
                continue;

            if (global_max[i] - global_min[i] > MAX_SIGNAL_PEAK
                || global_max[i] - global_min[i] < MIN_SIGNAL_PEAK) {

                if (badsignal >= 0)
                    return 1;
                badsignal = i;
            }
        }

        return 0;
    }
}