Relationships between HRV, sleep and physical activity in personal Oura ring data

I’ve just posted a new blogpost where I’m sharing five insights that I’ve gotten from (statistically) exploring relationships between my personal resting Heart Rate Variability (HRV), sleep and physical activity data as collected with my Oura ring over the past 501 days.

To summarize my main findings:

  1. Low sedentary time, as well as high moderate and high vigorous physical activity predicted low subsequent nocturnal HRV (9.4% explained variance). So apparently my HRV takes a hit either when I’m very active, or not active at all.
  2. My resting HRV changed rather dramatically (structurally doubled) over the course of a year or so after some drastic lifestyle changes. For me personally, anekdotally explaining the longer term trends that I witnessed in my data were quite eye-opening.
  3. My resting HRV can be partially predicted using the HRV data of the previous three days in a time series (ARIMA (3,1,1)) model. To me, this shows tracking resting HRV might be useful as a proxy for detecting early signs of a negative feedback loop or downwards spiral (which is consistent with one of the hypotheses that I’m testing in my current PhD trajectory).
  4. My nocturnal HRV has a weak correlation (1.7% explained variance) with my Total Sleep Time (TST), and sleep stages explain 48.2% of the variance in my nocturnal HRV. The latter is most likely the result of Oura ring probably using HRV to categorize the actual sleep stages, but I found it fun to explore nonetheless.
  5. Low sedentary time and high moderate-to-vigorous physical activity (MVPA) predicted higher TST, whereas low TST predicted higher sedentary time. So apparently I sleep better if I’m not sitting around too much and am a bit more active, and am very inactive on days after a short night’s sleep, which makes sense I guess.

You can read the full blog post here:

Feel free to share any suggestions or questions on the topic or just let me know if you’ve enjoyed the post!


I received a request to share the code that I used to do these analyses. A R notebook with all code and results can be downloaded here (5 MB). I added the link in the original article too.

I also added the code to a chart that didn’t make it into the article, but I’ll share here because it is interesting. It is more easy to understand what I’m about to post if you’re read the blog post btw.

What I did here is standardize my Total Sleep Time (TST) and Heart Rate Variability (HRV) values ((observation - mean) / sd) so that both TST and HRV are represented on the same scale, which is essentially the number of standard deviations from the mean. The chart below contains the charts for both TST and HRV.

What I found interesting is this; my TST and HRV seem to have moved together a bit throughout time during most of the measurement period, but seem to have decoupled somewhere late July, when I had a couple of very short nights but my HRV kept going up regardless. Around that time I had just gotten back from a holiday and was basically forced to stop cycling due to mechanical problems, after which my HRV went up a lot. I think this effect is mostly due to me not cycling any more (which I did ~3x pw before then), meaning one of the larger negative short-term effects on my HRV was gone. The decline in HRV after that may just be related to the decline in my VO2max over the past few weeks. I picked up running as an alternative to cycling (my bike is still at the shop because they are still waiting for the parts to be delivered due to supply chain issues related to COVID-19 unfortunately), but couldn’t immediately do as cardiovascularly-intense exercise as I did during cycling since my muscles and tendons needed to get used to running. Just thought it was interesting and wanted to share it.


Thank you! this is great! The time series analysis is especially useful. I’ll be studying your code carefully to see how to modify for other QS projects. Thanks!

1 Like

Hey @hermandevries,
thanks for sharing the code, that’s super useful (and also thanks for presenting your work last week during the self-research chat!).

I’ve taken the liberty to make your code work with the JupyterHub setup that Open Humans runs, which enables people to use existing QS data analyses based on the standardized data store that Open Humans offers. You can find that reproducible version of the notebook on our Notebook Exploratory, which hopefully is useful to @sprague and other’s.

Here are the steps to use that notebook:

  1. Import our Oura data into Open Humans (your data is stored securely & privately, with no one having access to it but you)
  2. Visit the notebook in the Exploratory
  3. Either select Open (this gives you a dashboard version of the notebook, all cells are being run but the code is hidden and only the output remains, launching this takes a while based on the amount of calculations @hermandevries’ work includes) or Edit & Run (this opens a regular Jupyter Notebook version, you can run and edit the code according to your preferences).

Have fun exploring!