% MATLAB script for processing a Challenge 2013 data set with a Challenge entry % Version 1.0 (13 February 2013) % % A script similar to this one will be used as part of the evaluation of % Challenge entries written in m-code. We have provided these scripts so % that Challenge participants can test their entries to verify that they % run properly in the environment that will be used to test them. % % This script supplies a complete set of records, one at a time, to an % entry, and collects its output for each record (a vector of QRS % annotations and an estimate of QT interval). % % If your entry is written in m-code, it must be in the form of a function % named physionet2013, with this signature: % [fetal_QRSAnn_est,QT_Interval]=physionet2013(tm,ecgs) % % See the sample entry at http://physionet.org/challenge/2013/physionet2013.m % for descriptions of the input and output variables. % % To use this script to obtain an unofficial score for your entry on set A: % 1. Download these files from http://www.physionet.org/challenge/2013/ and % save them in your MATLAB working directory: % genresults.m (this file) % set-a-text.zip % or % set-a-text.tar.gz (zip archive or tarball of set A CSV files) % % 2. Unzip set-a-text.zip (or unpack set-a.tar-text.gz), creating a % subdirectory within your working directory called 'set-a-text'. When % you have completed this step, the set-a-text directory should contain % the individual signal files files (*.csv) as well as the reference % annotation files (*.fqrs.txt). % % 3. Save a copy of your entry (which should be named physionet2013.m) in % your working directory. You can test this procedure using the sample % 'physionet2013.m' we have provided, or you can use your own version. % % 4. The next few lines are MATLAB code that clears any previously set % variables, and sets the name of the directory containing the input % data, the name for the annotation/QT output files, and the name of % the files containing the known QRS intervals (*.fqrs). Change them % if necessary. % % Note that if you run a test on a set more than once, this code will % overwrite your output files!! %Written by Ikaro Silva, 2013 clear all;close all;clc % Suffix for fetal QRS annotation files produced by your entry annotation_suffix='.fqrs_entry1'; % Suffix for reference fetal QRS annotation files supplied by PhysioNet annotation_answer_suffix='.fqrs.txt'; % set_name is the name of the working directory containing the input % CSV files. Your entry's output annotation files will be written into % this directory. When you unpacked set A, the reference annotation % files were also written in this working directory. The reference % annotation files will be inaccessible to your code while it is being % evaluated using set B or set C. The challenge is (in part) to produce % annotation files that are as similar to the hidden reference annotation % files as possible. set_name='set-b-text'; % (change this to use other datasets) rec_ext='.csv'; % (using the CSV dataset) %QT Interval file: example of how to set the suffix in order to generate % files for the QT interval (stored in the same location as the annotation % files). % NOTE that for this to work you will have to comment out or delete the % qt_suffix=''; line right below. qt_suffix='.qt_entry1'; %NOTE: set qt_suffix to empty (as below) if you do not wisth to compete in this event %this will stop the script from generating QT files int the same directory qt_suffix=''; %Set 'show' to true to display the waveforms and their annotations show=1; clr={'k-','k-','k-','k-','b-'}; %Used for plotting only fdel='/'; if(ispc) fdel='\'; end cur_dir=pwd; data_dir=[cur_dir fdel set_name fdel]; cd(data_dir) records=dir(['*' rec_ext]); cd(cur_dir) I=length(records); display(['Processing ' num2str(I) ' records ...']) % Each Challenge .csv file (record) contains ECG data for one patient, % in 5 columns (the timestamp and four abdominal_ecgs). During each % iteration of the loop below, the contents of a single record are % loaded into arrays named tm and abdominal_ecgs. Your physionet2013.m % then generates a set of annotations, fetal_QRSAnn_est, and an % estimated QT interval that will be stored in files with the same % record name but with suffixes defined by the values you have chosen % above for 'annotation_sufix' and 'qt_suffix'. The output files are all % kept in the same directory as the data (i.e., 'set-a-text' for set a). header={'tm','ecgs'}; for i=1:I record_id=records(i).name(1:end-4); fname=[data_dir record_id rec_ext]; fname_ann_out=[data_dir record_id annotation_suffix]; fname_qt_out=[data_dir record_id qt_suffix]; answers=[data_dir record_id annotation_answer_suffix]; fid_in=fopen(fname,'r'); if(fid_in == -1) error(['Could not open data file: ' fname]); else try %Read file header file_header=textscan(fid_in,'%s',2,'delimiter','\r\n'); %Find number of channel NCH=length(regexp(file_header{1}{2}, ','))+1; %Get data format_str=repmat('%f ',[1 NCH]); ecgs=textscan(fid_in,format_str,'delimiter',',',... 'TreatAsEmpty', {'-,', ',-,','-,'}); cd(cur_dir) fclose(fid_in); catch exception fclose(fid_in); rethrow(exception); end end %Convert time to milliseconds ecgs=cell2mat(ecgs); tm=ecgs(:,1)*1000; ecgs(:,1)=[]; % The contents of one input file are now ready to be given to your % physionet2013 function for analysis in the next line: %Get answers if the annotations are available QRSAnn=[]; %Get the answers for this record file [fetal_QRSAnn_est,QT_Interval]=physionet2013(tm,ecgs); %Save annotations and QT answers to file try csvwrite(fname_ann_out,fetal_QRSAnn_est); catch exception warning(['Could not write file in: ' fname_ann_out]) throw(exception) end if(~isempty(qt_suffix)) try csvwrite(fname_qt_out,QT_Interval); catch exception warning(['Could not write file in: ' fname_qt_out]) throw(exception) end end if(exist(answers,'file')) QRSAnn=dlmread(answers); if(~isempty(QRSAnn)) %%TODO: uncomment once you have PhysioNet's scoring function % score=score2013(fetal_QRSAnn_est,QRSAnn,QT_Interval,QTAnn); end end % If 'show' was set to true above, display results for individual records if(show) [N,M]=size(ecgs); figure for m=1:M sig=ecgs(:,m); if(nansum(sig)) sig=(sig-nanmean(sig))./(nanmax(sig)-nanmean(sig)); xlim([0,5000]); plot(sig + (m-1)*2,clr{m});hold on;grid on plot(fetal_QRSAnn_est,sig(fetal_QRSAnn_est)+(m-1)*2,... 'o','MarkerSize',7,'MarkerEdgeColor','r','LineWidth',2) if(~isempty(QRSAnn)) plot(QRSAnn,sig(QRSAnn)+(m-1)*2,'x','MarkerSize',7,... 'MarkerEdgeColor','g','LineWidth',2) lgd={'ECG','FQRS Estimate','FQRS Answer'}; else lgd={'ECG','FQRS Estimate'}; end end end title(['Record id: ' record_id]) xlabel('Time (ms)') legend(lgd) end if(~mod(i,5)) display(['Processed: ' num2str(i) ' records out of ' num2str(I)]) end end display(['Finished!!'])