mirror of https://github.com/espruino/BangleApps
parent
6c09713e90
commit
c213a1ab77
|
@ -1,7 +0,0 @@
|
||||||
Extract hrm raw signal data to CSV file
|
|
||||||
=======================================
|
|
||||||
|
|
||||||
Simple app that will run the heart rate monitor for a defined period of time you set at the start. The max time value is 60 minutes but you can increase this just by changing the value in the app's script code if you wanted to - be mindful that your log file can get large and there are storage limitations if you start trying to log beyond this max.
|
|
||||||
|
|
||||||
The hrm sensor is sampled @50Hz and this app does not do any processing on it, the array is written as-is. There is an example Python script that can process this signal, smooth it and also extract a myriad of heart rate variability metrics using the hrvanalysis library:
|
|
||||||
https://github.com/jabituyaben/BangleJS-HRM-Signal-Processing
|
|
|
@ -1 +0,0 @@
|
||||||
E.toArrayBuffer(atob("MDCEBAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAATP/8yAAAAAAAj//MxAAAAAAAAAAAAAC//////8gAAAC//////8gAAAAAAAAAAA/////////EAH////////zAAAAAAAAAA//////////8R//////////8AAAAAAAAD///yEAEv///////yEAEv//8wAAAAAAAv//MAAAAAL/////IAAAAf///yAAAAAAD//zAAAAAAAf///xAAAAH/////AAAAAAH//wAAAAAAAB//8QAAAB//////EAAAAAP/8gAAAAAAAAL/IAAAAf//8S//MAAAAAP/8QAAAAAAAAAiAAAAH///EB//MAAAAA//8AAAAAAQAAAAAAAB///xAA//8AAAAA//8AAAAALxAAAAAAAf//8QAA//8AAAAA//8QAAAC//EAAAAAH///EAAB//8AAAAAP/8gAAAf//8QAAAB///xAAAC//MAAAAAL/8wAAAB///xAAAf//8QAAAD//IAAAAAD//xAAAAH///EAH///EAAAAf//AAAAAAA//zAAAAAf//8R///xAAAAA//zAAAAAAAf//IAAAAB//////8QAAAAL//xAAAAAAAC//8QAAAAH/////EAAAAB//8gAAAAAAAA//8wAAAAAf///xAAAAAD//8AAAAAAAAAH//zAAAAAB//8QAAAAA///EAAAAAAAAAAv//IAAAAAH/EAAAAAL//yAAAAAAAAAAAD//8gAAAAARAAAAAC//8wAAAAAAAAAAAA///yAAAAAAAAAAAv//8AAAAAAAAAAAAAH///IAAAAAAAAAL///EAAAAAAAAAAAAAAf//8gAAAAAAAC///xAAAAAAAAAAAAAAAB///zAAAAAAA///8QAAAAAAAAAAAAAAAAH///MAAAAAP///EAAAAAAAAAAAAAAAAAAf//8wAAAD///xAAAAAAAAAAAAAAAAAAAAP//zEAA///MAAAAAAAAAAAAAAAAAAAAAA///8R///zAAAAAAAAAAAAAAAAAAAAAAAD//////8wAAAAAAAAAAAAAAAAAAAAAAAAL/////MAAAAAAAAAAAAAAAAAAAAAAAAAAv///yAAAAAAAAAAAAAAAAAAAAAAAAAAAC//8gAAAAAAAAAAAAAAAAAAAAAAAAAAAAH/EAAAAAAAAAAAAAAAAAAAAAAAAAAAAAARAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA=="))
|
|
|
@ -1,149 +0,0 @@
|
||||||
//ADVANCED SETTINGS
|
|
||||||
var lower_limit_BPM = 49;
|
|
||||||
var upper_limit_BPM = 140;
|
|
||||||
var deviation_threshold = 3;
|
|
||||||
|
|
||||||
var target_heartrate = 70;
|
|
||||||
var heartrate_set;
|
|
||||||
|
|
||||||
var currentBPM;
|
|
||||||
var lastBPM;
|
|
||||||
var firstBPM = true; // first reading since sensor turned on
|
|
||||||
var HR_samples = [];
|
|
||||||
var trigger_count = 0;
|
|
||||||
var file = require("Storage").open("steel_log.csv","a");
|
|
||||||
var launchtime;
|
|
||||||
var alarm_length;
|
|
||||||
|
|
||||||
function btn1Pressed() {
|
|
||||||
if(!heartrate_set){
|
|
||||||
target_heartrate++;
|
|
||||||
update_target_HR();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
function btn2Pressed() {
|
|
||||||
heartrate_set = true;
|
|
||||||
Bangle.setHRMPower(1);
|
|
||||||
launchtime = 0|getTime();
|
|
||||||
g.clear();
|
|
||||||
g.setFont("6x8",2);
|
|
||||||
g.drawString("tracking HR...", 120,120);
|
|
||||||
g.setFont("6x8",3);
|
|
||||||
}
|
|
||||||
|
|
||||||
function update_target_HR(){
|
|
||||||
|
|
||||||
g.clear();
|
|
||||||
g.setColor("#00ff7f");
|
|
||||||
g.setFont("6x8", 4);
|
|
||||||
g.setFontAlign(0,0); // center font
|
|
||||||
|
|
||||||
g.drawString(target_heartrate, 120,120);
|
|
||||||
g.setFont("6x8", 2);
|
|
||||||
g.setFontAlign(-1,-1);
|
|
||||||
g.drawString("-", 220, 200);
|
|
||||||
g.drawString("+", 220, 40);
|
|
||||||
g.drawString("GO", 210, 120);
|
|
||||||
|
|
||||||
g.setColor("#ffffff");
|
|
||||||
g.setFontAlign(0,0); // center font
|
|
||||||
g.drawString("target HR", 120,90);
|
|
||||||
|
|
||||||
g.setFont("6x8", 1);
|
|
||||||
g.drawString("if unsure, start with 7-10%\n less than waking average and\n adjust as required", 120,170);
|
|
||||||
|
|
||||||
g.setFont("6x8",3);
|
|
||||||
g.flip();
|
|
||||||
}
|
|
||||||
|
|
||||||
function btn3Pressed(){
|
|
||||||
if(!heartrate_set){
|
|
||||||
target_heartrate--;
|
|
||||||
update_target_HR();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
function alarm(){
|
|
||||||
if(alarm_length > 0){
|
|
||||||
//Bangle.beep(500,4000);
|
|
||||||
Bangle.buzz(500,1);
|
|
||||||
alarm_length--;
|
|
||||||
}
|
|
||||||
else{
|
|
||||||
clearInterval(alarm);
|
|
||||||
if(trigger_count > 1)
|
|
||||||
Bangle.setHRMPower(0);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
function average(nums) {
|
|
||||||
return nums.reduce((a, b) => (a + b)) / nums.length;
|
|
||||||
}
|
|
||||||
|
|
||||||
function getStandardDeviation (array) {
|
|
||||||
const n = array.length;
|
|
||||||
const mean = array.reduce((a, b) => a + b) / n;
|
|
||||||
return Math.sqrt(array.map(x => Math.pow(x - mean, 2)).reduce((a, b) => a + b) / n);
|
|
||||||
}
|
|
||||||
|
|
||||||
function checkHR() {
|
|
||||||
var bpm = currentBPM, isCurrent = true;
|
|
||||||
if (bpm===undefined) {
|
|
||||||
bpm = lastBPM;
|
|
||||||
isCurrent = false;
|
|
||||||
}
|
|
||||||
if (bpm===undefined || bpm < lower_limit_BPM || bpm > upper_limit_BPM)
|
|
||||||
bpm = "--";
|
|
||||||
if (bpm != "--"){
|
|
||||||
HR_samples.push(bpm);
|
|
||||||
// Terminal.println(bpm);
|
|
||||||
}
|
|
||||||
|
|
||||||
if(HR_samples.length == 5){
|
|
||||||
g.clear();
|
|
||||||
average_HR = average(HR_samples).toFixed(0);
|
|
||||||
stdev_HR = getStandardDeviation (HR_samples).toFixed(1);
|
|
||||||
|
|
||||||
g.drawString("HR: " + average_HR, 120,100);
|
|
||||||
g.drawString("STDEV: " + stdev_HR, 120,160);
|
|
||||||
HR_samples = [];
|
|
||||||
if(average_HR < target_heartrate && stdev_HR < deviation_threshold){
|
|
||||||
|
|
||||||
Bangle.setHRMPower(0);
|
|
||||||
alarm_length = 4;
|
|
||||||
setInterval(alarm, 2000);
|
|
||||||
|
|
||||||
trigger_count++;
|
|
||||||
var csv = [
|
|
||||||
0|getTime(),
|
|
||||||
launchtime,
|
|
||||||
average_HR,
|
|
||||||
stdev_HR
|
|
||||||
];
|
|
||||||
file.write(csv.join(",")+"\n");
|
|
||||||
|
|
||||||
heartrate_set = false;
|
|
||||||
update_target_HR();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
update_target_HR();
|
|
||||||
|
|
||||||
setWatch(btn1Pressed, BTN1, {repeat:true});
|
|
||||||
setWatch(btn2Pressed, BTN2, {repeat:true});
|
|
||||||
setWatch(btn3Pressed, BTN3, {repeat:true});
|
|
||||||
|
|
||||||
Bangle.on('HRM',function(hrm) {
|
|
||||||
|
|
||||||
if(trigger_count < 2){
|
|
||||||
if (firstBPM)
|
|
||||||
firstBPM=false; // ignore the first one as it's usually rubbish
|
|
||||||
else {
|
|
||||||
currentBPM = hrm.bpm;
|
|
||||||
lastBPM = currentBPM;
|
|
||||||
}
|
|
||||||
checkHR();
|
|
||||||
}
|
|
||||||
});
|
|
Binary file not shown.
Before Width: | Height: | Size: 1.4 KiB |
Loading…
Reference in New Issue