linking to this other thread, I had setup a repo for testing algorithms on Bangle JS. We currently have algos for step counting but it would make sense to add HR as well.
I have some student working on HR from PPG on mobile phones, but, if time allows, would like also to contribute to BangleJS.
The first thing to do would be to collect raw PPG data, as it comes to the algorithm, with a reference HR from another, trusted, sensor.
Once we are happy with the HR, it would be also cool to see if we can extract other parameters, such as respiration rate, but that would probably come later...
thanks for the explanation, now it's more or less clear.
As for testing, I have created a repo for testing the algos of BangleJS. Currently it contains only the step counter, but we could happily add also the heart rate. The idea is to upload some test data with reference (maybe coming from another commercial sensor) and benchmark different algorithms.
I have some students developing an algorithm to detect HR from raw PPG. We are trying to make the algorithm somewhat hardware indipendent, so the outcome could be applicable to Bangle as well (if good enough!). But first I wanted to understand how the current implementation works.
I know you used to compute autocorrelation at some point, but the current algorithm seems more like a peak detector? As the code is not greatly commented, can anybody (Gordon?) explain a little what is the idea behind?
Thanks a lot,
I forget how little portable C is!
OK, I have renamed time_t to sc_time_t so it doesn't conflict with linux time_t. Try pulling.
Need some 1 hour logs for sleep, driving, working, sitting watching TV - all ZERO step logs.
Yes, but let's not forget collecting steps data under different circumstances (slow walk, fast walk, running, etc).
It would be nice if we could involve other users, just to confirm that there are no major differences across devices.
Hi @fanoush, I have followed your work closely in the past. I can see that this is a collaboration among the best experts in reverse engineering watches there are around 😀!
As far as I understand what you are saying, the driver is just an implementation of the I2C protocol, and you have reverse-engineered it. Quite an achievement without a datasheet.
As for the higher level library, the reason why you do not want to use it is because it's not open sourced?
In any case, the fact that it requires acceleration is an indication that it makes use of it to probably discard data that is corrupted by movement. We could probably record some raw signals, including acceleration and PPG and put them in a repository for benchmarking different versions of algorithms. We would also need a reference heart rate for that, which we can obtain from another device, like a Polar or similar. Then we could invite people to test their best algorithms in some sort of competition...
I am working on an HR detection algorithm with students, but using the PPG from a smartphone. As the problem is similar, I may try to include data from the BangleJS as well. I'll keep you informed.
sorry there were a few bugs, I should have fixed them now, please pull. I have also run some more benchmarks with your new data and tuned the movement detection stage a bit.
It would be useful to keep the same file names so that provenance of the logs can be tracked.
Yes, good idea! The only requirement is that the first characters correspond to what we consider the "ground truth".
The Accelerometer logs below are all ZERO steps and should be part of the controlled test data in my view.
Yes, if you are sure about the fact that you did not do any step.
These and similar logs must form at least 50% of the test data in any test harness.
The more data we have the better. Actually we should also include running and walking in different conditions, like on soft floor, hard floor, with and without shoes etc.
No algorithm is going to be perfect, some may be more precise when walking, others when not. In the end it depends on the use case: runners may prefer better accuracy when running, others may prefer better accuracy when walking etc.
As a general aim I think we should try to have something as good as an average fitness tracker.
Hello @Gordon , thanks for the reply.
I understand that it makes sense to try with a more ad-hoc peak detector, especially if you know that the hardware is always the same. Our algorithm can be optimised a lot, starting from removing the buffers, but we didn't have enough time for that. As for the heart rate, I would probably trust the proprietary blob better than anything else. With time, if we manage to get a reliable algorithm, we would ideally get rid of it.
Back to the competition idea: I have created a repository where we can test algorithms, see here.
I have already populated it with the data I have collected myself plus some of the data collected by @HughB. I have not included those files where the two measurements of steps are too different, because I don't trust either, and for those that I have included, I have computed the average between the two given step counts.
@HughB would you be able to send me a pull request with your algorithm? Please check the structure inside the dummy algo. If that doesn't fit with yours, I am happy to change it, just le me know (or submit an issue on Github).
With time, we can add more algorithms, or simply improve ours. It's going to be fun (at least for me😀).
I would like to keep this repository also for testing the algorithms for heart rate or sleep detection when we get to it, and I will probably share it with students if I manage to involve some.
one note about your "ringing": it is maybe because of the pass-band filter. Have you tried with a low pass instead? Or can you just remove the filter altogether?
It would be interesting to see what it looked like without the buffering and pipeline and was just sequential.
Yes, I asked students to do that but they didn't have enough time. I agree that the buffers are not needed.
The approach the Bangle currently takes is very similar
Peak detectors are somewhat similar. The main issue is adapting to a signal where amplitude can change quickly. There are also other approaches than peak detection, like analysis in frequency, wavelets, or even machine learning, but I don't think they are suitable for an embedded device like a smartwatch.
If you could build a framework around those test cases above then I think we would have what we need.
Yes, I'll set it up and post the link here. I'll try to do it next week.
Hi, yes I was involved, I proposed the idea as a BsC project and I supervised students both at Oxford and at Malmo who worked on that.
The approach is described in two papers: here (behind paywall) and here. The basic idea is that the signal is converted to magnitude, then peaks are somewhat amplified, identified and selected.
You can split the algorithm into a pipeline of stages, with buffers between each stage. Not all stages are mandatory, for example I observed that interpolation and linear filtering do not bring any significative improvement and can be skipped.
As far as I remember, Gordon embedded the algorithm into the Espruino firmware at some point, but he complained about the fact that it took too much memory. After that I spent some time trying to remove redundancies and optimising memory a little bit, but I don't know if Gordon included those changes or if he decided to adopt another approach in the end.
Re. non-walking activities: the algorithm was meant to be used during walk and was not optimised to distinguish between genuine walk and other activities. To address this, I later added a basic movement detection step which improved things a bit on my short tests, but I have never tested it "in the wild" for a long time.
As for the competition, we could separate the algorithm from the Espruino code, prepare the testing dataset and add some wrapping code that runs the algorithm and compares it with the reference. I have something similar already I used myself to test my algorithm: I would happily polish it a little and share it if there's interest.
Hi all, excited to see how things are progressing here. I was curious to know how much of the original windowed peak detection is left in the current implementation?
The last version of the Oxford step counter in C was optimised for Bangle actually, and I even added a detection stage to filter out non-movement based on a minimum amplitude. I collected some data myself, 17 files with manually counted reference, and the accuracy was >90%.
Gordon, maybe having some sort of competition would be indeed a good idea, but we need to set it up well, which means good data and a simple way to run the code. I could also propose it to students here at the Uni.
A bit unrelated, but we could do the same for heart rate.
Gordon this is absolutely fantastic!
As my application area is health and fitness, I wonder what can you tell us about the step counter and the heart rate sensor. Chips used? Does the accelerometer include its HW step counter or are you relying on the same algorithm used on Bangle 1? What about the heart rate sensor?
I am very excited about this project, thanks very much for working on it.
thank you all! you can follow the development at https://github.com/espruino/Espruino/issues/1846
I've found a surprising way top count steps implemented in JS: https://github.com/alexgibson/shake.js/
Some people did a validation study here: https://www.ncbi.nlm.nih.gov/pmc/articles/PMC6219786/
I have looked at the code and it's basically a threshold on the difference between two samples. I doubt this is generalisable. In fact, the authors of the paper had to manually calibrate the threshold on each phone and walking style.
I'll leave it here as a curiosity.
the time is meant to be in ms and it can be since the start of the system (the most common case) or since the start of the algorithm. If you don't have a clock, you can just feed a variable which you increment of +sampling_frequency each time, as you say yourself.
It should be OK to reduce the type it to 32 bits, but there is no check when the clock is reset.
Alternatively, you could just get rid of the timestamp altogether, but whenever time is used later in the algorithm, you need to assume that it has increased of a given period.
A followup on this: we have a C implementation of the algorithm, in case anyone wants to import it: https://github.com/Oxford-step-counter/C-Step-Counter
about step counting, if you want to take a lower level approach and embed it into the firmware, this is open source and validated: https://github.com/Oxford-step-counter/C-Step-Counter
There are some constants that need to be optimised because they depend on the actual hardware you use and the sampling frequency (we used 50Hz, but probably 10Hz would do anyway). See the instructions in the README. If anyone here wants to try including this in the BangleJS firmware, I'll be happy to help.
our open source step counter has been ported to C and can be used in your project!
Here is the repo: https://github.com/Oxford-step-counter/C-Step-Counter
There are some constants that need to be optimised because they depend on the actual hardware you use and the sampling frequency (we used 50Hz, but probably 10Hz would do anyway). See the instructions in the README. If anyone here wants to try including this in the BangleJS firmware, I'll be happy to help!
I've received my BangleJS a couple of days ago and I'm very happy about how easy it is to program. Unfortunately, for my applications, I would need a rather good accuracy for both steps and heart rate. Let's discuss step counting here.
I noticed that the accelerometer does not include embedded step counting and that steps are computed by the Espruino firmware (here?). The algorithm unfortunately is very inaccurate: it waaaaaay over estimates my activity.
Do you have plans in this regard? Maybe include an accelerometer with an embedded step counter in the next model (if any) ?
If it helps, we are working on a C implementation of this algorithm specifically for microcontrollers and wearables. I can tell you when it's ready so maybe you could include it in the next firmware.
Thanks for the answer!
So, as far as I understand it, the options for this case would be:
a) customise the boot app
b) build a widget
c) customise a clock app
I didn't realise the widget thing! So I understand that, once installed, a widget is auto-restarted, runs all the time, and will react to events and timers even if the watch is idle.
The pedometer widget is actually the perfect starting point for my case.
For developing a good algorithm we would need the following:
looks like we can get all of them with the apps we have?