背景
2023年11月にPolar Vantage V3というPolarのスマートウォッチを購入しました。こちらで取り出せる生データが非常に興味深かったので投稿します。
Polar Vantage V3とは
Polar Vantage V3の特徴は数え切れないぐらいありますが、今回は、「自律神経」というテーマのため、脈拍センサに絞って説明します。
高性能な脈拍センサー
脈拍は、背面から照射される緑色のLEDの反射波から算出されます。(参考:脈波センサ)
LEDの強度が弱いと、反射波の振幅が小さくなり、S/N比が小さくなります。
Vantage V3ではLEDの数が一般的なスマートウォッチと比べて多く、それによって、高精度に脈拍を測定できます。
(LEDがいっぱい!)
LEDの数が多いと消費電流もそれに応じて多くなりますが、このウォッチの電池持ちは非常に良いです。(1度の充電で1週間ぐらい持ちます。)電池持ちが良いということは、それだけ長時間装着できるので、データの欠損も少なくてすみます。
脈拍と自律神経
少し生体の話になりますが、脈拍から自律神経が推定できる仕組みを説明します。
脈拍数(心拍数)は、通常も一定に見えて、実は絶えず変化しています。
↓脈拍波形のイメージ。赤い点が「ドクン」と脈打つところだと思ってください。
↓一拍毎の脈拍の変動をプロットすると
このように脈拍数は、比較的短い周期の変動(赤い線、高周波成分の変動:High Frequency)と比較的長い周期の変動(青い線、低周波成分の変動:Low Frequency)で変化します。
高周波の変動は主に副交感神経の影響で、低周波の変動は交感神経と副交感神経の影響によって生じます。ですので、低周波の変動と高周波の変動を追うことができれば、自律神経(交感神経・副交換神経)の働きを見ることができます。
一般的なスマートウォッチの脈拍性能
一般的なスマートウォッチは、1分間あたり60bpmといったように単位時間あたりの平均脈拍数を取得できますが、1拍ごとの脈拍間隔を取得できる機器は見たことがありません。しかしながら、このPolar Vantage V3は、一拍一拍の脈拍間隔が取得できるのです。
Polar Vantage V3の生データのダウンロード方法
- Polarのアカウントを登録し、デバイスを装着してデータをためる
-
アカウントページから、Downloadボタンを押す。※最初のアクセス時は、Downloadボタンを押したあとデータ処理の時間がかかる。データ処理が終わったあとに、ダウンロードリンクがメールで送信される。
生データの中身
ダウンロードしたフォルダを見てみると、いろいろなファイルが存在します。この中の「ppi_samples~~.json」ファイルが、脈拍間隔が保存されているファイルになります。(ppiはpeak to peak intervalの略?と思います)
このjsonファイルの中身を見てみると、
[
{
"date": "2024-05-01",
"devicePpiSamplesList": [
{
"deviceId": "12345678",
"ppiSamples": [
{
"sampleDateTime": "2024-05-01T00:00:00.938",
"pulseLength": 674
},
{
"sampleDateTime": "2024-05-01T00:00:01.612",
"pulseLength": 707
},
{
"sampleDateTime": "2024-05-01T00:00:02.319",
"pulseLength": 721
},
{
"sampleDateTime": "2024-05-01T00:00:03.040",
"pulseLength": 704
},
....
となっており、デバイスごとのppiが出力されています。
pythonで心拍変動を可視化
ファイルをデータフレームへ
jsonファイルをpythonで読み取り、心拍変動を可視化してみます。
import pandas as pd
import glob
import json
fs = glob.glob("ppi*.json")
dic_all = []
for f in fs:
print(f)
with open(f) as json_open:
json_data = json.load(json_open)
#各jsonに日付ごとのデータが入っている
for j in json_data:
tdic = j["devicePpiSamplesList"][0]["ppiSamples"] #デバイスは一つしかないので
dic_all.append(tdic)
flat = [x for row in dic_all for x in row]
df = pd.DataFrame(flat)
df["sampleDateTime"] = pd.to_datetime(df["sampleDateTime"])
df["MeasDate"] = df["sampleDateTime"].apply(lambda x: f"{x.year}-{x.month}-{x.day}")
df = df.rename(columns={"pulseLength": "rri"})
df["hr"] = 60.0 / df["rri"] * 1000
df["MeasHour"] = df["sampleDateTime"].dt.hour
#重複データ除外
df = df.drop_duplicates(keep="first")
これで、df
にrriが入りました。※ppiとrriは同じ脈拍間隔を指します。
可視化
試しに、私の脈拍のデータを見てみます。横軸が時間、縦軸が脈拍数です。
0:00~6:00は、おそらく睡眠しているので、脈拍の変動は比較的小さいですが、6:00~24:00はかなり暴れています。
もう少し、移動平均を取って見やすくしてみましょう。
だいぶ見やすくなりましたね。
これを見ると、睡眠中は、徐々に脈拍数が下がり、起床後脈拍数が上がります。また、12:00~13:00も脈数が上がっています。(おそらく、昼食の影響ですね)
※ちなみ、飲み会があったときのデータ↓
このときは、確か19:00〜飲み会があって、24:00ぐらいに解散したのですが、
飲酒のせいか、その期間ずっと脈拍数が上がっています。これを見ると、二日酔いしない程度の自分の適切な飲酒量がわかりそう・・・。
このように、脈拍数だけでもかなり自分の状態がわかります。
次回はもっと詳細に自律神経の評価をしていきたいと思います。