-
-
Notifications
You must be signed in to change notification settings - Fork 1k
Refactored Ppg for frequency based algorithm. #1486
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Conversation
|
Complete refactoring the heart rate code. This has been tested against a predicate device and looks to be typically within +/-1bpm when heart rate is stable. This is my first pull request so I would appreciate any guidance on moving forward. |
|
There are files under the Apache License 2.0. Are they compatible with this project? Edit: seems like adding Apache 2.0 code to GPL code is compatible, but I am no lawyer. |
|
Since this PR contains a lot, any sort of documentation helps you to potentially get this through. For the start it think you should describe a little why you did what you did to get an overview of the different changes. The maintainers don't have much time so presenting your ideas and reasons well is very helpful. Then we could discuss if we like the changes and if they could maybe separated into smaller pull requests. Also please tell us what this PR improves. |
|
Thanks for taking a look at this!
According to Apache.org (first 2 paragraphs) we are good to use Apache V2.0 within GPLV3, just not the other way around: https://www.apache.org/licenses/GPL-compatibility.html
|
|
Ok, cool. Are you aware that your replies contain some email stuff? No offense, just wanted to tell you in case you didn't notice. |
|
If replying over email, it's better not to quote the previous message. I've also manually truncated it from people's comments so the thread would look nicer. |
This comment was marked as outdated.
This comment was marked as outdated.
|
Your description sounds good as far as I read it. More reliable heart rate data would be a very good thing! Can you restore the formatting that it seemed to have when you wrote it? ;) You can just edit the comment if that is possible for you. |
|
Motivation: Changes:
Improvements:
Cons:
Pull Request: Applied Algorithm (Ppg::HeartRate):
Execution time ~20ms Relevant feature requests: Increase the heart rate data logging interval Ring Buffer for Heart Rate Data Potential feature requests that can be addressed in future pull requests: Bug: Heart rate monitoring continues while charging Sleep tracking Heart rate measurement is stops, when the screen is turned off |
|
Reformatted pull request description. Not sure what the SOP is here, should I delete the old one and this comment as well? |
|
I don't think it is necessary to delete the comments. Thank you for posting it again! 😊 This will help a lot. |
|
I didn't quite have as much time to test this as I wanted too, so this will be brief (making the hrs better was something I never quite got to, so thanks!) it seems to have some issue - every about 10 seconds or so, it resets back to |
|
Thanks for testing it! I know the signal gets polluted with quite a lot of noise from movement, heaving breathing, fast heart rate, etc., basically anything that adds a lot of energy. I have also noticed that I have hard time getting a reading when it is cold out and there is a large temperature difference between the top of the watch and my wrist. Anyway, if it continues to be an issue the averaging buffer size can be increased to mitigate. I hope that you and others will have time to try it for a longer period. I've only tried it on a couple of other people, so really looking forward to the feedback. We might also want to think of different instructions to the user like, "Not enough data, please remain still..." or something like that. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
From simple testing this seems to work very well. The fact that it resets to zero when I'm moving around and presumably can't get a clean signal is giving me confidence that the reported values are more trustworthy, and the faster reporting of the heartrate is a much better experience.
Can you explain how you can get better results with less frequent data? Is more data just not necessary? Will the code work as well if the frequency was increased, or would it require tweaking?
How is the average power consumption compared to the previous code?
I made some comments on the code. The suggestions should be applied in all applicable places. Some of these suggestions are from clang-tidy.
Libs should be places in the libs directory. Can you add the libs in one commit, and make the changes in another, so we can keep track of the changes? Libs also should not be reformatted.
JF002
left a comment
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I tested this PR, and it looks very promising. See the following video (the sealed pinetime on the left is running InfiniTime 1.11, the wired devkit on the right is running this PR):
new-hr-algo-2.mp4
The value is updated more often, it detects very quickly that I removed my finger, and it doesn't sense any heart beat in the breadboard, which is nice! 👍
I do not have the equipment needed to check the accuracy of the measurements, though.
I think there are a few things that must be improved in the code, but I really hope we'll complete the review, validate the results and approve those changes :)
I fully agree with @Riksu9000's review :
- Document how this signal processing work and why it's better than the previous one (do not go into much details, but give a bit of info for those like me who do not know much about signal processing)
- Move the 3rd party libraries in the folder
libs.
I also added a few comments in my review. I know there are quite a few things to change, but they are mostly minor changes needed to conform with our coding standards :)
We must keep in mind memory usage : as I wrote in a comment : this implementation uses 4x time amount of RAM memory than before (from 200B to 1024+B). This seems to be fine as the compiler does not complain about overlapping regions, but we know that we are already quite tight in RAM memory.
|
Basic Algorithm How and Why How Why |
|
any news ? sometime it's restart measuring ... |
|
@lman0 , thanks for testing this! |
|
There are still unaddressed review comments and the PR needs to be cleaned up. Someone from the dev team may end up creating a new PR based on these changes, so we can get it merged soon. |
|
@lman0 |
|
@Ceimour can you check why the action crashed? |
|
The PR needs to be rebased and commits that fix mistakes squashed. The libs should be added in one commit, and modified in another, so we can see the changes made. |
|
Mark reviews as resolved when you've resolved them, please. |
|
@Ceimour Amazing job 🥇 , thank you! I've just checked the flash memory usage : these changes add a bit less than 2KB, which seems much more reasonable than before ! Regarding RAM usage, I couldn't find any dynamic allocation (which is nice), and the whole HeartRateTask class uses less than 1KB. It's probably more than the previous implementation, but these improvements are probably worth it. This PR looks good to me. I'll ask @Riksu9000 and @FintasticMan to check whether all their conversations (review) are now solved :) |
|
@JF002 Thanks! |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The last commit contains fixes for the first commit, which should be applied to the first commit to meet the commit requirements, however the entire commit should not necessarily be squashed. Ideally each commit would contain much fewer changes, because the descriptions are long.
|
Other than the points Riksu has raised, I have no issues with this code. |
93304e9 to
63b9233
Compare
Changed driver settings in HRS3300.cpp for better signal to noise at 10Hz. Changed measurementStarted delay to 100ms in HeartRateTask.cpp. Removed unused ppg methods from HeartRateTask.cpp. Added ambient light sensor acquisition and handling in HeartRateTask.cpp.
…polationLib. Hrs3300: Changed driver parameters to 50ms wait and 15bit ADC resolution. libs/Arduino-Interpolation: Removed library. libs/arduinoFFT: Removed library. libs/arduino-FFT-develop: Added this header only implementation to replace libs/arduinoFFT (removed). arduinoFFT-develop/src/arduinoFFT.h: Changed define for sqrt to sqrtf (saves ~3KB of flash). CMakeLists.txt: Updated with new library entries.
FintasticMan
left a comment
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This looks good to me! I've opened a PR to the FFT library that would allow us to specify the square root function to use without modifying the library: kosme/arduinoFFT#83. I don't think we should wait for that before merging this. We can update the library and put it in a git submodule in a later PR.
|
@Ceimour Thank you very much for your work and also for you patience and courage while we reviewed this PR! |
|
@JF002 Thanks! And thanks to everyone who tested and helped guide me through the process. You all made the code and implementation much better! |
|
I noticed the HR readings drops a lot to zero especially during motion. I was wondering if you have got the time to implement the adaptive filtering above? Otherwise, is changing some of the parameters such as peakDetectionThreshold, maxPeakWidth, and signalToNoiseThreshold would help? Thanks. |
|
@Anasdec Thanks for your interest in in improving this. Adaptive filtering unfortunately would require the use of the math libraries mentioned above (adds ~8KB). Not sure it would help that much since the fundamental issue is the poor signal quality from the sensor. I came to the conclusion that the ONLY use case for this current implementation is stationary, spot measurements. I still hold out hope that someone out there will find a way to get better signal to noise from the sensor. You may be able to get a better motion related experience by increasing the spectrum averaging and/or results averaging. The downside is more averaging, more lag in the reading. If you are really keen on playing with peak and signal metrics, I recommend using a dev unit wired to a debugger such that the watch heart rate sensor can be in contact with the wrist. Then make a small change and observe the effect. Iterate to get desired end result. Warning, it will take up a lot of your time! |
|
@Ceimour Thanks for coming back. I'm keen to look into this, but I don't have much experience. To increase the spectrum averaging as you suggest. Does that mean I need to do the following : Change: datalength from 64 to 128 and the Hanning Coefficients (via python - numpy.hanning(128) and only use the first 64 values)? and increasing dataAverage array from 20 to, say, 30? am I correct? |
|
@Anasdec To increase spectrum averaging adjust: To increase heart rate result history, adjust the array size as you mentioned above: Note that as the spectrum average is increased, the peak may spread out (peak width) as the heart rate varies. If you find that you are suddenly unable to get a result, the max peak width may need to be increased: Cheers! |

Changed driver settings in HRS3300.cpp for better signal to noise at 10Hz. Changed measurementStarted delay to 100ms in HeartRateTask.cpp. Removed unused ppg methods from HeartRateTask.cpp. Added ambient light sensor acquisition and handling in HeartRateTask.cpp. Added FFT and interpolation Ppg support code from Arduino FOSS implementations. Removed currently unused time domain based code.
Changed all doubles in PPG/Arduino code to float type so that FPU is used.