Skip to content

Commit 1d60ad6

Browse files
committed
hrv - wip
1 parent b903fb4 commit 1d60ad6

File tree

1 file changed

+100
-63
lines changed

1 file changed

+100
-63
lines changed

src/data_analysis/heart_rate_variability/exploring_heart_rate_variability.clj

Lines changed: 100 additions & 63 deletions
Original file line numberDiff line numberDiff line change
@@ -27,7 +27,7 @@
2727
[java-time.api :as jt]))
2828

2929

30-
;; # Exploring HRV
30+
;; # Exploring HRV - DRAFT 🛠
3131

3232
(ns data-analysis.heart-rate-variability.exploring-heart-rate-variability
3333
(:require [tech.v3.datatype :as dtype]
@@ -75,8 +75,7 @@
7575
(plotly/layer-bar {:=y :ppi})))
7676

7777

78-
79-
(def compute-spectrograms
78+
(def compute-measures
8079
(fn [ppi-ds {:keys [sampling-rate
8180
window-size-in-sec ]}]
8281
(let [spline (interp/interpolation
@@ -121,10 +120,9 @@
121120

122121

123122
(comment
124-
(compute-spectrograms my-ppi
125-
{:sampling-rate 10
126-
:window-size-in-sec 60}))
127-
123+
(compute-measures my-ppi
124+
{:sampling-rate 10
125+
:window-size-in-sec 60}))
128126

129127

130128
;; [An Overview of Heart Rate Variability Metrics and Norms](https://pmc.ncbi.nlm.nih.gov/articles/PMC5624990/)
@@ -145,63 +143,61 @@
145143
tcc/sum))))
146144

147145

148-
149-
(defn plot-with-power-spectrum [{:keys [sampling-rate
150-
resampled-ppi
151-
spectrograms]}]
146+
(defn plot-with-measures [{:keys [sampling-rate
147+
resampled-ppi
148+
spectrograms]}]
152149
(when spectrograms
153-
(kind/fragment
154-
(let [n (-> spectrograms first :magnitude count)
155-
Nyquist-freq (/ sampling-rate 2.0)
156-
freq-resolution (/ Nyquist-freq n)
157-
times (map (comp str :t) spectrograms)
158-
freqs (tcc/* (range n)
159-
freq-resolution)]
160-
[(-> resampled-ppi
161-
(plotly/base {:=height 300 :=width 700})
162-
(plotly/layer-bar (merge {:=x :t
163-
:=y :ppi}
164-
(when (:label resampled-ppi)
165-
{:=color :label
166-
:=color-type :nominal}))))
167-
(kind/plotly
168-
{:data [{:x times
169-
:y freqs
170-
:z (-> (mapv :magnitude spectrograms)
171-
(tensor/transpose [1 0]))
172-
:type :heatmap
173-
:showscale false}]
174-
:layout {:height 300
175-
:width 700
176-
:margin {:t 25}
177-
:xaxis {:title {:text "t"}}
178-
:yaxis {:title {:text "freq"}}}})
179-
(-> {:freq freqs
180-
:mean-power (-> spectrograms
181-
(->> (map :magnitude))
182-
tensor/->tensor
183-
(tensor/reduce-axis dfn/mean 0))}
184-
tc/dataset
185-
(plotly/base {:=height 300 :=width 700})
186-
(plotly/layer-bar {:=x :freq
187-
:=y :mean-power}))
188-
(-> {:t times
189-
:LF-to-HF (->> spectrograms
190-
(map (partial LF-to-HF freqs)))}
191-
tc/dataset
192-
(plotly/base {:=height 300 :=width 700})
193-
(plotly/layer-line {:=x :t
194-
:=y :LF-to-HF})
195-
plotly/plot
196-
(assoc-in [:layout :yaxis :range] [0 4])
197-
(assoc-in [:layout :yaxis :title] {:text "LF/HF"}))]))))
150+
(let [n (-> spectrograms first :magnitude count)
151+
Nyquist-freq (/ sampling-rate 2.0)
152+
freq-resolution (/ Nyquist-freq n)
153+
times (map (comp str :t) spectrograms)
154+
freqs (tcc/* (range n)
155+
freq-resolution)]
156+
{:resampled-ppi (-> resampled-ppi
157+
(plotly/base {:=height 300 :=width 700})
158+
(plotly/layer-bar (merge {:=x :t
159+
:=y :ppi}
160+
(when (:label resampled-ppi)
161+
{:=color :label
162+
:=color-type :nominal}))))
163+
:power-spectrum (kind/plotly
164+
{:data [{:x times
165+
:y freqs
166+
:z (-> (mapv :magnitude spectrograms)
167+
(tensor/transpose [1 0]))
168+
:type :heatmap
169+
:showscale false}]
170+
:layout {:height 300
171+
:width 700
172+
:margin {:t 25}
173+
:xaxis {:title {:text "t"}}
174+
:yaxis {:title {:text "freq"}}}})
175+
:mean-power-spectrum (-> {:freq freqs
176+
:mean-power (-> spectrograms
177+
(->> (map :magnitude))
178+
tensor/->tensor
179+
(tensor/reduce-axis dfn/mean 0))}
180+
tc/dataset
181+
(plotly/base {:=height 300 :=width 700})
182+
(plotly/layer-bar {:=x :freq
183+
:=y :mean-power}))
184+
:LF-to-HF-series (-> {:t times
185+
:LF-to-HF (->> spectrograms
186+
(map (partial LF-to-HF freqs)))}
187+
tc/dataset
188+
(plotly/base {:=height 300 :=width 700})
189+
(plotly/layer-line {:=x :t
190+
:=y :LF-to-HF})
191+
plotly/plot
192+
(assoc-in [:layout :yaxis :range] [0 4])
193+
(assoc-in [:layout :yaxis :title] {:text "LF/HF"}))})))
198194

199195

200196
(delay
201197
(-> my-ppi
202-
(compute-spectrograms {:sampling-rate 10
203-
:window-size-in-sec 60})
204-
plot-with-power-spectrum))
198+
(compute-measures {:sampling-rate 10
199+
:window-size-in-sec 60})
200+
plot-with-measures))
205201

206202

207203
;; ## Analysing ECG data
@@ -327,7 +323,6 @@
327323
(tcc/shift (:t %) 1)))
328324
(tc/drop-rows [0]))))
329325

330-
331326
;; ### Plotting the PPI
332327

333328
(delay
@@ -341,14 +336,14 @@
341336
(plotly/layer-bar {:=x :t
342337
:=y :ppi})))
343338

344-
;; ## Spectrograms again
339+
;; ### Measures again
345340

346341
(def WESAD-spectrograms
347342
(memoize
348343
(fn [{:keys [ppi-params spectrogram-params]}]
349344
(-> ppi-params
350345
extract-ppi
351-
(compute-spectrograms spectrogram-params)))))
346+
(compute-measures spectrogram-params)))))
352347

353348

354349
(delay
@@ -357,6 +352,48 @@
357352
:spectrogram-params {:sampling-rate 10
358353
:window-size-in-sec 120}}
359354
WESAD-spectrograms
360-
plot-with-power-spectrum))
355+
plot-with-measures))
356+
357+
;; ## A subject's journey
358+
359+
(def id->label
360+
[:transient, :baseline,
361+
:stress, :amusement, :meditation,
362+
:ignore :ignore :ignore])
361363

364+
(def label-intervals
365+
(memoize
366+
(fn [subject]
367+
(-> (labelled-dataset subject)
368+
:label
369+
(->> (partition-by identity)
370+
(map (fn [part]
371+
[(-> part first int id->label)
372+
(count part)])))
373+
tc/dataset
374+
(tc/rename-columns [:label :n])
375+
(tc/add-column :offset #(cons 0 (reductions + (:n %))))
376+
(tc/select-columns [:offset :n :label])))))
362377

378+
379+
(delay
380+
(label-intervals 5))
381+
382+
383+
(delay
384+
(let [subject 5]
385+
(-> (label-intervals subject)
386+
(tc/select-rows #(not= (:label %) :ignore))
387+
#_(tc/select-rows #(= (:label %) :meditation))
388+
(tc/rows :as-maps)
389+
(->> (map (fn [{:keys [offset n label]}]
390+
[label
391+
(try (-> {:ppi-params {:subject-id subject
392+
:row-interval [offset (+ offset n)]}
393+
:spectrogram-params {:sampling-rate 10
394+
:window-size-in-sec 120}}
395+
WESAD-spectrograms
396+
plot-with-measures
397+
;; :LF-to-HF-series
398+
)
399+
(catch Exception e 'unavailable))]))))))

0 commit comments

Comments
 (0)