scripts/channelClasses/standard/HRpt.java

/////////////////////////////////////////////////////////////////
// Processes ECG data by the Pan-Tompkins algorithm, to generate and
// append HR and RR timeseries
//
// This code is compiled at runtime, but compilation can be tested by:
//    javac -cp build scripts/channelClasses/standard/HRpt.java
//    rm scripts/channelClasses/standard/HRpt.class 
//
// Try this script, HRpt, with
//    java -ea -cp build:lib/derby.jar:jri/JRI.jar -Dserver.cache.enable=false -Djava.library.path=c:jri  frontendClasses/CLI -fn data/10006636.EC.NS5 -scriptChannel HRpt -paradigm ec -scriptEpoch OneLong -reviewSeries
//
// and see, from the additional series, that the mean HR is about 59.8 bpm.  
// Then try this script again, but do spectral transformation (but not score)
//
//    java -ea -cp build:lib/derby.jar:jri/JRI.jar -Dserver.cache.enable=false -Djava.library.path=c:jri  frontendClasses/CLI -fn data/10006636.EC.NS5 -scriptChannel HRpt -paradigm ec -scriptEpoch OneLong -chanSelection "PrimarySite LIKE '_z' OR Mode='ECG' OR Mode='CED'" -transform power -binZ PrimarySite -display "TiledStack(offsetV=0.2, offsetH=0.25)"
//
// and see if ECG peaks at 0.970 Hz, and respiratory sinus arrhythmia is 
// apparent in ECG_Rate at 0.2 -- 0.3 Hz.  Finally, try another script and
// the HeartRate scoring option (but no spectral transform)
//
//   java -cp build:lib/derby.jar -Dserver.cache.enable=false -Djava.library.path=c frontendClasses/CLI -fn data/10006636.EC.NS5 -scriptChannel HRpt -paradigm ec -scriptEpoch OneLong -chanSelection "PrimarySite LIKE '_z' OR Mode='ECG' OR Mode='CED'" -score "HeartRate()" -display "TiledStack()" -output "Export(outAttr=false,outWave=false,as=TXT,tableAsCols=false)"
//
// to see the summary HRV scores.
/////////////////////////////////////////////////////////////////
package standard;

import java.io.*;
import java.util.*;

import generalClasses.*;
import recordingClasses.Recording;
import seriesClasses.*;
import channelClasses.ChannelScript;
import static channelClasses.Channel.*;

/////////////////////////////////////////////////////////////////

/** Processes ECG data by the Pan-Tompkins algorithm, to generate 
 * and append HR and RR timeseries.  More about this algorithm can 
 * be found in {@link generalClasses.QRSpt}.   Time-domain plots are
 * useful for visually checking QRS detection for artifacts.
 * Frequency-domain plots are useful for visualizing the structure of
 * HR variability.
 * <p>This script is <b>not</b> required in order to obtain HRV scores.
 */
public class HRpt extends ChannelScript
{
    /** Recording instance to be operated on */
    Recording rec = null;
    /** Log of warnings generated during update */
    private ArrayList<String> warnings = null;
    /** This is used only for debugging purposes */
    private ByteArrayOutputStream ba = null;

    ////////////////////////////////////////////////////////////////////
    /** Initialize instance by setting its parameters to default values.
     */
    public HRpt(Recording rec) {
        this.rec = rec;
        warnings = new ArrayList<String>();
        ba = new ByteArrayOutputStream();
    } // HRpt


    ////////////////////////////////////////////////////////////////////
    /** Update recording data by performing channel-oriented operations.
     */
    public void update() {
        // DO standard processing of EEG channels
        float highpassCutoff = 0.5f;
        ArrayList<SeriesAnalog> subsetEEG = selectMode(rec, DataMode.EEG);
        filterHP(highpassCutoff, subsetEEG); // NB: this does not remove DC
        subtractTemporalMean(subsetEEG);
        updateMatchingSeries(rec, subsetEEG);

        // Find one and only ECG
        ArrayList<SeriesAnalog> subset = selectMode(rec, DataMode.ECG);
        if(subset.size()==0) {
            warnings.add("HRpt: unable to find any ECG channels");
            return;
        } else if(subset.size()>1) {
            String list = "";
            for(SeriesAnalog s: subset) list += s.getPrimaryLabel()+" ";
            warnings.add("HRpt: "+list+"all ECG; only one is allowed");
            return;
        }
        SeriesAnalog series = subset.get(0);

        SeriesAnalog hrSeries = QRSpt.getHRSeries(series, new PrintStream(ba));
        SeriesAnalog rrSeries = QRSpt.getRRSeries(series, null);
        // This converts the two extra series from DataMode=ECG to
        // something else (anything else) in order that the heart rate
        // scoring algorithm can still identify the read ECG channel
        hrSeries.setMode(DataMode.CED); // +ve up, yDelta=0.4
        rrSeries.setMode(DataMode.CED); // +ve up, yDelta=0.4

        // Update Recording object
        appendToCurrentSeries(rec, hrSeries);
        appendToCurrentSeries(rec, rrSeries); 

    } // update


    ////////////////////////////////////////////////////////////////////
    /** Dump summary of this class or object
     * @return String representation of this object
     */
    public String toString() {
        String s = "<<<"+this.getClass().toString()+">>>\n";
        s += ba.toString();
        for(String w: warnings)
            s += w+"\n";
        return s;
    } // toString
}

 


Validate HTML CSS Generated 2009-09-06T16:13:22+1000 Chris Rennie