function ecg2hr(stopt, hrdt) %ECG2HR(stopt, hrdt) % % stopt (300): stop execution after (stopt) seconds of input have passed % hrsf (20): heart rate sampling frequency; can be chosen arbitrarily % %Examples: % ecg2hr % ecg2hr(5) %parse first 5 seconds of data %From here on, a number in parenthesis will denote a time dependent number %These numbers would likely change with a Sampling Frequency [sf] < 1000 %or if this ECG program were used with, say, humans rather than mice % Tests on the input arguments [ecgfilename, cdfilename, rrfilename, hrfilename, ecgfilenameonly] = chooser('useold'); if (nargin==0) stopt = (300); end %if if (nargin<=1) hrsf = (20); end %if if (hrsf==0) error('Parameters hrsf, hbwt, and nswt cannot equal 0; check your parameters.'); end %if %used to convert between seconds and milliseconds TIMEBASIS = .001; INVTIMEBASIS = 1000; %used to define heartbeat boundaries in ms MINRRINTERVAL = (66); MAXRRINTERVAL = (500); %used to set up running averages of the given length AVGLENGTH = (20); SLOPERANGE = (2); RRAVGLENGTH = 5; %used for heartbeat and noise running averages HBTLENGTH = 5; LTTLENGTH = 5; NAVGLENGTH = 200; %constants/thresholds used to determine heartbeats HBTM = .3; HBTRTM = .8; NSM = 1.1; SDT = (20); %used to read and store the ecg t = (-inf); prevecg = 0; ecgread = 0; tims = 0; %used for basic calculations on the ecg avg = 0; avgdiv = 0; ema = 0; waveq = 1; %used to find the sampling frequency of the ecg t0 = 0; tcount = 0; edt = 0; edtims = 0; sf = 1000; %used to analyze the slope of the ecg avgslope = 0; curslope = 0; aaslope = 0; %used to analyze the change in slope of the ecg slopediff = 0; prevecg = 0; prevt = 0; dt = (.001); %used to define and utilize heartbeat threshold band phbt = 0; nhbt = 0; ptrtims = 0; lttcount = 0; pltttims = 0; %used to find rr intervals rt0 = 0; recentrt = 0; prevema = 0; ishb = 0; %used for rr calculations and output avgrrint = 0; i = 0; rrstate = -1; rrcount = 0; %used to analyze the rr intervals prevrr = 0; bestrt = 0; bestrr = 0; bestema = 0; pbema = 0; %used to find best hb match hbmatchdiff = 0; minhbmatchdiff = inf; %used to determine the amount of noise navg = 0; bestnavg = 0; aflag = 0; %file ids ecgfid = fopen(ecgfilename,'r'); cdfid = fopen(cdfilename,'w'); rrfid = fopen(rrfilename,'w'); hrfid = fopen(hrfilename,'w'); while (t < stopt & ~feof(ecgfid)) %input a line form the ecg file ecgline = fgetl(ecgfid); if (tcount == 0) if (isempty(ecgline)) while (isempty(ecgline)) ecgline = fgetl(ecgfid); end %while end %if if ~isempty(sscanf(ecgline,'%[# b-df-mo-zB-DF-MO-Z]')) error('Data from ECG input file is not valid. Please run Splice if appropriate.'); end %if end %if %read and analyze the ecg ecgline = sscanf(ecgline,'%f %f',[1 2]); prevt = t; prevecg = ecgread; t = ecgline(1) - t0; ecgread = ecgline(2); if (t <= prevt) error('ECG time column must increase continuously.'); end %if if (tcount >= 0) %start the process of figuring out the ECG sampling frequency if (tcount == 0) t0 = t; t = 0; prevt = 0; prevecg = ecgread; else dt = t - prevt; edt = edt + (dt - edt)/tcount; end %if tcount = tcount+1; end %if %figure out parameters used to determine heartbeats tims = (round(t*sf)/sf)*INVTIMEBASIS; prevema = ema; ema = ecgread - avg; if (ema > phbt*HBTRTM/HBTM) phbt = phbt + HBTM*ema/HBTLENGTH; ptrtims = tims; elseif (ema > 0) phbt = phbt*.999; end %if if (ema < nhbt*HBTRTM/HBTM) nhbt = nhbt + HBTM*ema/HBTLENGTH; ptrtims = tims; elseif (ema < 0) nhbt = nhbt*.999; end %if if (ema > phbt | ema < nhbt) lttcount = lttcount + 1; pltttims = tims; end %if fprintf(hrfid, '%10.3f %10.3f %10.3f %10.3f %10.3f %10.3f\n', t, phbt+avg, nhbt+avg, abs(ema)+.2, navg+.2, (ishb + aflag)*.1+.6); if (tims - pltttims > MAXRRINTERVAL & rrstate ~= -1) rrstate = -1; disp(sprintf('Analysis stopped at t=%g since the value at t=%g was too large.', t, ptrtims*TIMEBASIS)); rt0 = recentrt; end %if avgdiv = avgdiv + (AVGLENGTH-avgdiv)/AVGLENGTH; avg = avg + ema/avgdiv; curslope = (ecgread - prevecg)/dt; slopediff = curslope - avgslope; avgslope = avgslope + slopediff/SLOPERANGE; aaslope = aaslope + abs(slopediff)/(SLOPERANGE); navg = navg + (abs(ema) - navg)/NAVGLENGTH; temprrint = tims - recentrt; aflag = 0; %is this ecg value a heartbeat? ishb = (rrstate >= 0 | temprrint > MAXRRINTERVAL) & (lttcount); ishb = abs(slopediff) > SDT & temprrint > MINRRINTERVAL & (ishb); if (ishb) %a new possible heartbeat has been found if (rrstate == -1) %first heartbeat, need one more to calculate heart rate rrstate = 0; lttcount = 0; recentrt = tims; %should be tims-edtims, but possibly we don't know edtims yet elseif (rrstate == 0) %second heartbeat, now heart rate (and edtims) is known rrstate = 1; if (tcount >= 0) %calculate final sf, edt sf = round(.1/edt)*10; edt = 1/sf; edtims = INVTIMEBASIS/sf; %output sf fprintf(cdfid, '%5g\n', sf); fprintf(rrfid, '%5g\n', sf); tcount = -1; end %if %set rr variables bestrt = tims-edtims; recentrt = recentrt-edtims; %-edtims to account above discrepancy bestrr = temprrint; %+(1-1)*edtims to account for recentrt discrepancy avgrrint = bestrr; lttcount = 0; if (bestrr > MAXRRINTERVAL) rrstate = -1; disp(sprintf('Analysis stopped at t=%g since the next heartbeat was too far away.', recentrt*TIMEBASIS)); rt0 = tims; else %output this rr interval disp(sprintf('Heartbeat found at t=%g.', (recentrt-edtims)*TIMEBASIS)); rrcount = rrcount + 2; fprintf(rrfid, '%10g %10g\n', bestrt, bestrr); for i=(rt0:edtims:recentrt-edtims) fprintf(cdfid, '%11.3f %10.3f\n', i*TIMEBASIS, 0); end %for fprintf(cdfid, '%11.3f %10.3f\n', recentrt*TIMEBASIS, 1); for i=(recentrt+edtims:edtims:bestrt-edtims) fprintf(cdfid, '%11.3f %10.3f\n', i*TIMEBASIS, 0); end %for fprintf(cdfid, '%11.3f %10.3f\n', bestrt*TIMEBASIS, 1); prevrr = bestrr; recentrt = bestrt; end %if else %all other heartbeats execute these statements if (bestrr > MAXRRINTERVAL) rrstate = -1; disp(sprintf('Analysis stopped at t=%g since the next heartbeat was too far away.', recentrt*TIMEBASIS)); rt0 = tims; end %if if ((temprrint > avgrrint * 1.5) & rrstate > 0) % past likely RR interval boundary, so calculate heart rate if (abs(bestema)*NSM < bestnavg) %best heartbeat was not discernable rrstate = -1; disp(sprintf('Analysis stopped at t=%g since there was too much intra-beat noise.', (tims-edtims)*TIMEBASIS)); rt0 = recentrt; else %best heartbeat was discernable rrcount = rrcount + 1; if (rrstate < RRAVGLENGTH) rrstate = rrstate + 1; end %if avgrrint = avgrrint + (bestrr-avgrrint)/rrstate; %output rr interval fprintf(rrfid, '%10g %10g\n', bestrt, bestrr); for i=(recentrt+edtims:edtims:bestrt-edtims) fprintf(cdfid, '%11.3f %10.3f\n', i*TIMEBASIS, 0); end %for fprintf(cdfid, '%11.3f %10.3f\n', bestrt*TIMEBASIS, .8); %.5*bestema); prevrr = bestrr; recentrt = bestrt; pbema = bestema; %reset rr variables temprrint = tims - recentrt; bestema = 0; minhbmatchdiff = inf; waveq = 4; %waveq + .01*(lttcount-waveq)/LTTLENGTH; AVGLENGTH = avgrrint/waveq; lttcount = 0; end %if end %if if (prevema~=0 & temprrint > MINRRINTERVAL & rrstate > 0) %test heartbeat candidate to see if it's a good match hbmatchdiff = abs((abs(INVTIMEBASIS/(temprrint-edtims)-INVTIMEBASIS/prevrr)+10)/prevema)*... ((sign(prevema) ~= sign(pbema))+.1); if (hbmatchdiff <= minhbmatchdiff) minhbmatchdiff = hbmatchdiff; bestema = prevema; bestrt = tims-edtims; bestrr = temprrint-edtims; bestnavg = navg; end %if end %if end %if end %if end %while disp(sprintf('Finished at t=%g with %g heartbeats', t, rrcount)); fclose(ecgfid); fclose(cdfid); fclose(rrfid); %fprintf(hrfid, '%5g %10g\n', sf, hrsf); %hrt = 0:t %[rt rr] = textread(rrfilename, '%f %f', -1, 'headerlines', 1); %[ fclose(hrfid);