From b06aa603216a346fb9194a2db267f6fe9900dc3b Mon Sep 17 00:00:00 2001 From: Ben Jabituya <74158243+jabituyaben@users.noreply.github.com> Date: Mon, 21 Dec 2020 10:48:30 +0000 Subject: [PATCH 01/14] Create HRV.js --- apps/HRV/HRV.js | 205 ++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 205 insertions(+) create mode 100644 apps/HRV/HRV.js diff --git a/apps/HRV/HRV.js b/apps/HRV/HRV.js new file mode 100644 index 000000000..98f577293 --- /dev/null +++ b/apps/HRV/HRV.js @@ -0,0 +1,205 @@ +var file = require("Storage").open("HR_log.csv", "w"); +file.write(""); //reset log + +file = require("Storage").open("HR_log.csv", "a"); + +//debugging or analysis files +var cutoff_file = require("Storage").open("cuttoff.csv", "w"); +var peaks_file = require("Storage").open("peaks.csv", "w"); +var debugging = true; + +var first_signals = 0; // ignore the first several signals +var heartrate = []; +var BPM_array = []; +var raw_HR_array = new Float32Array(1024); +var alternate_array = new Float32Array(3072); +var pulse_array = []; +var pulsecount = 0; +var cutoff_threshold = 0.5; +var sample_frequency = 51.6; +var gap_threshold = 0.15; +var hr_min = 40; +var hr_max = 160; + +g.setFontAlign(0, 0); // center font +g.setFont("6x8", 2); + +function storeMyData(data, file_type) { + log = raw_HR_array; + // shift elements backwards - note the 4, because a Float32 is 4 bytes + log.set(new Float32Array(log.buffer, 4 /*bytes*/)); + // add ad final element + log[log.length - 1] = data; +} + +function average(samples) { + var sum = 0; + for (var i = 0; i < samples.length; i++) { + sum += parseFloat(samples[i]); + } + var avg = sum / samples.length; + return avg; +} + +function StandardDeviation(data) { + var m = average(data); + return Math.sqrt(data.reduce(function (sq, n) { + return sq + Math.pow(n - m, 2); + }, 0) / (data.length - 1)); +} + +function turn_off() { + Bangle.setHRMPower(0); + + g.clear(); + g.drawString("processing 1/5", 120, 120); + + rolling_average(raw_HR_array,5); + g.clear(); + g.drawString("processing 2/5", 120, 120); + + upscale(); + g.clear(); + g.drawString("processing 3/5", 120, 120); + + rolling_average(alternate_array,5); + g.clear(); + g.drawString("processing 4/5", 120, 120); + + apply_cutoff(); + if(debugging) + for (let i = 0; i < 256; i++) { + cutoff_file.write(alternate_array[i] + "," + "\n"); + } + + find_peaks(); + if(debugging) + for (let i = 0; i < pulse_array.length; i++) { + peaks_file.write(pulse_array[i] + "," + "\n"); + } + g.clear(); + g.drawString("processing 5/5", 120, 120); + + calculate_HRV(); +} + +function bernstein(A, B, C, D, E, t) { + s = 1 - t; + x = (A * Math.pow(s, 4)) + (B * 4 * Math.pow(s, 3) * t) + (C * 6 * s * s * t * t) + + (D * 4 * s * Math.pow(t, 3)) + (E * Math.pow(t, 4)); + return x; +} + +function upscale() { + var index = 0; + for (let i = raw_HR_array.length - 1; i > 5; i -= 5) { + p0 = raw_HR_array[i]; + p1 = raw_HR_array[i - 1]; + p2 = raw_HR_array[i - 2]; + p3 = raw_HR_array[i - 3]; + p4 = raw_HR_array[i - 4]; + for (let T = 0; T < 100; T += 10) { + x = T / 100; + D = bernstein(p0, p1, p2, p3, p4, x); + alternate_array[index] = D; + index++; + } + } +} + +function rolling_average(values, count) { + temp_array = []; + + for (let i = 0; i < values.length; i++) { + temp_array = []; + for (let x = 0; x < count; x++) + temp_array.push(values[i + x]); + + values[i] = average(temp_array); + } +} + +function apply_cutoff() { + var x; + for (let i = 0; i < alternate_array.length; i++) { + x = alternate_array[i]; + if (x < cutoff_threshold) + x = cutoff_threshold; + alternate_array[i] = x; + } +} + +function find_peaks() { + var previous; + var previous_slope = 0; + var slope; + var gap_size = 0; + var temp_array = []; + + for (let i = 0; i < alternate_array.length; i++) { + if (previous == null) + previous = alternate_array[i]; + slope = alternate_array[i] - previous; + if (slope * previous_slope < 0) { + if (gap_size > 30) { + pulse_array.push(gap_size); + gap_size = 0; + } + } + else { + gap_size++; + } + previous_slope = slope; + previous = alternate_array[i]; + } +} + +function calculate_HRV() { + var gap_average = average(pulse_array); + var temp_array = []; + var gap_max = (1 + gap_threshold) * gap_average; + var gap_min = (1 - gap_threshold) * gap_average; + for (let i = 0; i < pulse_array.length; i++) { + if (pulse_array[i] > gap_min && pulse_array[i] < gap_max) + temp_array.push(pulse_array[i]); + } + gap_average = average(temp_array); + var calculatedHR = (sample_frequency*60)/(gap_average/2); + g.flip(); + g.clear(); + //var display_stdv = StandardDeviation(pulse_array).toFixed(1); + var HRV = (StandardDeviation(temp_array) * (1 / (sample_frequency * 2) * 1000)).toFixed(0); + g.drawString("HRV:" + HRV + "\nHR:" + calculatedHR.toFixed(0) + +"\nSample Count:" + temp_array.length, 120, 120); + Bangle.buzz(500,1); +} + +g.clear(); +g.drawString("preparing", 120, 120); + +Bangle.setHRMPower(1); + +Bangle.on('HRM', function (hrm) { + g.flip(); + if (first_signals < 5) { + g.clear(); + g.drawString("setting up...\nremain still " + first_signals * 20 + "%", 120, 120); + first_signals++; + } + else { + BPM_array = hrm.raw; + if(hrm.bpm > hr_min && hrm.bpm < hr_max) + heartrate.push(hrm.bpm); + if (pulsecount < 7) { + for (let i = 0; i < 256; i++) { + file.write(BPM_array[i]+","+"\n"); + storeMyData(BPM_array[i], 0); + } + g.clear(); + g.drawString("logging: " + ((pulsecount/6)*100).toFixed(0) + "%", 120, 120); + } + if(pulsecount == 6) + turn_off(); + pulsecount++; + } +}); From c1e7829c7abbf32f0f32e77c66e3f7b6ae453fd5 Mon Sep 17 00:00:00 2001 From: Ben Jabituya <74158243+jabituyaben@users.noreply.github.com> Date: Mon, 21 Dec 2020 11:00:37 +0000 Subject: [PATCH 02/14] Add files via upload --- apps/HRV/hrv.png | Bin 0 -> 749 bytes 1 file changed, 0 insertions(+), 0 deletions(-) create mode 100644 apps/HRV/hrv.png diff --git a/apps/HRV/hrv.png b/apps/HRV/hrv.png new file mode 100644 index 0000000000000000000000000000000000000000..7fdbce610555f4fb39ed1106c2b7e61e6a6c339b GIT binary patch literal 749 zcmVPx#1ZP1_K>z@;j|==^1poj532;bRa{vGi!~g&e!~vBn4jTXf00v@9M??Vs0RI60 zpuMM)0007TNkl@9@iHZ0c8tFs1 z;DQ?>iW|7pbhW3aoa)na?{&Pl9H^}AP>2u0n)uJd0QT1c_1)o0_*??$d1EMi) zAQp=$^Z8tv&1On88inXf*sX&sHXrA*a&`_DG1@1nT321|bCl^L!<{-AD0b@p4Dna+-|qQpH8O@#h=e-lFeofUK61~NX5WByj(69SuU5bg^}%cOT1q1 zhyMx1Q=vgf$G|-I@_0OCygBSs#ad0l7_QZq15I2`(_-64`Xb{pf`0+?2VmJ)wESE|pgI8BRpVtc3`Nm;$FEj|d zVDRJpeji3|(Ag~%3I-o9dTk#J2AbmWIO_RJp+P8%!H?4dbm*++ayf(NKM4&&X$*cm z6bfnILZ{Pt)=WMm`A#ev*??$d1EP@)h(h*ex`pyAW;CyO~_P f5RGg=EQ<0DVjKyPk>G_d00000NkvXXu0mjf48luD literal 0 HcmV?d00001 From bfcb3753d4231238291e4e4afecc8450147055eb Mon Sep 17 00:00:00 2001 From: Ben Jabituya <74158243+jabituyaben@users.noreply.github.com> Date: Mon, 21 Dec 2020 11:04:34 +0000 Subject: [PATCH 03/14] Create hrv-icon.js --- apps/HRV/hrv-icon.js | 1 + 1 file changed, 1 insertion(+) create mode 100644 apps/HRV/hrv-icon.js diff --git a/apps/HRV/hrv-icon.js b/apps/HRV/hrv-icon.js new file mode 100644 index 000000000..e8084a26e --- /dev/null +++ b/apps/HRV/hrv-icon.js @@ -0,0 +1 @@ +require("heatshrink").decompress(atob("mEwwkEIf4A/ACUf+IXV///C/4X/C+jOIC5sBBxAIHgcgFwgXPFAUQAohHOFAQRCAoQdCC5QoCCQQuKC4woCCYQuKC4ooC+UvDQi/NFAUggRKEC5guDAoIwCFxIXEFwaqHC5YoGj4uKC4woKI5cxCyDvHC/4X/C/4XqAB3xC4s/DCAXFh4XWGCBHGAH4A/ABg")) From c00328b3f25a1a5653cec67a16116bf8c7e02a2f Mon Sep 17 00:00:00 2001 From: Ben Jabituya <74158243+jabituyaben@users.noreply.github.com> Date: Mon, 21 Dec 2020 11:04:53 +0000 Subject: [PATCH 04/14] Delete hrv-icon.js --- apps/HRV/hrv-icon.js | 1 - 1 file changed, 1 deletion(-) delete mode 100644 apps/HRV/hrv-icon.js diff --git a/apps/HRV/hrv-icon.js b/apps/HRV/hrv-icon.js deleted file mode 100644 index e8084a26e..000000000 --- a/apps/HRV/hrv-icon.js +++ /dev/null @@ -1 +0,0 @@ -require("heatshrink").decompress(atob("mEwwkEIf4A/ACUf+IXV///C/4X/C+jOIC5sBBxAIHgcgFwgXPFAUQAohHOFAQRCAoQdCC5QoCCQQuKC4woCCYQuKC4ooC+UvDQi/NFAUggRKEC5guDAoIwCFxIXEFwaqHC5YoGj4uKC4woKI5cxCyDvHC/4X/C/4XqAB3xC4s/DCAXFh4XWGCBHGAH4A/ABg")) From 1d502425f9698f22b9531ad3a4ecfe8497117e54 Mon Sep 17 00:00:00 2001 From: Ben Jabituya <74158243+jabituyaben@users.noreply.github.com> Date: Mon, 21 Dec 2020 11:05:13 +0000 Subject: [PATCH 05/14] Create HRV-icon.js --- apps/HRV/HRV-icon.js | 1 + 1 file changed, 1 insertion(+) create mode 100644 apps/HRV/HRV-icon.js diff --git a/apps/HRV/HRV-icon.js b/apps/HRV/HRV-icon.js new file mode 100644 index 000000000..e8084a26e --- /dev/null +++ b/apps/HRV/HRV-icon.js @@ -0,0 +1 @@ +require("heatshrink").decompress(atob("mEwwkEIf4A/ACUf+IXV///C/4X/C+jOIC5sBBxAIHgcgFwgXPFAUQAohHOFAQRCAoQdCC5QoCCQQuKC4woCCYQuKC4ooC+UvDQi/NFAUggRKEC5guDAoIwCFxIXEFwaqHC5YoGj4uKC4woKI5cxCyDvHC/4X/C/4XqAB3xC4s/DCAXFh4XWGCBHGAH4A/ABg")) From 91367d9139a38f70a33347b6fbaced8bbd2ac5a5 Mon Sep 17 00:00:00 2001 From: Ben Jabituya <74158243+jabituyaben@users.noreply.github.com> Date: Mon, 21 Dec 2020 11:14:36 +0000 Subject: [PATCH 06/14] Update apps.json --- apps.json | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/apps.json b/apps.json index 0dd96d3fe..dd57aed54 100644 --- a/apps.json +++ b/apps.json @@ -2480,3 +2480,17 @@ ] } ] +}, +{ "id": "HRV", + "name": "HRV monitor app", + "shortName":"HRV monitor", + "icon": "HRV-icon.png", + "version":"0.01", + "description": "Heart Rate Variability app", + "tags": "", + "storage": [ + {"name":"HRV.app.js","url":"HRV.js"}, + {"name":"HRV.img","url":"HRV-icon.js","evaluate":true} + ] +} +] From 66705a135686696fc784fd69b36b2ca5525323ce Mon Sep 17 00:00:00 2001 From: Ben Jabituya <74158243+jabituyaben@users.noreply.github.com> Date: Mon, 21 Dec 2020 11:18:44 +0000 Subject: [PATCH 07/14] Update apps.json --- apps.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apps.json b/apps.json index dd57aed54..00a8e4ecf 100644 --- a/apps.json +++ b/apps.json @@ -2484,7 +2484,7 @@ { "id": "HRV", "name": "HRV monitor app", "shortName":"HRV monitor", - "icon": "HRV-icon.png", + "icon": "hrv.png", "version":"0.01", "description": "Heart Rate Variability app", "tags": "", From acdb25602002e4068c3a58c1557fa8a18833029b Mon Sep 17 00:00:00 2001 From: Ben Jabituya <74158243+jabituyaben@users.noreply.github.com> Date: Mon, 21 Dec 2020 11:21:59 +0000 Subject: [PATCH 08/14] Update apps.json --- apps.json | 2 -- 1 file changed, 2 deletions(-) diff --git a/apps.json b/apps.json index 00a8e4ecf..a975cdcb0 100644 --- a/apps.json +++ b/apps.json @@ -2478,8 +2478,6 @@ {"name":"gmeter.app.js","url":"app.js"}, {"name":"gmeter.img","url":"app-icon.js","evaluate":true} ] -} -] }, { "id": "HRV", "name": "HRV monitor app", From 04a806bd3a305146f5dc4c0a57fe7f3b6bb0edd6 Mon Sep 17 00:00:00 2001 From: Ben Jabituya <74158243+jabituyaben@users.noreply.github.com> Date: Mon, 21 Dec 2020 11:25:39 +0000 Subject: [PATCH 09/14] Rename HRV.js to app.js --- apps/HRV/{HRV.js => app.js} | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename apps/HRV/{HRV.js => app.js} (100%) diff --git a/apps/HRV/HRV.js b/apps/HRV/app.js similarity index 100% rename from apps/HRV/HRV.js rename to apps/HRV/app.js From 8dfa1158541cf7614845cc8bf94f21025fe30a4f Mon Sep 17 00:00:00 2001 From: Ben Jabituya <74158243+jabituyaben@users.noreply.github.com> Date: Mon, 21 Dec 2020 11:26:48 +0000 Subject: [PATCH 10/14] Rename HRV-icon.js to app-icon.js --- apps/HRV/{HRV-icon.js => app-icon.js} | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename apps/HRV/{HRV-icon.js => app-icon.js} (100%) diff --git a/apps/HRV/HRV-icon.js b/apps/HRV/app-icon.js similarity index 100% rename from apps/HRV/HRV-icon.js rename to apps/HRV/app-icon.js From 6836fd88a138dc0d5cf12c3bb14f3177b81967be Mon Sep 17 00:00:00 2001 From: Ben Jabituya <74158243+jabituyaben@users.noreply.github.com> Date: Mon, 21 Dec 2020 11:27:53 +0000 Subject: [PATCH 11/14] Update apps.json --- apps.json | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/apps.json b/apps.json index a975cdcb0..1bb88f882 100644 --- a/apps.json +++ b/apps.json @@ -2487,8 +2487,8 @@ "description": "Heart Rate Variability app", "tags": "", "storage": [ - {"name":"HRV.app.js","url":"HRV.js"}, - {"name":"HRV.img","url":"HRV-icon.js","evaluate":true} + {"name":"HRV.app.js","url":"app.js"}, + {"name":"HRV.img","url":"app-icon.js","evaluate":true} ] } ] From 56c77daeb0c67e7337267d006bb851869f0e6fb9 Mon Sep 17 00:00:00 2001 From: Ben Jabituya <74158243+jabituyaben@users.noreply.github.com> Date: Mon, 21 Dec 2020 11:31:29 +0000 Subject: [PATCH 12/14] Update apps.json --- apps.json | 12 ------------ 1 file changed, 12 deletions(-) diff --git a/apps.json b/apps.json index 1bb88f882..0dd96d3fe 100644 --- a/apps.json +++ b/apps.json @@ -2478,17 +2478,5 @@ {"name":"gmeter.app.js","url":"app.js"}, {"name":"gmeter.img","url":"app-icon.js","evaluate":true} ] -}, -{ "id": "HRV", - "name": "HRV monitor app", - "shortName":"HRV monitor", - "icon": "hrv.png", - "version":"0.01", - "description": "Heart Rate Variability app", - "tags": "", - "storage": [ - {"name":"HRV.app.js","url":"app.js"}, - {"name":"HRV.img","url":"app-icon.js","evaluate":true} - ] } ] From 3ec2622b50d87fa10dc37583389369b63b43bd45 Mon Sep 17 00:00:00 2001 From: Ben Jabituya <74158243+jabituyaben@users.noreply.github.com> Date: Mon, 21 Dec 2020 11:34:54 +0000 Subject: [PATCH 13/14] Update apps.json --- apps.json | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/apps.json b/apps.json index 0dd96d3fe..f24027ec2 100644 --- a/apps.json +++ b/apps.json @@ -2466,6 +2466,18 @@ {"name":"mario_wh.img","url":"mario_wh.js","evaluate":true}, {"name":"pipe.img","url":"pipe.js","evaluate":true} ] + }, +{ "id": "HRV", + "name": "HRV monitor app", + "shortName":"HRV monitor", + "icon": "hrv.png", + "version":"0.01", + "description": "Heart Rate Variability app", + "tags": "", + "storage": [ + {"name":"HRV.app.js","url":"app.js"}, + {"name":"HRV.img","url":"app-icon.js","evaluate":true} + ] }, { "id": "gmeter", "name": "G-Meter", From d6b2127892fe8f8961f66eea531d93987a0dffef Mon Sep 17 00:00:00 2001 From: Ben Jabituya <74158243+jabituyaben@users.noreply.github.com> Date: Mon, 21 Dec 2020 11:37:37 +0000 Subject: [PATCH 14/14] Update apps.json --- apps.json | 24 ++++++++++++------------ 1 file changed, 12 insertions(+), 12 deletions(-) diff --git a/apps.json b/apps.json index f24027ec2..1bb88f882 100644 --- a/apps.json +++ b/apps.json @@ -2466,18 +2466,6 @@ {"name":"mario_wh.img","url":"mario_wh.js","evaluate":true}, {"name":"pipe.img","url":"pipe.js","evaluate":true} ] - }, -{ "id": "HRV", - "name": "HRV monitor app", - "shortName":"HRV monitor", - "icon": "hrv.png", - "version":"0.01", - "description": "Heart Rate Variability app", - "tags": "", - "storage": [ - {"name":"HRV.app.js","url":"app.js"}, - {"name":"HRV.img","url":"app-icon.js","evaluate":true} - ] }, { "id": "gmeter", "name": "G-Meter", @@ -2490,5 +2478,17 @@ {"name":"gmeter.app.js","url":"app.js"}, {"name":"gmeter.img","url":"app-icon.js","evaluate":true} ] +}, +{ "id": "HRV", + "name": "HRV monitor app", + "shortName":"HRV monitor", + "icon": "hrv.png", + "version":"0.01", + "description": "Heart Rate Variability app", + "tags": "", + "storage": [ + {"name":"HRV.app.js","url":"app.js"}, + {"name":"HRV.img","url":"app-icon.js","evaluate":true} + ] } ]