Diff of /HRV.src/get_hrv [000000] .. [1a3ddc]

Switch to unified view

a b/HRV.src/get_hrv
1
#! /bin/sh
2
3
# get_hrv       Joe Mietus      Apr 1 2011
4
5
# get_hrv       Joe Mietus      Nov 9 2010
6
7
8
USAGE="$0 [options] -R rrfile | record annotator [start [end]]
9
    Get HRV statistics :
10
      REC : NN/RR AVNN SDNN SDANN SDNNINDX RMSSD PNN : TOTPWR ULF VLF LF HF LF/HF
11
    options :
12
      [-R rrfile] : RR interval file : time (sec), interval
13
      [-f \"filt hwin\"] : filter outliers
14
      [-p \"nndiff ...\"] : nn difference for pnn (default: 50 msec)
15
      [-P \"lo1 hi1 lo2 hi2 lo3 hi3 lo4 hi4\"] : power bands
16
        (default : 0 0.0033 0.0033 0.04 0.04 0.15 0.15 0.4)
17
      [-s] : short term stats of
18
             REC : NN/RR AVNN SDNN RMSSD PNN : TOTPWR VLF LF HF LF/HF
19
      [-I c|h|m] : input time format: hh::mm:ss, hours, minutes (default: seconds)
20
          [-m] : RR intervals in msec
21
      [-M] : output statistics in msec rather than sec
22
      [-L] : output statistics on one line 
23
      [-S] : plot HRV results on screen
24
25
    plotting options :
26
      [-F \"filt hwin\"] : filter outliers, plot filtered data
27
      [-y \"ymin ymax\"] : time series y-axis limits (\"- -\" for self-scaling)
28
      [-X maxfreq] : fft maximum frequency (default : 0.4 Hz)
29
      [-Y fftmax] : fft maximum (\"-\" for self-scaling)
30
      [-o] : output plot in postscript
31
32
"
33
34
while getopts R:f:p:P:sI:mtMLSF:y:X:Y:o c
35
do
36
    case $c in
37
    R) RRFILE=$OPTARG ;;
38
    f) FILT=$OPTARG ;;
39
    p) PFLAG="-p $OPTARG" ;;
40
    P) PWRBANDS=$OPTARG ;;
41
        s) SFLAG='-s' ;;
42
        I) TIME=$OPTARG ;;
43
    m) MFLAG=1 ;;
44
    M) MSEC='-m' ;;
45
    L) SLINE=1 ;;
46
    S) SCREENPLOT=1 ;;
47
    F) FILT=$OPTARG
48
       PLTFILT=1 ;;
49
    y) Y0LIMS=$OPTARG
50
       if test `echo $Y0LIMS | wc -w` -ne 2
51
       then
52
               echo "$0 : [-y \"ymin ymax\"]"
53
               exit 1
54
       fi ;;
55
    X) X1MAX=$OPTARG ;;
56
    Y) Y1MAX=$OPTARG ;;
57
    o) SCREENPLOT=1
58
       PS=-ps ;;
59
    \?) echo "$USAGE"
60
            exit 1 ;;
61
    esac
62
done
63
64
shift `expr $OPTIND - 1`
65
66
if test "$RRFILE"
67
then
68
    if test ! -r "$RRFILE"
69
    then
70
    echo "$0 : Can't open $RRFILE"
71
    exit 1
72
    fi
73
74
    NFLAG=1
75
    REC=$1
76
    ANN=$2
77
fi
78
79
START=$1
80
END=$2
81
82
if test ! "$START" -o "$START" = "-"
83
then
84
    START=00:00:00
85
fi
86
STARTSEC=`seconds $START`
87
if test "$STARTSEC" -eq -1
88
then
89
    echo "$0 : bad start time : $START"
90
    exit 1
91
fi
92
START=`hours $STARTSEC`
93
94
if test "$END"
95
then 
96
    ENDSEC=`seconds $END`
97
    if test $STARTSEC -gt $ENDSEC
98
    then
99
    echo "$0: start time greater than end time"
100
    exit 1
101
    fi
102
fi
103
104
if test ! "$PWRBANDS"
105
then
106
    if test -n "$SFLAG"
107
    then
108
        LO1=0
109
        HI1=0.04
110
        LO2=0.04
111
        HI2=0.15
112
        LO3=0.15
113
        HI3=0.4
114
    else
115
        LO1=0
116
        HI1=0.0033
117
        LO2=0.0033
118
        HI2=0.04
119
        LO3=0.04
120
        HI3=0.15
121
        LO4=0.15
122
        HI4=0.4
123
    fi
124
    PWRBANDS="$LO1 $HI1 $LO2 $HI2 $LO3 $HI3 $LO4 $HI4"
125
elif test "$PWRBANDS" != 0
126
then
127
    if test `echo $PWRBANDS | wc -w | awk '{print $1%2}'` -ne 0
128
    then
129
    echo "$0 : [-P \"lo hi [...]\"]"
130
    exit 1
131
    fi
132
fi
133
134
FMAX=`echo $PWRBANDS | tr ' ' '\n' | sort -n | tail -1`
135
136
(
137
if test "$RRFILE"
138
then
139
    cat $RRFILE |
140
    (
141
    if test "$TFLAG"
142
    then awk '{T+=$1}; {printf "%.3f %s\n", T, $0}'
143
    else cat
144
    fi
145
    ) |
146
    (
147
    if test "$MFLAG" -a "$TFLAG"
148
    then awk '{$1/=1000; $2/=1000; print}'
149
    elif test "$MFLAG"
150
    then awk '{$2/=1000; print}'
151
    else cat
152
    fi
153
    ) |
154
    (
155
    if test "$TIME" = c
156
    then
157
        sed 's/[0-9:.][0-9:.]* /&: /' |
158
        awk -F: 'NF==2 {print $1, $2}
159
                 NF==3 {print $1*60+$2, $3}
160
                 NF==4 {print $1*3600+$2*60+$3, $4}'
161
    elif test "$TIME" = h
162
    then
163
        awk '{$1*=3600; print}'
164
    elif test "$TIME" = m
165
    then
166
        awk '{$1*=60; print}'
167
    else
168
        cat
169
    fi
170
    ) |
171
    (
172
    if test "$END"
173
    then
174
    awk "\$1>=$STARTSEC && \$1<=$ENDSEC && \$2!=0 {print}
175
         \$1>$ENDSEC {exit}"
176
    else
177
    awk "\$1>=$STARTSEC && \$2!=0 {print}"
178
    fi
179
    ) |
180
    (
181
    if test "$NFLAG"
182
    then
183
        awk '{print $1, $2, "N"}'
184
    else
185
        cat
186
    fi
187
    )
188
else
189
    rrlist $ANN $REC -f $START ${END:+-t} $END -s
190
fi
191
) >foo.rr
192
193
cat foo.rr |
194
(
195
if test "$FILT"
196
then
197
    filtnn $FILT -n 2>foo.nrr | sort -k 1n
198
else
199
    awk '{RR++}
200
         LAST=="N" && $3=="N" {NN++}
201
         {print; LAST=$3}
202
         END {printf "NN : RR = %d : %d = %f\n",  NN, RR, NN/RR >"foo.nrr"}'
203
fi
204
) |
205
(
206
if test "$MSEC"
207
then
208
    awk '{$2*=1000; print}'
209
else
210
    cat
211
fi
212
) |
213
awk 'NR==1 {T0=$1}
214
     {print $1-T0, $2, $3}' >foo.frr
215
216
217
cat foo.frr |
218
statnn $SFLAG $MSEC $PFLAG >foo.nnstat
219
NNSTATS=`cat foo.nnstat`
220
221
cat foo.frr |
222
awk 'LAST=="N" && $3=="N" {print $1, $2}; {LAST=$3}' |
223
tee foo.nn |
224
lomb - |
225
tee foo.fft |
226
awk "\$1<=$FMAX {print}" |
227
pwr $PWRBANDS |
228
sed 's/Total/TOT PWR/
229
     s/0 - 0.0033/ULF PWR/
230
     s/0.0033 - 0.04/VLF PWR/
231
     s/0 - 0.04/VLF PWR/
232
     s/0.04 - 0.15/LF PWR/
233
     s/0.15 - 0.4/HF PWR/' |
234
awk '{print}
235
     $1=="LF" {LF=$4}
236
     $1=="HF" {HF=$4}
237
     END {printf "LF/HF = %g\n", LF/HF}' >foo.pwr
238
NNPWRS=`cat foo.pwr | sed 's/  */ /'`
239
240
if test ! "$PS"
241
then
242
   (
243
    echo "${REC:-$RRFILE} :"
244
    cat foo.nnstat  | awk -F= '{printf "%-8s = %g\n", $1, $2}'
245
    cat foo.pwr | awk -F= '{printf "%-8s = %g\n", $1, $2}'
246
    ) |
247
    (
248
    if test "$SLINE"
249
    then
250
        sed '/TOT.*/i\
251
             :
252
             s/.*= //' |
253
             tr '\n' ' ' | awk '{print}' | sed 's/  */ /g'
254
    else
255
        cat
256
    fi
257
    ) 
258
fi
259
260
if test ! "$SCREENPLOT"
261
then
262
    rm -f foo.rr foo.frr foo.nn foo.nrr foo.nnstat foo.fft foo.pwr foo.ab
263
    exit
264
fi
265
266
##################################################################################
267
268
if test "$PS"
269
then
270
    PTERM=lw
271
    export PTERM
272
else
273
    xpltwin -g 720x940
274
fi
275
276
RATIO=`cat foo.nrr | 
277
       awk '{printf "Filt : NN : RR = %d : %d : %d = %.3f : %.3f = %.3f\n", \
278
                     $7, $9, $11, $13, $15, $17}'` 
279
EXCLUDED=`cat foo.nrr |
280
          awk 'NF==17 {printf "[%d Filtered, %d non-NN]\n", $9-$7, $11-$9}
281
               NF==9 {printf "[%d non-NN]\n", $7-$5}'`
282
 
283
PROG="NN interval"
284
if test "$FILT"
285
then PROG="$PROG, filt $FILT"
286
fi
287
PROG="$PROG, lomb"
288
289
TITLE="${RRFILE:-$REC $ANN} ($START)"
290
291
(
292
plt -wm 0 : -F"
293
t
294
L (P14) 0.5 0.99 CC $TITLE
295
L (P12) 0.5 0.96 CC ($PROG)
296
L (P12) 0.5 0.93 CC $RATIO $EXCLUDED
297
s f"
298
299
cat foo.rr |
300
(
301
if test "$FILT"
302
then
303
    filtnn $FILT -p | sort -k 1n
304
else
305
    cat
306
fi
307
) |
308
(
309
if test "$MSEC"
310
then
311
    awk '{$2*=1000; print}'
312
else
313
    cat
314
fi
315
) |
316
(
317
if test -z "$ZFLAG"
318
then
319
    awk 'NR==1 {T0=$1}
320
         {print $1-T0, $2, $3}'
321
else
322
    cat
323
fi
324
) >foo.frr
325
326
X0MIN=`head -1 foo.frr | awk '{print $1/60}'`
327
X0MAX=`tail -1 foo.frr | awk '{print $1/60}'`
328
if test `expr "$X0MAX" : '\(.*\)\..*'` -ge 120
329
then
330
    X0MAX=`echo $X0MAX | awk '{print $1/60}'`
331
    TUNIT=hr
332
else
333
    TUNIT=min
334
fi
335
336
if test "$MSEC"
337
then
338
    if test ! "$Y0LIMS"
339
    then
340
        Y0LIMS="0 2000"
341
    fi
342
    IUNIT="msec"
343
    PNN="%"
344
    PUNIT="msec2"
345
    cat foo.nnstat |
346
    sed "s/^[^p].*NN.*/& $IUNIT/
347
         s/rMSSD.*/& $IUNIT/
348
         s/pNN.*/& $PNN/" |
349
    awk 'NR==1 {printf "%s %s %.3f %s\n", $1, $2, $3, $4}
350
         NR>1 {printf "%s %s %.2f %s\n", $1, $2, $3, $4}' >foo.nnstat.hl
351
    cat foo.pwr |
352
    sed "s/.*PWR.*/& $PUNIT/" |
353
    awk 'NF==5 {printf "%s %s %s %.2f %s\n", $1, $2, $3, $4, $5}
354
         NF==3 {printf "%s %s %.4f\n", $1, $2, $3}' >foo.pwr.hl
355
else
356
    if test ! "$Y0LIMS"
357
    then
358
        Y0LIMS="0 2.0"
359
    fi
360
    IUNIT="sec"
361
    PNN=""
362
    PUNIT="sec2"
363
    cat foo.nnstat |
364
    sed "s/^[^p].*NN.*/& $IUNIT/
365
         s/rMSSD.*/& $IUNIT/
366
         s/pNN.*/& $PNN/" |
367
    awk 'NR==1 {printf "%s %s %.3f %s\n", $1, $2, $3, $4}
368
         NR>1 {printf "%s %s %.4f %s\n", $1, $2, $3, $4}' >foo.nnstat.hl
369
    cat foo.pwr |
370
    sed "s/.*PWR.*/& $PUNIT/" |
371
    awk 'NF==5 {printf "%s %s %s %.6f %s\n", $1, $2, $3, $4, $5}
372
         NF==3 {printf "%s %s %.4f\n", $1, $2, $3}' >foo.pwr.hl
373
fi
374
TLINES=`wc foo.nnstat.hl | awk '{print $1}'`
375
FLINES=`wc foo.pwr.hl | awk '{print $1}'`
376
377
Y0MIN=`expr "$Y0LIMS" : '\([^ ]*\)'`
378
Y0MAX=`expr "$Y0LIMS" : '.* \(.*\)'`
379
380
cat foo.frr |
381
(
382
if test "$PLTFILT"
383
then
384
    cat
385
else
386
    awk 'LAST=="N" && $3=="N" {print}; {LAST=$3}'
387
fi
388
) |
389
(
390
if test "$Y0MIN" = "-"
391
then
392
    if test "$Y0MAX" = "-"
393
    then
394
        awk "{\$1/=60; print}"
395
    else
396
        awk "{if(\$2>$Y0MAX) \$2=$Y0MAX;
397
              \$1/=60; print}"
398
    fi
399
else
400
    if test "$Y0MAX" = "-"
401
    then
402
        awk "{if(\$2<$Y0MIN) \$2=$Y0MIN; 
403
              \$1/=60; print}"
404
    else
405
        awk "{if(\$2<$Y0MIN) \$2=$Y0MIN; 
406
              if(\$2>$Y0MAX) \$2=$Y0MAX;
407
              \$1/=60; print}"
408
    fi
409
fi
410
) |
411
(
412
if test $TUNIT = hr
413
then
414
    awk '{$1/=60; print}'
415
else
416
    cat
417
fi
418
) >foo.frr1
419
mv foo.frr1 foo.frr
420
421
cat foo.frr |
422
plt 0 1 -wms 1 -F"
423
W 0.10 0.69 0.95 0.87
424
sf all P13
425
t
426
x Time ($TUNIT)
427
y NN Interval ($IUNIT)
428
xa $X0MIN $X0MAX
429
ya $Y0MIN $Y0MAX
430
s p
431
fa foo.axes"
432
433
cat foo.frr |
434
awk 'LAST=="N" && $3=="N" {print}
435
     {LAST=$3}' |
436
plt 0 1 -wms 1 -F"
437
sf all P13
438
f foo.axes"
439
440
if test "$PLTFILT"
441
then
442
    cat foo.frr | sed '/N/d' >foo.exc
443
444
    # plot non-normals
445
    cat foo.exc |
446
    sed '/X/d' |
447
    plt 0 1 -wms 1 -F"
448
    sf all P12
449
    lp 0.2 1.23 0
450
    le 0 0 
451
    L 0.19 1.14 LC Non-normal
452
    f foo.axes
453
    o
454
    p 0,1S0(P6)" 2>/dev/null
455
456
    # plot filtered beats
457
    cat foo.exc |
458
    sed -n '/X/p' |
459
    plt 0 1 -wms 1 -F"
460
    sf all P12
461
    lp 0.7 1.23 0
462
    le 0 0 
463
    L 0.69 1.14 LC Outliers
464
    f foo.axes
465
    o
466
    p 0,1S5(P6)" 2>/dev/null
467
468
    rm foo.exc
469
fi
470
471
# NN interval histogram
472
473
N=`wc foo.nn | awk '{print $1}'` 
474
cat foo.nn | awk '{print $2}' | sort | uniq -c |
475
awk "{print \$1/$N, \$2}" |
476
plt % -wms 1 -F"
477
W 0.1 0.38 0.4 0.57
478
sf all P13
479
t NN Interval Histogram
480
x NN interval ($IUNIT)
481
y Probability
482
p 1,0i"
483
484
# Power spectrum
485
486
if test ! "$X1MAX"
487
then
488
    X1MAX=$FMAX
489
elif test "$X1MAX" = "-"
490
then
491
    X1MAX=`sed -n '$p' foo.fft | awk '{print $1}'`
492
fi
493
494
if test ! "$Y1MAX"
495
then
496
    cat foo.fft | awk "\$1<=$X1MAX {SUM+=\$2*\$2; N++}
497
                       END {printf \"%.1g\n\", 20*SUM/N}" >foo.y1max
498
    Y1MAX=`cat foo.y1max`
499
    rm foo.y1max
500
elif test "$Y1MAX" = "-"
501
then
502
    cat foo.fft | awk "\$1<=$X1MAX {print \$2*\$2}" | max >foo.y1max
503
    Y1MAX=`cat foo.y1max`
504
    rm foo.y1max
505
fi
506
507
cat foo.fft |
508
awk '{print $1, $2*$2}' |
509
awk "\$1<=$X1MAX {if(\$2>$Y1MAX) \$2=$Y1MAX; print}" |
510
plt 0 1 -wms 1 -F"
511
W 0.6 0.38 0.9 0.57
512
sf all P13
513
t Lomb NN Interval Spectrum
514
x Frequency (Hz)
515
y Power ($PUNIT)
516
xa 0 $X1MAX
517
ya 0 $Y1MAX"
518
519
520
# HRV stats
521
plt : -wms 1 -F"
522
sf all P13
523
hl (P12) 0.075 -2.3 LC $TLINES
524
`cat foo.nnstat.hl`
525
hl (P12) 0.64 -2.3 LC $FLINES
526
`cat foo.pwr.hl`
527
f foo.axes"
528
529
) |
530
(
531
if test "$PTERM"
532
then cat | lwcat -full $PS
533
else cat
534
fi
535
)
536
537
rm -f foo.rr foo.frr foo.nn foo.nrr foo.nnstat foo.fft foo.pwr foo.ab
538
rm -f foo.axes foo.nnstat.hl foo.pwr.hl