자전거 퍼포먼스 × 카페인 × 시간대: 인과 분석 리포트
대상: Taeho Kim (iPhone + Apple Watch + Zwift) 분석 기간: 2025-12-20 ~ 2026-04-09 (111일) 분석 대상: 87건의 Zwift 실내 사이클링 세션 데이터 소스: Apple HealthKit via Health Data Bridge CLI (raw HR 52,826건 포함) 분석 일자: 2026-04-10 (v1 speed-based) · 2026-04-11 (v2 HR-intensity-based) 선행 리포트:
- report.md — 카페인과 수면
- caffeine-multidim.md — 카페인의 다각도 영향
⚠️ v2 UPDATE: 방법론 개선 (HR-based intensity)
v1 한계 (사용자 지적): v1은 avg speed와 kcal/min을 퍼포먼스 지표로 사용했는데, Zwift 실내에서도 가상 경사도에 따라 speed가 달라져 power의 엄밀한 proxy가 아닙니다.
Power 데이터의 한계: Zwift는 Apple Health에 파워(W)를 쓰지 않습니다. Strava도 2022년 3월부터 third-party 기기 파워 sync를 중단했습니다. HealthFit 앱 + FIT 파일 수동 import, 또는 RunGap + TrainingPeaks 유료 파이프라인을 통해서만 파워 데이터를 Apple Health에 넣을 수 있습니다. 이건 추후 과제.
v2 접근: Power 없이 52,826건 raw HR time-series로부터 5가지 power-analogous intensity 지표를 유도:
- Normalized HR (NHR) — Power의 NP 개념을 HR에 적용 (30-sec rolling avg의 4제곱 평균의 4제곱근)
- TRIMP (Banister 공식) — 총 training stress, 개인화된 HRR 기반
- HR time-in-zones (Z1-Z5) — 관측 Max HR 186 bpm 기반 (52,826 samples 중 반복 관측)
- HR drift — 첫 1/4 vs 마지막 1/4 평균 HR 변화율 (CV fitness 지표)
- HR CV — intra-session 변동 계수
- **HR reserve **% — (HR - RHR) / (MHR - RHR), 개인화된 intensity
또한 HR 시그니처 기반으로 세션 타입 자동 분류 (rule-based): recovery / endurance / tempo / threshold / interval. 이를 바탕으로 session-type-matched pairing 실행.
v2 결과: v1 결론 완전 확증 + 강화. 모든 새 intensity 지표에서 카페인 효과 zero. 29쌍 session-type-matched pairing에서 모든 p > 0.49 (TRIMP Δ=-0.21, NHR Δ=+0.50, HR drift Δ=+0.78%). TRIMP 회귀 R²=0.880이 Duration + session type + recovery/threshold 분류 + HRV로 거의 완벽히 설명되고 카페인 β=+0.021, p=0.693.
출발 질문
사용자 관찰: "아침엔 에스프레소 마시고 자전거 타고, 저녁엔 커피 부담스러워서 그냥 자전거만 타. 이 두 상태의 퍼포먼스 차이가 있을까? 있다면 그게 카페인 때문인가, 아침 > 저녁이라는 circadian 때문인가, 아니면 다른 요인인가?"
검증할 4가지 모델:
- (A) 카페인 에르고제닉 효과
- (B) Circadian rhythm (아침이 더 좋음)
- (C) 다른 교란 변수 (수면, 피로, selection bias)
- (D) 혼합
Executive Summary (v2)
| 가설 | 판정 | v2 근거 |
|---|---|---|
| (A) 카페인 에르고제닉 | ❌ 완전 기각 | 29쌍 session-type-matched: 모든 지표 p > 0.49 (TRIMP Δ=-0.21, NHR Δ=+0.50, HR drift Δ=+0.78) |
| (B) Circadian (아침>저녁) | ❌ Bimodal (아침=저녁) | 아침 08-10 ≈ 저녁 18-20 모두 peak. 저녁 threshold 16건 vs 아침 11건. |
| (C) 세션 종류 (duration + 타입) | ✅ 주요 원인 | TRIMP 회귀 R²=0.880. Duration β=+0.689, Threshold β=+0.491, Recovery β=-0.204 |
| (D) HRV 기반 자체 조절 | ✅ 보조 원인 | HRV 높은 날 recovery 선택 (+3.6ms), 낮은 날 threshold (-1.2ms) |
최종 결론 (v2): 당신의 자전거 퍼포먼스를 결정하는 것은 세션 종류(타입 × duration)와 HRV 기반 자체 조절이지 카페인이 아닙니다. v1에서는 speed/kcal-min 기반이라 "카페인의 시간 혼입" 가능성을 100% 배제하기 어려웠는데, v2에서 power-analogous HR intensity 지표(NHR, TRIMP, HR drift) 전부에서 같은 결론이 나오면서 카페인이 운동 중 물리적 출력에 영향을 주지 않는다가 확정됐습니다. 효과가 있다면 β=0.021로 측정 노이즈 수준.
1. 데이터
- Cycling workouts: 87건 (필터 적용 후) / 95건 (raw)
- 필터: duration ≥ 10min, distance ≥ 1km
- Source: Zwift (실내 트레이너) 100% — Strava 실외 0건이었음
- Heart rate: 52,826건 (워크아웃별 window에서 pull, 평균 556건/세션)
- Caffeine intakes: 302건 (타임스탬프 + mg)
- Sleep: 110 nightly sessions
- HRV/RHR: 일별 111일 (100% coverage)
성능 지표 정의 (3축)
| 축 | 지표 | 계산 |
|---|---|---|
| Output | Average speed (km/h) | distance / (duration/60) |
| Kcal/min | 파워 프록시 (Zwift 실내는 Speed와 r=0.80) | |
| Effort | Average HR | workout window 내 raw HR 평균 |
| Max HR | workout window 내 raw HR 최대 | |
| Efficiency | Speed/HR | 심박 대비 출력 |
| (kcal/min)/HR | 심박당 kcal 생산량 |
기술통계
| 지표 | 평균 | SD | 범위 |
|---|---|---|---|
| Duration | 42.7 min | ±16.8 | 15.3–97.6 |
| Distance | 21.4 km | ±8.8 | 3.5–54.8 |
| Avg speed | 30.1 km/h | ±5.1 | 13.6–37.8 |
| Kcal/min | 10.1 | ±2.4 | 3.5–14.2 |
| Avg HR | 138.5 bpm | ±17.3 | 91.2–165.0 |
| Max HR | 170.4 bpm | ±14.7 | 108.0–186.0 |
| Speed/HR | 0.218 | — | 0.13–0.28 |
| Start hour (KST) | 14.5 | ±3.7 | 08.5–21.4 |
2. 시간대 × 카페인 분포 (사용자 관찰 검증)
카페인 노출 매트릭스
| 시간대 | 카페인 ○ | 카페인 × | ○ 비율 |
|---|---|---|---|
| 아침 (06-11) | 17 | 1 | 94% |
| 오전 (11-13) | 14 | 5 | 74% |
| 오후 (13-17) | 13 | 8 | 62% |
| 저녁 (17-22) | 3 | 26 | 10% |
사용자 관찰 완전 확인: 저녁엔 사실상 카페인 없이 탑니다.
셀별 평균 속도 (Raw)
| 시간대 | 카페인 ○ | 카페인 × |
|---|---|---|
| 아침 (06-11) | 30.4 km/h (n=17) | 35.9 (n=1) |
| 오전 (11-13) | 30.5 (n=14) | 30.1 (n=5) |
| 오후 (13-17) | 26.5 (n=13) | 31.3 (n=8) |
| 저녁 (17-22) | 29.3 (n=3) | 30.9 (n=26) |
이상한 패턴: 오후엔 카페인 있을 때가 -4.7 km/h 느림 (Cohen's d = -0.91 large). 카페인이 성능을 떨어뜨리나? 이 의문이 다음 분석을 촉발.
3. Circadian Baseline — Bimodal 발견
시간대별 실제 평균 속도
08-10시 (n=10): 32.6 km/h ████████████████████ ← Peak 1
10-12시 (n=19): 30.4 km/h ████████
12-14시 (n=17): 27.6 km/h ███ ← Trough 1
14-16시 (n=10): 29.6 km/h ██████
16-18시 (n=10): 27.2 km/h ██ ← Trough 2
18-20시 (n=16): 32.6 km/h ████████████████████ ← Peak 2
20-22시 (n= 5): 30.5 km/h █████████
아침 08-10과 저녁 18-20이 똑같이 32.6 km/h로 쌍봉 peak. 한가운데 점심-오후가 가장 느림.
Circadian 모델링
Avg speed ~ hour + hour² 단순 이차 회귀:
- R² = 0.050 (adj R² = 0.027)
- β_hour = -2.97, p = 0.046
- β_hour² = +0.102, p = 0.042
- Vertex (vertex) ≈ 14:35 (하지만 실제 데이터는 쌍봉이라 2차 함수가 잘 맞지 않음)
결론: 사용자의 "아침 > 저녁" 전제는 틀렸습니다. 아침과 저녁은 동점이고, 오히려 점심-오후가 나쁨. 따라서 가설 (B)는 기각됨과 동시에 전제 자체가 잘못됨.
4. 카페인 효과 — 시간대 통제 후
Residual (잔차) 분석
시간대 효과를 ols로 빼낸 residual에 카페인이 어떤 설명력을 갖는가?
| 검정 | r | p |
|---|---|---|
| 속도 잔차 ↔ 잔류 카페인 | -0.063 | 0.560 |
| 속도 잔차 ↔ Pre-caf 2h (mg) | -0.030 | 0.785 |
| 효율 잔차 ↔ 잔류 카페인 | -0.067 | 0.537 |
| 효율 잔차 ↔ Pre-caf 2h (mg) | -0.105 | 0.333 |
모두 사실상 0. 시간대를 통제한 뒤에는 카페인이 설명하는 변동이 없음. 방향도 살짝 음의 부호.
다중회귀 — Avg speed
Avg speed ~ Residual caffeine + Hour + Hour² + Duration + Prev sleep + HRV + Recent vol
| 변수 | β (std) | p |
|---|---|---|
| Hour of day | -1.893 | 0.071 * |
| Hour² | +1.876 | 0.078 * |
| HRV | -0.312 | 0.004 ** |
| Residual caffeine | -0.156 | 0.247 |
| Prev sleep | -0.106 | 0.314 |
| Duration | +0.079 | 0.463 |
| Recent vol (3d) | +0.057 | 0.595 |
R² = 0.174, adj R² = 0.101.
핵심 관찰 1: 카페인은 p = 0.247로 유의하지 않음. 시간대 통제 후에는 카페인이 무관.
핵심 관찰 2: HRV가 유일한 강한 유의 변수 (p = 0.004), 하지만 방향이 음성 — "HRV 높을수록 속도 낮음". 역설적으로 보이지만 해석 가능 (섹션 6 참조).
다중회귀 — Avg HR
| 변수 | β (std) | p |
|---|---|---|
| Distance | +1.351 | <0.001 ** |
| Duration | -1.140 | <0.001 ** |
| HRV | -0.167 | 0.061 * |
| Prev sleep | -0.105 | 0.217 |
| Hour of day | -0.061 | 0.563 |
| Residual caffeine | +0.054 | 0.620 |
R² = 0.445.
카페인이 평균 심박을 올리지 않음 (β=+0.054, p=0.620). 자율신경 각성 가설과 배치. 운동 중에는 카페인의 HR 효과가 측정 불가능하거나 기저 운동 심박에 묻힘.
5. 왜 카페인 ○ 가 느린가? — Session Selection 가설
Duration 비교
| 그룹 | N | 평균 Duration | median | max |
|---|---|---|---|---|
| 카페인 ○ | 47 | 44.3 min | 40.1 | 98 |
| 카페인 × | 40 | 40.7 min | 39.0 | 69 |
카페인 그룹이 평균 3.6분 길게 탐. 최대값은 카페인 그룹만 60분 초과 세션 (98 vs 69 min).
오후 (13-17시) 세부
| 그룹 | N | Duration | Distance | Speed |
|---|---|---|---|---|
| 카페인 ○ | 13 | 55.6 ± 26.2 min | 24.4 km | 26.5 km/h |
| 카페인 × | 8 | 46.5 ± 15.9 min | 24.1 km | 31.3 km/h |
같은 거리(24km)를 카페인 있는 오후엔 9분 더 길게 탔습니다. 속도 차이의 전부가 duration(페이스 낮춤)에서 옴.
최근 3일 훈련 볼륨
| 그룹 | 3일 누적 운동 |
|---|---|
| 카페인 ○ | 135 min |
| 카페인 × | 99 min |
카페인 그룹이 36% 더 많은 최근 볼륨. 훈련 주간의 중심 세션이 "커피 마시고 자전거 타는 날".
Selection Bias 검증 — Baseline 동일
| 지표 | 카페인 ○ (n=47) | 카페인 × (n=40) |
|---|---|---|
| HRV | 49.9 ms | 49.9 ms (0 차이) |
| 전날 수면 | 7.2 h | 6.8 h |
컨디션 baseline은 완전히 동일. "컨디션 좋은 날만 커피 + 운동"이라는 self-selection은 없음. 오히려 카페인 없는 저녁 운동은 전날 수면이 0.4시간 짧았고, 그런데도 속도는 빨랐음.
6. Duration-Matched 비교 — 결정타
카페인 그룹과 non-caffeine 그룹에서 duration이 ±5분 이내인 쌍만 매칭 (Nearest neighbor, without replacement).
매칭 결과: 39쌍, 평균 duration 차이 1.3분
| 지표 | 카페인 ○ | 카페인 × | Δ | Paired t | p |
|---|---|---|---|---|---|
| Speed (km/h) | 30.2 | 30.8 | -0.65 | -0.59 | 0.560 |
| Kcal/min | 10.24 | 10.40 | -0.17 | -0.31 | 0.761 |
| Avg HR (bpm) | 139.3 | 139.6 | -0.3 | -0.07 | 0.945 |
| Speed/HR | 0.2170 | 0.2204 | -0.0035 | -0.74 | 0.464 |
같은 duration을 매칭하면 모든 지표의 차이가 사실상 0 (모든 p > 0.46). 이것이 "카페인 효과 없음"의 결정적 증거입니다.
Duration bin별 패턴 — 흥미로운 반전
| 구간 | 카페인 ○ | 카페인 × | Δ |
|---|---|---|---|
| <30min | 30.3 (n=8) | 26.2 (n=7) | +4.1 ← 역전 |
| 30-45min | 29.4 (n=22) | 31.8 (n=21) | -2.4 |
| 45-60min | 28.6 (n=9) | 31.8 (n=7) | -3.1 |
| 60+min | 28.5 (n=8) | 32.9 (n=5) | -4.4 |
짧은 세션 (<30min)에서는 카페인 있을 때가 4.1 km/h 빠름. 이건 세션 목적이 완전히 다르기 때문:
- 짧음 + 카페인: 아침의 짧고 강한 tempo/HIIT — "오늘은 짧게 빡세게"
- 짧음 + 노카페인: 저녁의 warm-up/cool-down — 26.2 km/h는 매우 낮음
- 길음 + 카페인: 긴 endurance (의도적으로 페이스 낮춰 길게)
- 길음 + 노카페인: 긴 tempo/endurance (중간 페이스 유지)
즉 duration 자체가 세션 목적의 proxy이고, 목적이 페이스를 결정합니다. 매칭은 duration은 맞추지만 목적은 완전히 맞출 수 없어서 bin별 패턴에 남는 것이지, 순수 카페인 효과는 아닙니다.
7. 강도 기반 재분석
Speed는 Zwift 실내에서 파워의 proxy
| 상관 | r |
|---|---|
| Speed ↔ Kcal/min | +0.805 (매우 강함) |
| Speed ↔ Avg HR | +0.765 (매우 강함) |
| Speed ↔ Kcal/km | +0.045 (무관) |
Zwift 실내 트레이너에서는 바람/지형 변수가 없어 speed ≈ power. Kcal/min과 r=0.80으로 거의 동의어. 따라서 speed 기반 분석이 power 기반 분석과 본질적으로 같은 답을 줍니다.
Kcal/min 시간대 × 카페인 매트릭스
| 시간대 | 카페인 ○ | 카페인 × | Δ |
|---|---|---|---|
| 아침 | 10.47 (n=17) | 12.78 (n=1) | — |
| 오전 | 10.08 (n=14) | 9.65 (n=5) | +0.43 |
| 오후 | 9.09 (n=13) | 10.49 (n=8) | -1.41 |
| 저녁 | 9.26 (n=3) | 10.44 (n=26) | -1.18 |
Speed와 똑같은 패턴. 파워 관점에서도 카페인 있을 때가 살짝 낮음 → 세션 선택 가설 확증.
Kcal/min 다중회귀
kcal/min ~ Residual caffeine + Hour + Hour² + Duration + Prev sleep + HRV + Recent vol
| 변수 | β (std) | p |
|---|---|---|
| HRV | -0.220 | 0.043 ** |
| Prev sleep | -0.206 | 0.058 * |
| Hour of day | -1.377 | 0.199 |
| Hour² | +1.372 | 0.207 |
| Recent vol | +0.090 | 0.414 |
| Residual caffeine | -0.056 | 0.685 |
| Duration | -0.006 | 0.956 |
R² = 0.128.
카페인 p=0.685 — 완전 무관. HRV와 전날 수면이 음의 방향으로 유의: 잘 쉰 날일수록 페이스가 낮음.
(Kcal/min)/HR — 심박당 파워 효율
| 그룹 | (Kcal/min) / HR |
|---|---|
| 카페인 ○ | 0.0709 |
| 카페인 × | 0.0735 |
차이 -0.00259 (사실상 0). 같은 심박수에서 카페인이 있든 없든 내는 파워가 동일. 에르고제닉 효과의 가장 엄밀한 기각.
8. HRV의 역방향 효과 — 진짜 숨은 스토리
여러 회귀에서 일관되게 나온 패턴:
| DV | HRV β | p |
|---|---|---|
| Avg speed | -0.312 | 0.004 ** |
| Kcal/min | -0.220 | 0.043 ** |
"HRV 높을수록 퍼포먼스 낮음" — 역설적으로 보이지만, 이건 훈련 intelligence의 signature입니다:
해석
- HRV 높은 날 = 자율신경이 잘 쉼 = 몸이 회복된 상태
- → 사용자가 recovery ride를 선택 (천천히 길게)
- → 낮은 평균 속도, 낮은 kcal/min
- HRV 낮은 날 = 피로/스트레스 누적 상태
- → 사용자가 의외로 빠르게 탐 (tempo/interval)
- → 높은 평균 속도
이건 "intelligent training selection" 패턴입니다. HRV는 퍼포먼스의 원인이 아니라 세션 목적 선택의 매개변수. 당신이 (아마 무의식적으로) HRV/몸 상태를 보고 훈련 강도를 조절하고 있다는 증거.
앞선 리포트와의 관계
caffeine-multidim.md 리포트에서 아침 카페인과 일상 HRV 저하 사이에 일관된 cross-sectional 연관을 확인했습니다 (r=-0.215, p=0.023; dose-response 선명; 교란 통제 후 유지; 역인과 기각). 단 caffeine-multidim v3.1 정정에 따라 엄밀한 lagged-only Granger로는 p=0.125(n.s.)로, 이전에 보고했던 "Granger p=0.003"은 구현 버그(unrestricted 모델에 동시대 항 포함)에서 나온 값이었음. 자세한 내용은 caffeine-multidim §5-1 참조.
여기서 다루는 것은 workout 중/직후의 강도-HRV 관계로 독립적 검정입니다. 두 결과는 공존 가능:
- 아침 카페인 → 자율신경 부담 → 일상 HRV 약한 저하 (caffeine-multidim §5, effective signal)
- 사이클 훈련 선택 → HRV 패턴과의 상관 → 별개 현상 (본 리포트 §8)
9. v2: HR-based Intensity Analysis
v1 speed 기반의 한계(Zwift 실내에서도 가상 경사도로 인해 speed ≠ power)를 보완하기 위해 52,826건 raw HR time-series에서 power-analogous intensity 지표를 유도하여 재분석.
9-1. 개인 HR 기준 파라미터
| 파라미터 | 값 | 출처 |
|---|---|---|
| MHR (Max HR) | 186 bpm | 52,826 HR 샘플 중 반복 관측된 peak |
| RHR (daily avg) | 49.6 bpm | 일별 RHR 평균 |
| HRR range | 137 bpm | MHR - RHR |
관측된 max HR을 사용하는 이유: 220 - age 공식은 큰 오차(±12 bpm)가 있으나, 지난 111일간 반복적으로 도달한 peak값은 실제 개인 MHR의 더 정확한 추정치.
9-2. 새 Intensity 지표
| 지표 | 공식 | 해석 |
|---|---|---|
| Normalized HR (NHR) | (mean(HR_rolling30s^4))^(1/4) | Power의 NP 개념. 변동이 큰 세션은 NHR > avg HR |
| TRIMP (Banister) | duration × HRr × 0.64 × e^(1.92 × HRr) | 총 training stress. HRr = (avg HR - RHR) / (MHR - RHR) |
| HR drift | (last 25% avg - first 25% avg) / first25% × 100 | Cardiovascular drift. fitness/hydration 지표 |
| HR CV | SD(HR) / mean(HR) | Intra-session 변동. interval 판정 |
| **HRR **% | (avg HR - RHR) / (MHR - RHR) | 개인화된 intensity |
| Zone time | Z1-Z5 분포 | Karvonen-ish (50-60% / 60-70% / 70-80% / 80-90% / 90%+) |
9-3. Intensity 기술통계 (87개 세션)
| 지표 | 평균 | SD | 범위 |
|---|---|---|---|
| Avg HR | 138.5 bpm | ±17.3 | 91-165 |
| Max HR | 170.4 bpm | ±14.7 | 108-186 |
| NHR | 142.4 bpm | ±17.3 | 92-167 |
| HR CV | 14.8% | ±3.3 | 7-29% |
| HR drift | +24.7% | ±17.3 | -10 ~ +109% |
| HRR % | 65.2% | ±12.6 | 30-84% |
| TRIMP | 66.9 | ±34.0 | 8-160 |
관찰: 평균 HR drift +24.7%는 매우 높은 수준. 정상 fit cyclist의 drift는 steady-state endurance에서 <5%. 이는 사용자 세션 대부분이 non-steady-state (interval 또는 progressive)임을 시사.
9-4. 세션 타입 자동 분류 (rule-based)
분류 규칙:
- Recovery: HRR < 55% AND Z4+Z5 < 10%
- Interval: Z4+Z5 ≥ 15% AND Z1+Z2 ≥ 20% AND HR CV ≥ 15% (bimodal distribution)
- 나머지: dominant zone으로 분류 (Z1→recovery, Z2→endurance, Z3→tempo, Z4+Z5→threshold)
- Mixed (top zone < 35%): HRR 기반 (<65% endurance, <75% tempo, 이상 threshold)
분류 결과:
| 타입 | N | 평균 HR | NHR | HR CV | Drift | HRR% | Duration | Speed | kcal/min |
|---|---|---|---|---|---|---|---|---|---|
| Recovery | 16 | 98 bpm | 99 | 10.5% | -7.4% | 35% | 35 min | 20.1 km/h | 4.6 |
| Endurance | 3 | 124 | 126 | 10.9% | +6.8% | 56% | 39 | 27.3 | 8.4 |
| Tempo | 11 | 139 | 141 | 10.9% | +17.7% | 65% | 61 | 32.3 | 10.2 |
| Threshold | 45 | 155 | 157 | 10.2% | +14.5% | 78% | 38 | 35.3 | 12.7 |
| Interval | 12 | 138 | 142 | 15.7% | +27.3% | 65% | 42 | 29.7 | 10.1 |
관찰: Threshold 세션이 지배적 (45/87 = 52%). 사용자는 대부분 Z4 (80-90% MHR) 영역에서 탐. 이건 "짧고 강한 훈련" 선호 패턴.
9-5. 세션 타입 × 카페인 매트릭스
| 타입 | 카페인 ○ | 카페인 × | ○ 비율 |
|---|---|---|---|
| Recovery | 9 | 7 | 56% |
| Endurance | 2 | 1 | 67% |
| Tempo | 5 | 6 | 45% |
| Threshold | 23 | 22 | 51% |
| Interval | 8 | 4 | 67% |
모든 타입에서 카페인 분포가 거의 50/50. 사용자가 타입별로 카페인을 차별하지 않음 — 즉 "카페인이 있어야 할 수 있는 세션"은 없음.
9-6. Intensity 지표 × 카페인 상관 (전체 N=87)
| Intensity | Pre-caf 3h (mg) | Residual caf |
|---|---|---|
| Avg HR | r = -0.011 | r = +0.000 |
| NHR | r = -0.006 | r = +0.007 |
| HR CV | r = +0.057 | r = +0.066 |
| HR drift | r = +0.030 | r = +0.089 |
| HRR % | r = -0.011 | r = +0.004 |
| TRIMP | r = +0.021 | r = +0.128 |
| Kcal/min | r = -0.029 | r = -0.051 |
모든 상관이 |r| < 0.13. 가장 큰 TRIMP × residual caffeine도 r=0.128 (p>0.2). v1의 speed 기반 상관(r≈-0.06 수준)과 정확히 같은 그림.
9-7. Session-Type + Duration Matched 29쌍 — 최종 확증
같은 세션 타입 + duration ±10분 이내로 매칭한 29쌍 paired t-test:
| 지표 | 카페인 ○ | 카페인 × | Δ | Paired t | p |
|---|---|---|---|---|---|
| Avg speed | 31.39 km/h | 31.34 | +0.059 | +0.06 | 0.951 |
| Kcal/min | 10.76 | 10.70 | +0.066 | +0.22 | 0.827 |
| Avg HR | 142.15 bpm | 141.29 | +0.87 | +0.43 | 0.669 |
| NHR | 145.71 bpm | 145.21 | +0.50 | +0.25 | 0.806 |
| HR CV | 14.20% | 14.80% | -0.60% | -0.70 | 0.491 |
| HR drift | 25.32% | 24.54% | +0.78% | +0.17 | 0.867 |
| **HRR **% | 67.94% | 67.29% | +0.65% | +0.43 | 0.670 |
| TRIMP | 67.96 | 68.18 | -0.21 | -0.06 | 0.952 |
| Duration | 39.12 min | 39.50 | -0.38 min | -0.71 | 0.481 |
모든 8개 intensity 지표에서 Δ가 측정 노이즈 수준(<1% of mean)이고 p > 0.49. 세션 타입과 duration을 맞춘 상태에서 카페인의 어떤 생리학적 효과도 감지되지 않음.
9-8. v2 TRIMP 다중회귀 (결정적)
TRIMP ~ Residual caf + Hour + Hour² + Duration + Prev sleep + HRV + Session type dummies
R² = 0.880, adj R² = 0.864 (v1 speed 모델 R²=0.174 대비 5배 향상!)
| 변수 | β (std) | p |
|---|---|---|
| Duration | +0.689 | <0.001 ** |
| Threshold session | +0.491 | <0.001 ** |
| Hour² | +0.228 | 0.583 |
| Recovery session | -0.204 | 0.037 ** |
| Hour of day | -0.196 | 0.632 |
| Tempo session | +0.070 | 0.395 |
| Prev sleep | +0.069 | 0.106 |
| HRV | -0.048 | 0.265 |
| Residual caffeine | +0.021 | 0.693 |
| Interval session | -0.002 | 0.985 |
Duration + session type이 training stress의 88%를 설명. 카페인 β=+0.021로 사실상 zero. HRV도 session type을 통제한 후에는 유의하지 않음 — v1의 HRV β=-0.22는 session type과의 collinearity 때문에 over-attributed됐던 것.
9-9. v2 NHR 다중회귀
R² = 0.874
| 변수 | β | p |
|---|---|---|
| Hour² | +0.642 | 0.133 |
| Hour of day | -0.619 | 0.142 |
| Threshold session | +0.593 | <0.001 ** |
| Recovery session | -0.493 | <0.001 ** |
| Tempo session | +0.088 | 0.298 |
| Prev sleep | +0.061 | 0.164 |
| HRV | -0.054 | 0.223 |
| Residual caffeine | +0.001 | 0.984 |
카페인 β = +0.001, p = 0.984 — NHR(normalized HR)은 사실상 Power의 NP와 같은 개념인데, 여기서 카페인 효과가 정확히 0. 이것이 v2의 가장 강한 negative 결과.
9-10. HRV → 세션 타입 선택 메커니즘 확증
| 타입 | N | 평균 HRV | vs 전체 평균 |
|---|---|---|---|
| Recovery | 16 | 53.5 ms | +3.6 ↑ |
| Endurance | 3 | 50.9 | +1.1 |
| Tempo | 11 | 50.1 | +0.2 |
| Threshold | 45 | 48.7 | -1.2 |
| Interval | 12 | 49.0 | -0.9 |
HRV 높은 날 → recovery 세션 (+3.6ms), HRV 낮은 날 → threshold 세션 (-1.2ms). 이 메커니즘이 v1에서 관찰한 "HRV 높을수록 퍼포먼스 낮음" 역설의 진짜 원인:
- HRV 높다 → 잘 쉰 상태 → recovery 선택 → TRIMP 낮음 → "퍼포먼스 낮음"처럼 보임
- HRV 낮다 → 피로 누적 → 의외로 threshold 선택 → TRIMP 높음
이건 일반적 훈련 권고(HRV 낮으면 쉬어라)와 반대 방향입니다. 사용자 본능이 일반 권고와 다르게 작동한다는 점에 주목.
9-11. 세션 타입의 시간대 분포 — Bimodal의 진짜 원인
| 시간대 | recovery | endurance | tempo | threshold | interval |
|---|---|---|---|---|---|
| 아침 (06-11) | 3 | 0 | 1 | 11 | 3 |
| 오전 (11-13) | 4 | 0 | 3 | 10 | 2 |
| 오후 (13-17) | 2 | 2 | 3 | 8 | 6 |
| 저녁 (17-22) | 7 | 1 | 4 | 16 | 1 |
아침 threshold 11건 + 저녁 threshold 16건 = 27건 (45 threshold 중 60%). 그리고 저녁에 recovery 7건(recovery 16 중 44%)이 함께 있어서 저녁의 평균이 bimodal을 만듦.
v1에서 관찰한 "bimodal peak 08-10시, 18-20시"의 정확한 메커니즘: threshold 세션을 아침과 저녁에 집중 배치. 점심-오후는 interval(6)과 tempo/endurance 섞여서 평균이 낮아짐.
10. 종합 해석 (v2)
당신의 자전거 퍼포먼스를 결정하는 것 (v2 영향력 순)
- 세션 타입 (threshold vs recovery vs interval vs tempo) — TRIMP의 49% 설명 (β=+0.491 threshold, -0.204 recovery)
- Duration — TRIMP β=+0.689 (가장 강한 단일 변수)
- HRV 기반 자체 조절 — HRV 높은 날 recovery, 낮은 날 threshold (dominant zone 분포)
- 시간대 — Bimodal (아침 08-10, 저녁 18-20 peak). 점심-오후 trough. Threshold 세션이 아침/저녁에 집중 배치됨으로써 생성되는 패턴.
- 카페인 — 영향 없음 (확정). NHR β=+0.001, TRIMP β=+0.021, 모든 29쌍 matched 지표 p > 0.49
"아침엔 커피 + 자전거 빠르게, 저녁엔 맨 몸으로 자전거 빠르게"의 진실 (v2)
메커니즘 확정:
- 당신은 threshold 세션을 아침과 저녁에 집중 배치합니다 (45 threshold 중 27건 = 60%)
- 그 중 아침 threshold에는 우연히 커피를 마신 상태가 대부분 (아침 커피는 일상)
- 저녁 threshold에는 커피를 마시지 않은 상태가 대부분 (저녁 커피 회피)
- 두 시간대 모두 threshold 세션이기 때문에 NHR/TRIMP/HR drift가 동일하게 높음
- 점심-오후에는 tempo/interval/endurance가 섞여서 평균 intensity가 낮아짐
카페인은 무관: 세션 타입이 intensity를 결정하고, 카페인은 그 선택과 무관.
실질적 함의 (v2)
- 에르고제닉 목적 카페인 완전 불필요 — NHR 기준 β = +0.001 (정확히 zero). TRIMP 기준 β = +0.021 (p=0.693). Speed, kcal/min, HR drift, HR CV, HRR% 전부 같은 결론.
- 운동 중 카페인의 HR 효과도 없음 — 앞선 caffeine-multidim에서 발견한 "아침 카페인 → 일상 HRV 저하" 효과는 운동 중엔 측정 불가. 운동 자체의 교감신경 활성이 카페인의 추가 효과를 묻어버림.
- HRV 기반 훈련 선택을 계속 유지 — 사용자는 무의식적으로 HRV 높은 날엔 recovery, 낮은 날엔 threshold를 선택. 이게 결과적으로 bimodal performance peak를 만들고 있음. 단 "HRV 낮은 날 강한 운동"은 일반적 권고와 반대 방향이므로 오버트레이닝 리스크 모니터링 권장.
- 점심-오후 (12-17시)는 여전히 피하는 게 유리 — 아침/저녁에 집중된 threshold 세션이 이 시간대에는 배치되지 않음. 사용자의 본능이 이미 최적화되어 있음.
- HR drift가 높은 이유 (+24.7%) — 대부분 세션이 interval 또는 progressive여서. Steady-state aerobic base 세션을 늘리면 CV fitness 개선 가능.
11. 분석 한계 (v2)
- N = 87: 회귀 분석에는 빠듯. 교란 변수를 4-5개로 제한. v2에서 R²=0.88으로 개선됐지만 여전히 power-level confidence는 낮음.
- Zwift 실내만: 실외 사이클링 데이터 0건. 실외는 바람/지형/안전 변수 추가로 결과 다를 수 있음.
- Power 데이터 부재: Zwift → Apple Health 파워 sync가 공식적으로 막혀 있음. HealthFit 수동 import 또는 RunGap+TrainingPeaks 유료 파이프라인 필요.
- Session type은 post-hoc rule-based 분류: "오늘 어떤 세션을 하려고 했나"의 ground truth는 없음. HR 시그니처로 역추론.
- Rule-based 분류기의 민감도: 분류 임계값(HR CV 15%, Z4+Z5 15%, HRR 55%)이 arbitrary. k-means unsupervised 분류로 검증 필요.
- MHR 추정의 정확도: 관측 peak 186 bpm 사용. 실제 MHR이 더 높을 수 있으나 (실제 all-out 테스트가 없었다면) 관측 peak이 가장 안전한 하한선 추정치.
- Caffeine 노출 ≤ 3h 이분화: pharmacokinetic residual로도 병렬 검증했으나 같은 결론.
12. 다음 가능한 질문
- Zwift 내 세션 타입 태그 활용: Zwift API에서 workout name/type을 가져오면 "endurance / tempo / HIIT" 직접 구분 가능. 현재 분석은 duration proxy로만 추론.
- Power data (Watts): Zwift는 실제 파워를 기록함. HealthKit에는 기록 안 됨 — Zwift API 직접 연동 필요.
- 장기 추세: 4개월 데이터라 fitness 진전 효과 무시. VO2 Max, FTP 같은 장기 지표 추적 시 다른 그림 가능.
- 실험적 검증: 일주일간 같은 시간대에 카페인 있는 세션 vs 없는 세션 교차 실행. Power/HR matched. 실제 RCT에 가장 가까운 검증.
부록: 분석 방법론
| 단계 | 방법 | 목적 |
|---|---|---|
| 1 | 데이터 prep, HR window matching | workout별 avg/max HR 계산 |
| 2 | Descriptive, time-of-day × caffeine matrix | 사용자 관찰 검증, 카페인 분포 확인 |
| 3 | Circadian baseline (polynomial + bin) | 시간대 단독 효과 추출 |
| 4 | Residual analysis | 시간대 통제 후 카페인 효과 |
| 5 | Multiple regression (avg speed, kcal/min, avg HR) | 교란 변수 통제, 상대 영향력 |
| 6 | Duration-matched pairing (±5min) | 세션 종류 통제 — 카페인 순수 효과 |
| 7 | Duration-binned analysis | 세션 선택 가설 검증 |
| 8 | Intensity-based re-analysis (kcal/min) | Speed → Power 대체 검증 |
| 9 | (Kcal/min)/HR — HR-normalized intensity | 심박당 파워 효율 |
| v2-1 | HR intensity metrics (NHR, TRIMP, HR zones, drift, CV) | Power-analogous 지표 유도 from 52,826 raw HR samples |
| v2-2 | Rule-based workout classification (recovery/endurance/tempo/threshold/interval) | Post-hoc session type identification |
| v2-3 | Session-type + duration matched pairing (29쌍) | Session selection bias 제거한 정밀 비교 |
| v2-4 | Multiple regression with session type dummies | R²=0.88 모델에서 카페인 independent effect 측정 |
도구: Bun + TypeScript (외부 통계 라이브러리 없이 자체 구현: OLS, paired t-test, Pearson correlation, partial correlation, t-distribution p-value).
부록 B: Power 데이터를 확보하는 방법 (미래 과제)
Zwift는 현재 파워(W)를 Apple Health에 쓰지 않음 (feature request 수년째 pending). Strava도 2022년 3월부터 third-party power sync 중단. 파워 기반 분석을 하려면 아래 경로 중 하나:
| 경로 | 방법 | 장점 | 단점 |
|---|---|---|---|
| A. HealthFit 수동 import | Zwift 웹 → .fit 다운로드 → HealthFit 앱으로 import | cyclingPower HKQuantityType 기록, 무료 | 세션마다 수동 작업, 소급 적용 부담 |
| B. RunGap + TrainingPeaks | Zwift → TP 자동 → RunGap Swag Bag(유료) → Apple Health | 자동화, 모든 metric | TP 계정 + RunGap 구독 필요 |
| C. Zwift API 직접 | Non-official zwift-client 라이브러리 | 최대 유연성 | 복잡, 유지보수 부담 |
추천: A (HealthFit) 부분 import — 과거 주요 세션 15-20건만 수동 import 해두고, Health Data Bridge CLI에 cyclingPower 타입만 추가하면 "파워 있는 subset"에서 재분석 가능. iOS 코드 수정은 HealthBridgeQuantityIdentifier enum에 case 추가하는 작업 (약 10분).
현재 v2 결론이 HR 기반으로 매우 강력하게(β = +0.001 ~ +0.021) 뒷받침되므로, power 기반 재검증이 "결론 뒤집기"보다는 "확증"에 더 가까울 것으로 예상. 단 NHR이 실제 Power NP와 얼마나 잘 일치하는지는 confirm 필요.
<!-- charts:section:start -->📊 데이터 시각화
아래 차트들은
research/taeho-health/sleep-caffeine/charts.mjs가 raw Health Data Bridge 데이터를 직접 읽어 SVG로 생성한 것입니다. 본문 텍스트와 다소 다른 윈도우 / aggregation 을 사용할 수 있고, 본문의 정교한 통계 (Granger / PK / mediation 등) 결과를 시각적으로 보완하는 보조 자료입니다. 자세한 재생산 절차는data/README.md참고.
사이클링 평균 속도 × 시간대 (bimodal 패턴)
사이클링 세션의 시간대별 평균 속도 (bimodal 패턴). cycling-performance.md §6의 핵심 발견인 "08-10시와 18-20시에 두 개의 피크"를 시각화. 본문은 이 bimodal이 "Threshold/Recovery 세션이 이 시간대에 집중되어서 생긴 artifact"임을 multivariate로 입증함.
사이클링 kcal/min × 카페인 섭취 여부
사이클링 kcal/min × 카페인 섭취 여부 (그날 75 mg 기준). 본문 §10의 "카페인은 power proxy(kcal/min)에 영향 없음" 결론을 단순 비교 차트로 표시. 두 bar 모두 SD 범위 내라 차이는 noise 수준 — Δ p>0.46 (matched pair) 결과와 부합.
사이클링 세션 duration 분포
사이클링 세션 duration 분포. 30-45 분 구간이 modal — 본문 §4의 "평균 42.7 ± 16.8 min" 분포 형태를 보여줌. duration이 카페인 효과의 confounder인 이유 (long sessions tend to be both more caffeinated AND lower-intensity by definition).
Daily Steps × HRV 산점도
일일 걸음수 × HRV 산점도. cycling/activity 컨텍스트에서 "활동량이 많은 날일수록 다음날 회복 지표가 어떻게 움직이는가"를 1차원으로 본 보조 차트. 약한 양의 상관 — 운동 적당히 한 날이 회복도 좋다는 일반 패턴.
<!-- charts:section:end -->