From 6c04fa35fb3726c6886af1f654a64ea156924e63 Mon Sep 17 00:00:00 2001 From: urme-b <148221893+urme-b@users.noreply.github.com> Date: Wed, 17 Jun 2026 05:59:41 +0600 Subject: [PATCH] hrv caveat --- Sensor's data/DATA_DICTIONARY.md | 2 +- analysis/explore_data.ipynb | 10 +++------- 2 files changed, 4 insertions(+), 8 deletions(-) diff --git a/Sensor's data/DATA_DICTIONARY.md b/Sensor's data/DATA_DICTIONARY.md index 0b9fd54..672ee6b 100644 --- a/Sensor's data/DATA_DICTIONARY.md +++ b/Sensor's data/DATA_DICTIONARY.md @@ -53,7 +53,7 @@ Continuous heart rate readings from chest-strap sensors, sampled at ~2 Hz per se ## ibi.csv -Beat-to-beat inter-beat intervals from the chest-strap sensors. These are the raw intervals between successive heartbeats, used to derive HRV metrics like RMSSD and SDNN. +Interval series from the heart-rate sensors. Note: these values are quantized and heavily forward-filled (most successive differences are exactly 0 ms), so they are **not** true beat-to-beat R-R intervals and are unsuitable for reliable time-domain HRV (RMSSD/SDNN). | Column | Type | Range | Description | |--------|------|-------|-------------| diff --git a/analysis/explore_data.ipynb b/analysis/explore_data.ipynb index e58cc3f..092d183 100644 --- a/analysis/explore_data.ipynb +++ b/analysis/explore_data.ipynb @@ -97,18 +97,14 @@ { "cell_type": "markdown", "metadata": {}, - "source": [ - "## 5. Inter-beat intervals and HRV\n", - "\n", - "IBI series from the sensor with the most data (sensor 5), plus RMSSD and SDNN computed over a sliding window. The anxiety threshold for both metrics is **< 50 ms**." - ] + "source": "IBI series from the sensor with the most data (sensor 5). Note: this `ibi.csv` series is quantized and forward-filled (most successive differences are exactly 0 ms), so it is **not** true beat-to-beat R-R data. The RMSSD/SDNN below are therefore artifactually low (median RMSSD ~3 ms) and should not be read as a real HRV or anxiety signal; shown for completeness only." }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], - "source": "# sensor 5 has most data\nibi_s5 = ibi[(ibi[\"iSensor\"] == 5) & (ibi[\"ibi\"] > 0)].copy().reset_index(drop=True)\n\nfig, axes = plt.subplots(2, 1, figsize=(12, 7), sharex=True)\n\naxes[0].plot(ibi_s5[\"reltime\"], ibi_s5[\"ibi\"], color=\"steelblue\", linewidth=0.6)\naxes[0].set_ylabel(\"IBI (ms)\")\naxes[0].set_title(\"Inter-beat intervals — Sensor 5\")\naxes[0].set_ylim(400, 1200)\n\n# sliding-window HRV (30-beat windows)\nw = 30\nsuccessive_diff = ibi_s5[\"ibi\"].diff()\nrmssd = np.sqrt((successive_diff ** 2).rolling(w, min_periods=w).mean())\nsdnn = ibi_s5[\"ibi\"].rolling(w, min_periods=w).std()\n\naxes[1].plot(ibi_s5[\"reltime\"], rmssd, label=\"RMSSD\", color=\"#e74c3c\", linewidth=1)\naxes[1].plot(ibi_s5[\"reltime\"], sdnn, label=\"SDNN\", color=\"#3498db\", linewidth=1)\naxes[1].axhline(50, color=\"gray\", linestyle=\"--\", linewidth=1, label=\"Anxiety threshold (50 ms)\")\naxes[1].set_xlabel(\"Time (seconds)\")\naxes[1].set_ylabel(\"HRV metric (ms)\")\naxes[1].set_title(f\"Sliding-window HRV ({w}-beat window)\")\naxes[1].legend()\naxes[1].set_ylim(0, 200)\n\nplt.tight_layout()\nplt.show()" + "source": "# sensor 5 has most data\nibi_s5 = ibi[(ibi[\"iSensor\"] == 5) & (ibi[\"ibi\"] > 0)].copy().reset_index(drop=True)\n\nfig, axes = plt.subplots(2, 1, figsize=(12, 7), sharex=True)\n\naxes[0].plot(ibi_s5[\"reltime\"], ibi_s5[\"ibi\"], color=\"steelblue\", linewidth=0.6)\naxes[0].set_ylabel(\"IBI (ms)\")\naxes[0].set_title(\"Inter-beat intervals — Sensor 5\")\naxes[0].set_ylim(400, 1200)\n\n# sliding-window HRV (30-beat windows)\nw = 30\nsuccessive_diff = ibi_s5[\"ibi\"].diff()\nrmssd = np.sqrt((successive_diff ** 2).rolling(w, min_periods=w).mean())\nsdnn = ibi_s5[\"ibi\"].rolling(w, min_periods=w).std()\n\naxes[1].plot(ibi_s5[\"reltime\"], rmssd, label=\"RMSSD\", color=\"#e74c3c\", linewidth=1)\naxes[1].plot(ibi_s5[\"reltime\"], sdnn, label=\"SDNN\", color=\"#3498db\", linewidth=1)\naxes[1].set_xlabel(\"Time (seconds)\")\naxes[1].set_ylabel(\"HRV metric (ms)\")\naxes[1].set_title(f\"Sliding-window HRV ({w}-beat window)\")\naxes[1].legend()\naxes[1].set_ylim(0, 200)\n\nplt.tight_layout()\nplt.show()" }, { "cell_type": "markdown", @@ -165,4 +161,4 @@ }, "nbformat": 4, "nbformat_minor": 4 -} \ No newline at end of file +}